diff --git a/CHANGES.txt b/CHANGES.txt index f9446b203583..071394593996 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +2021-05-07 version 3.17.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) + PHP + * Fixed JSON parser to allow multiple values from the same oneof as long as + all but one are null. + + Ruby + * Fixed JSON parser to allow multiple values from the same oneof as long as + all but one are null. + 2021-05-07 version 3.17.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) Protocol Compiler diff --git a/Makefile.am b/Makefile.am index cab595ded3f6..8cf5473e2f1a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -801,6 +801,7 @@ objectivec_EXTRA_DIST= \ php_EXTRA_DIST= \ composer.json \ php/README.md \ + php/REFCOUNTING.md \ php/composer.json \ php/ext/google/protobuf/arena.c \ php/ext/google/protobuf/arena.h \ diff --git a/conformance/failure_list_php_c.txt b/conformance/failure_list_php_c.txt index 198202911241..63c7e8a024cc 100644 --- a/conformance/failure_list_php_c.txt +++ b/conformance/failure_list_php_c.txt @@ -1,4 +1,2 @@ Recommended.Proto2.JsonInput.FieldNameExtension.Validator Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator -Required.Proto3.JsonInput.OneofFieldNullSecond.JsonOutput -Required.Proto3.JsonInput.OneofFieldNullSecond.ProtobufOutput diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt index ea5de3660963..4938202ad70b 100644 --- a/conformance/failure_list_ruby.txt +++ b/conformance/failure_list_ruby.txt @@ -56,5 +56,3 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.UnpackedOu Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.UnpackedOutput.ProtobufOutput -Required.Proto3.JsonInput.OneofFieldNullSecond.JsonOutput -Required.Proto3.JsonInput.OneofFieldNullSecond.ProtobufOutput diff --git a/kokoro/linux/php80/build.sh b/kokoro/linux/php80/build.sh index f17aec104f9b..ba269e52dbc6 100755 --- a/kokoro/linux/php80/build.sh +++ b/kokoro/linux/php80/build.sh @@ -1,18 +1,17 @@ #!/bin/bash # -# This is the top-level script we give to Kokoro as the entry point for -# running the "pull request" project: -# -# This script selects a specific Dockerfile (for building a Docker image) and -# a script to run inside that image. Then we delegate to the general -# build_and_run_docker.sh script. +# This is the entry point for kicking off a Kokoro job. This path is referenced +# from the .cfg files in this directory. + +set -ex + +cd $(dirname $0) -# Change to repo root -cd $(dirname $0)/../../.. +# Most of our tests use a debug build of PHP, but we do one build against an opt +# php just in case that surfaces anything unexpected. +../test_php.sh gcr.io/protobuf-build/php/linux:8.0.5-14a06550010c0649bf69b6c9b803c1ca609bbb6d -export DOCKERHUB_ORGANIZATION=protobuftesting -export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/php80 -export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh -export OUTPUT_DIR=testoutput -export TEST_SET="php8.0_all" -./kokoro/linux/build_and_run_docker.sh +../test_php.sh gcr.io/protobuf-build/php/linux:7.0.33-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d +../test_php.sh gcr.io/protobuf-build/php/linux:7.3.28-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d +../test_php.sh gcr.io/protobuf-build/php/linux:7.4.18-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d +../test_php.sh gcr.io/protobuf-build/php/linux:8.0.5-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d diff --git a/kokoro/linux/php80/continuous.cfg b/kokoro/linux/php80/continuous.cfg index 8426318bbee4..6d67a8c31ad7 100644 --- a/kokoro/linux/php80/continuous.cfg +++ b/kokoro/linux/php80/continuous.cfg @@ -2,10 +2,4 @@ # Location of the build script in repository build_file: "protobuf/kokoro/linux/php80/build.sh" -timeout_mins: 120 - -action { - define_artifacts { - regex: "**/sponge_log.xml" - } -} +timeout_mins: 20 diff --git a/kokoro/linux/php80/presubmit.cfg b/kokoro/linux/php80/presubmit.cfg index 8426318bbee4..6d67a8c31ad7 100644 --- a/kokoro/linux/php80/presubmit.cfg +++ b/kokoro/linux/php80/presubmit.cfg @@ -2,10 +2,4 @@ # Location of the build script in repository build_file: "protobuf/kokoro/linux/php80/build.sh" -timeout_mins: 120 - -action { - define_artifacts { - regex: "**/sponge_log.xml" - } -} +timeout_mins: 20 diff --git a/kokoro/linux/php_all/build.sh b/kokoro/linux/php_all/build.sh index 23468a70107e..1ee79adf817a 100755 --- a/kokoro/linux/php_all/build.sh +++ b/kokoro/linux/php_all/build.sh @@ -1,18 +1,20 @@ #!/bin/bash # -# This is the top-level script we give to Kokoro as the entry point for -# running the "pull request" project: -# -# This script selects a specific Dockerfile (for building a Docker image) and -# a script to run inside that image. Then we delegate to the general -# build_and_run_docker.sh script. +# This is the entry point for kicking off a Kokoro job. This path is referenced +# from the .cfg files in this directory. + +set -ex -# Change to repo root +# Change to repo base. cd $(dirname $0)/../../.. -export DOCKERHUB_ORGANIZATION=protobuftesting -export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/php -export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh -export OUTPUT_DIR=testoutput -export TEST_SET="php_all" -./kokoro/linux/build_and_run_docker.sh +docker run $(test -t 0 && echo "-it") -v$PWD:/workspace gcr.io/protobuf-build/php/linux:8.0.5-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d "composer test_valgrind" + +docker run $(test -t 0 && echo "-it") -v$PWD:/workspace gcr.io/protobuf-build/php/linux:7.0.33-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d "composer test && composer test_c" +docker run $(test -t 0 && echo "-it") -v$PWD:/workspace gcr.io/protobuf-build/php/linux:7.3.28-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d "composer test && composer test_c" +docker run $(test -t 0 && echo "-it") -v$PWD:/workspace gcr.io/protobuf-build/php/linux:7.4.18-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d "composer test && composer test_c" +docker run $(test -t 0 && echo "-it") -v$PWD:/workspace gcr.io/protobuf-build/php/linux:8.0.5-dbg-14a06550010c0649bf69b6c9b803c1ca609bbb6d "composer test && composer test_c" + +# Most of our tests use a debug build of PHP, but we do one build against an opt +# php just in case that surfaces anything unexpected. +docker run $(test -t 0 && echo "-it") -v$PWD:/workspace gcr.io/protobuf-build/php/linux:8.0.5-14a06550010c0649bf69b6c9b803c1ca609bbb6d "composer test && composer test_c" diff --git a/php/REFCOUNTING.md b/php/REFCOUNTING.md new file mode 100644 index 000000000000..26ca7170df7a --- /dev/null +++ b/php/REFCOUNTING.md @@ -0,0 +1,112 @@ + +# Refcounting Tips + +One of the trickiest parts of the C extension for PHP is getting the refcounting +right. These are some notes about the basics of what you should know, +especially if you're not super familiar with PHP's C API. + +These notes cover the same general material as [the Memory Management chapter of +the PHP internal's +book](https://www.phpinternalsbook.com/php7/zvals/memory_management.html), but +calls out some points that were not immediately clear to me. + +## Zvals + +In the PHP C API, the `zval` type is roughly analogous to a variable in PHP, eg: + +```php + // Think of $a as a "zval". + $a = []; +``` + +The equivalent PHP C code would be: + +```c + zval a; + ZVAL_NEW_ARR(&a); // Allocates and assigns a new array. +``` + +PHP is reference counted, so each variable -- and thus each zval -- will have a +reference on whatever it points to (unless its holding a data type that isn't +refcounted at all, like numbers). Since the zval owns a reference, it must be +explicitly destroyed in order to release this reference. + +```c + zval a; + ZVAL_NEW_ARR(&a); + + // The destructor for a zval, this must be called or the ref will be leaked. + zval_ptr_dtor(&a); +``` + +Whenever you see a `zval`, you can assume it owns a ref (or is storing a +non-refcounted type). If you see a `zval*`, which is also quite common, then +this is *pointing to* something that owns a ref, but it does not own a ref +itself. + +The [`ZVAL_*` family of +macros](https://github.com/php/php-src/blob/4030a00e8b6453aff929362bf9b25c193f72c94a/Zend/zend_types.h#L883-L1109) +initializes a `zval` from a specific value type. A few examples: + +* `ZVAL_NULL(&zv)`: initializes the value to `null` +* `ZVAL_LONG(&zv, 5)`: initializes a `zend_long` (integer) value +* `ZVAL_ARR(&zv, arr)`: initializes a `zend_array*` value (refcounted) +* `ZVAL_OBJ(&zv, obj)`: initializes a `zend_object*` value (refcounted) + +Note that all of our custom objects (messages, repeated fields, descriptors, +etc) are `zend_object*`. + +The variants that initialize from a refcounted type do *not* increase the +refcount. This makes them suitable for initializing from a newly-created object: + +```c + zval zv; + ZVAL_OBJ(&zv, CreateObject()); +``` + +Once in a while, we want to initialize a `zval` while also increasing the +reference count. For this we can use `ZVAL_OBJ_COPY()`: + +```c +zend_object *some_global; + +void GetGlobal(zval *zv) { + // We want to create a new ref to an existing object. + ZVAL_OBJ_COPY(zv, some_global); +} +``` + +## Transferring references + +A `zval`'s ref must be released at some point. While `zval_ptr_dtor()` is the +simplest way of releasing a ref, it is not the most common (at least in our code +base). More often, we are returning the `zval` back to PHP from C. + +```c + zval zv; + InitializeOurZval(&zv); + // Returns the value of zv to the caller and donates our ref. + RETURN_COPY_VALUE(&zv); +``` + +The `RETURN_COPY_VALUE()` macro (standard in PHP 8.x, and polyfilled in earlier +versions) is the most common way we return a value back to PHP, because it +donates our `zval`'s refcount to the caller, and thus saves us from needing to +destroy our `zval` explicitly. This is ideal when we have a full `zval` to +return. + +Once in a while we have a `zval*` to return instead. For example when we parse +parameters to our function and ask for a `zval`, PHP will give us pointers to +the existing `zval` structures instead of creating new ones. + +```c + zval *val; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &val) == FAILURE) { + return; + } + // Returns a copy of this zval, adding a ref in the process. + RETURN_COPY(val); +``` + +When we use `RETURN_COPY`, the refcount is increased; this is perfect for +returning a `zval*` when we do not own a ref on it. diff --git a/php/composer.json b/php/composer.json index 5ea49edb2ec4..f712f0ebb9d6 100644 --- a/php/composer.json +++ b/php/composer.json @@ -24,6 +24,7 @@ }, "scripts": { "test_c": "./generate_test_protos.sh && ./tests/compile_extension.sh && php -dextension=ext/google/protobuf/modules/protobuf.so vendor/bin/phpunit --bootstrap tests/force_c_ext.php tests", + "test_valgrind": "./generate_test_protos.sh && ./tests/compile_extension.sh && ZEND_DONT_UNLOAD_MODULES=1 USE_ZEND_ALLOC=0 valgrind --leak-check=full --error-exitcode=1 php -dextension=ext/google/protobuf/modules/protobuf.so vendor/bin/phpunit --bootstrap tests/force_c_ext.php tests", "test": "./generate_test_protos.sh && vendor/bin/phpunit tests", "aggregate_metadata_test": "./generate_test_protos.sh --aggregate_metadata && vendor/bin/phpunit tests" } diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c index 3a2f734a71d8..765e90297c38 100644 --- a/php/ext/google/protobuf/array.c +++ b/php/ext/google/protobuf/array.c @@ -337,7 +337,7 @@ PHP_METHOD(RepeatedField, offsetGet) { msgval = upb_array_get(intern->array, index); Convert_UpbToPhp(msgval, &ret, intern->type, &intern->arena); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /** @@ -447,7 +447,7 @@ PHP_METHOD(RepeatedField, count) { PHP_METHOD(RepeatedField, getIterator) { zval ret; RepeatedFieldIter_make(&ret, getThis()); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 1) @@ -579,7 +579,7 @@ PHP_METHOD(RepeatedFieldIter, current) { msgval = upb_array_get(array, index); Convert_UpbToPhp(msgval, &ret, field->type, &field->arena); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /** diff --git a/php/ext/google/protobuf/convert.c b/php/ext/google/protobuf/convert.c index c518ccaa4da6..a1ed2c8a3fec 100644 --- a/php/ext/google/protobuf/convert.c +++ b/php/ext/google/protobuf/convert.c @@ -76,7 +76,7 @@ PHP_METHOD(Util, checkMapField) { &val_type, &klass) == FAILURE) { return; } - RETURN_ZVAL(val, 1, 0); + RETURN_COPY(val); } // The result of checkRepeatedField() is assigned, so we need to return the @@ -89,13 +89,18 @@ PHP_METHOD(Util, checkRepeatedField) { FAILURE) { return; } - RETURN_ZVAL(val, 1, 0); + RETURN_COPY(val); } ZEND_BEGIN_ARG_INFO_EX(arginfo_checkPrimitive, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_checkString, 0, 0, 1) + ZEND_ARG_INFO(0, value) + ZEND_ARG_INFO(0, check_utf8) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_checkMessage, 0, 0, 2) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, class) @@ -123,7 +128,7 @@ static zend_function_entry util_methods[] = { ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(Util, checkUint64, arginfo_checkPrimitive, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkEnum, arginfo_checkPrimitive, + PHP_ME(Util, checkEnum, arginfo_checkMessage, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(Util, checkFloat, arginfo_checkPrimitive, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) @@ -131,7 +136,7 @@ static zend_function_entry util_methods[] = { ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(Util, checkBool, arginfo_checkPrimitive, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkString, arginfo_checkPrimitive, + PHP_ME(Util, checkString, arginfo_checkString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(Util, checkBytes, arginfo_checkPrimitive, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) diff --git a/php/ext/google/protobuf/convert.h b/php/ext/google/protobuf/convert.h index 1bae233425ff..96cfc34fd009 100644 --- a/php/ext/google/protobuf/convert.h +++ b/php/ext/google/protobuf/convert.h @@ -60,9 +60,10 @@ bool Convert_PhpToUpbAutoWrap(zval *val, upb_msgval *upb_val, TypeInfo type, upb_arena *arena); // Converts |upb_val| to a PHP zval according to |type|. This may involve -// creating a PHP wrapper object. If type == UPB_TYPE_MESSAGE, then |desc| must -// be the Descriptor for this message type. Any newly created wrapper object +// creating a PHP wrapper object. Any newly created wrapper object // will reference |arena|. +// +// The caller owns a reference to the returned value. void Convert_UpbToPhp(upb_msgval upb_val, zval *php_val, TypeInfo type, zval *arena); diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c index 6e1a7e4e4335..9c8b6563319d 100644 --- a/php/ext/google/protobuf/def.c +++ b/php/ext/google/protobuf/def.c @@ -52,6 +52,9 @@ static zend_object *CreateHandler_ReturnNull(zend_class_entry *class_type) { return NULL; // Nobody should call this. } +ZEND_BEGIN_ARG_INFO_EX(arginfo_getByIndex, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() // ----------------------------------------------------------------------------- // EnumValueDescriptor @@ -115,12 +118,19 @@ static zend_function_entry EnumValueDescriptor_methods[] = { typedef struct { zend_object std; const upb_enumdef *enumdef; + void *cache_key; } EnumDescriptor; zend_class_entry *EnumDescriptor_class_entry; static zend_object_handlers EnumDescriptor_object_handlers; -void EnumDescriptor_FromClassEntry(zval *val, zend_class_entry *ce) { +static void EnumDescriptor_destructor(zend_object* obj) { + EnumDescriptor *intern = (EnumDescriptor*)obj; + ObjCache_Delete(intern->cache_key); +} + +// Caller owns a ref on the returned zval. +static void EnumDescriptor_FromClassEntry(zval *val, zend_class_entry *ce) { // To differentiate enums from classes, we pointer-tag the class entry. void* key = (void*)((uintptr_t)ce | 1); PBPHP_ASSERT(key != ce); @@ -140,16 +150,14 @@ void EnumDescriptor_FromClassEntry(zval *val, zend_class_entry *ce) { zend_object_std_init(&ret->std, EnumDescriptor_class_entry); ret->std.handlers = &EnumDescriptor_object_handlers; ret->enumdef = e; + ret->cache_key = key; ObjCache_Add(key, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - ZVAL_OBJ(val, &ret->std); } } -void EnumDescriptor_FromEnumDef(zval *val, const upb_enumdef *m) { +// Caller owns a ref on the returned zval. +static void EnumDescriptor_FromEnumDef(zval *val, const upb_enumdef *m) { if (!m) { ZVAL_NULL(val); } else { @@ -199,7 +207,7 @@ PHP_METHOD(EnumDescriptor, getValue) { EnumValueDescriptor_Make(&ret, upb_enum_iter_name(&iter), upb_enum_iter_number(&iter)); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /* @@ -220,13 +228,13 @@ PHP_METHOD(EnumDescriptor, getValueCount) { * the public and private descriptor. */ PHP_METHOD(EnumDescriptor, getPublicDescriptor) { - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry EnumDescriptor_methods[] = { PHP_ME(EnumDescriptor, getPublicDescriptor, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(EnumDescriptor, getValueCount, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(EnumDescriptor, getValue, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(EnumDescriptor, getValue, arginfo_getByIndex, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -242,6 +250,11 @@ typedef struct { zend_class_entry *OneofDescriptor_class_entry; static zend_object_handlers OneofDescriptor_object_handlers; +static void OneofDescriptor_destructor(zend_object* obj) { + OneofDescriptor *intern = (OneofDescriptor*)obj; + ObjCache_Delete(intern->oneofdef); +} + static void OneofDescriptor_FromOneofDef(zval *val, const upb_oneofdef *o) { if (o == NULL) { ZVAL_NULL(val); @@ -254,10 +267,6 @@ static void OneofDescriptor_FromOneofDef(zval *val, const upb_oneofdef *o) { ret->std.handlers = &OneofDescriptor_object_handlers; ret->oneofdef = o; ObjCache_Add(o, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - ZVAL_OBJ(val, &ret->std); } } @@ -302,7 +311,7 @@ PHP_METHOD(OneofDescriptor, getField) { const upb_fielddef *field = upb_oneof_iter_field(&iter); FieldDescriptor_FromFieldDef(&ret, field); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } /* @@ -317,7 +326,7 @@ PHP_METHOD(OneofDescriptor, getFieldCount) { static zend_function_entry OneofDescriptor_methods[] = { PHP_ME(OneofDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(OneofDescriptor, getField, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(OneofDescriptor, getField, arginfo_getByIndex, ZEND_ACC_PUBLIC) PHP_ME(OneofDescriptor, getFieldCount, arginfo_void, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -334,6 +343,12 @@ typedef struct { zend_class_entry *FieldDescriptor_class_entry; static zend_object_handlers FieldDescriptor_object_handlers; +static void FieldDescriptor_destructor(zend_object* obj) { + FieldDescriptor *intern = (FieldDescriptor*)obj; + ObjCache_Delete(intern->fielddef); +} + +// Caller owns a ref on the returned zval. static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f) { if (f == NULL) { ZVAL_NULL(val); @@ -346,10 +361,6 @@ static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f) { ret->std.handlers = &FieldDescriptor_object_handlers; ret->fielddef = f; ObjCache_Add(f, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - ZVAL_OBJ(val, &ret->std); } } @@ -455,7 +466,7 @@ PHP_METHOD(FieldDescriptor, getEnumType) { } EnumDescriptor_FromEnumDef(&ret, e); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } /* @@ -466,7 +477,6 @@ PHP_METHOD(FieldDescriptor, getEnumType) { PHP_METHOD(FieldDescriptor, getMessageType) { FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); Descriptor* desc = Descriptor_GetFromFieldDef(intern->fielddef); - zval ret; if (!desc) { zend_throw_exception_ex( @@ -475,8 +485,7 @@ PHP_METHOD(FieldDescriptor, getMessageType) { return; } - ZVAL_OBJ(&ret, &desc->std); - RETURN_ZVAL(&ret, 1, 0); + RETURN_OBJ_COPY(&desc->std); } static zend_function_entry FieldDescriptor_methods[] = { @@ -502,78 +511,80 @@ static void Descriptor_destructor(zend_object* obj) { // collected before the end of the request. } -// C Functions from def.h ////////////////////////////////////////////////////// +static zend_class_entry *Descriptor_GetGeneratedClass(const upb_msgdef *m) { + char *classname = + GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); + zend_string *str = zend_string_init(classname, strlen(classname), 0); + zend_class_entry *ce = zend_lookup_class(str); // May autoload the class. -// These are documented in the header file. + zend_string_release (str); -void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce) { - if (ce == NULL) { + if (!ce) { + zend_error(E_ERROR, "Couldn't load generated class %s", classname); + } + + free(classname); + return ce; +} + +void Descriptor_FromMessageDef(zval *val, const upb_msgdef *m) { + if (m == NULL) { ZVAL_NULL(val); return; } - if (!ObjCache_Get(ce, val)) { - const upb_msgdef *msgdef = NameMap_GetMessage(ce); - if (!msgdef) { - ZVAL_NULL(val); - return; + if (!ObjCache_Get(m, val)) { + zend_class_entry *ce = NULL; + if (!upb_msgdef_mapentry(m)) { // Map entries don't have a class. + ce = Descriptor_GetGeneratedClass(m); + if (!ce) { + ZVAL_NULL(val); + return; + } } Descriptor* ret = emalloc(sizeof(Descriptor)); zend_object_std_init(&ret->std, Descriptor_class_entry); ret->std.handlers = &Descriptor_object_handlers; ret->class_entry = ce; - ret->msgdef = msgdef; - ObjCache_Add(ce, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - + ret->msgdef = m; + ObjCache_Add(m, &ret->std); + Descriptors_Add(&ret->std); ZVAL_OBJ(val, &ret->std); } } -Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce) { - zval desc; - Descriptor_FromClassEntry(&desc, ce); - if (Z_TYPE_P(&desc) == IS_NULL) { - return NULL; +static void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce) { + if (ce) { + Descriptor_FromMessageDef(val, NameMap_GetMessage(ce)); } else { - return (Descriptor*)Z_OBJ_P(&desc); + ZVAL_NULL(val); } } -Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m) { - if (m) { - if (upb_msgdef_mapentry(m)) { - // A bit of a hack, since map entries don't have classes. - Descriptor* ret = emalloc(sizeof(Descriptor)); - zend_object_std_init(&ret->std, Descriptor_class_entry); - ret->std.handlers = &Descriptor_object_handlers; - ret->class_entry = NULL; - ret->msgdef = m; - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - - return ret; - } +static Descriptor* Descriptor_GetFromZval(zval *val) { + if (Z_TYPE_P(val) == IS_NULL) { + return NULL; + } else { + zend_object* ret = Z_OBJ_P(val); + zval_ptr_dtor(val); + return (Descriptor*)ret; + } +} - char *classname = - GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); - zend_string *str = zend_string_init(classname, strlen(classname), 0); - zend_class_entry *ce = zend_lookup_class(str); // May autoload the class. +// C Functions from def.h ////////////////////////////////////////////////////// - zend_string_release (str); +// These are documented in the header file. - if (!ce) { - zend_error(E_ERROR, "Couldn't load generated class %s", classname); - } +Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce) { + zval desc; + Descriptor_FromClassEntry(&desc, ce); + return Descriptor_GetFromZval(&desc); +} - free(classname); - return Descriptor_GetFromClassEntry(ce); - } else { - return NULL; - } +Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m) { + zval desc; + Descriptor_FromMessageDef(&desc, m); + return Descriptor_GetFromZval(&desc); } Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f) { @@ -588,7 +599,7 @@ Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f) { * the public and private descriptor. */ PHP_METHOD(Descriptor, getPublicDescriptor) { - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } /* @@ -623,15 +634,8 @@ PHP_METHOD(Descriptor, getField) { return; } - upb_msg_field_iter iter; - int i; - for(upb_msg_field_begin(&iter, intern->msgdef), i = 0; - !upb_msg_field_done(&iter) && i < index; - upb_msg_field_next(&iter), i++); - const upb_fielddef *field = upb_msg_iter_field(&iter); - - FieldDescriptor_FromFieldDef(&ret, field); - RETURN_ZVAL(&ret, 1, 0); + FieldDescriptor_FromFieldDef(&ret, upb_msgdef_field(intern->msgdef, index)); + RETURN_COPY_VALUE(&ret); } /* @@ -674,7 +678,7 @@ PHP_METHOD(Descriptor, getOneofDecl) { const upb_oneofdef *oneof = upb_msg_iter_oneof(&iter); OneofDescriptor_FromOneofDef(&ret, oneof); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } /* @@ -702,9 +706,9 @@ PHP_METHOD(Descriptor, getClass) { static zend_function_entry Descriptor_methods[] = { PHP_ME(Descriptor, getClass, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(Descriptor, getFullName, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getField, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getField, arginfo_getByIndex, ZEND_ACC_PUBLIC) PHP_ME(Descriptor, getFieldCount, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getOneofDecl, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getOneofDecl, arginfo_getByIndex, ZEND_ACC_PUBLIC) PHP_ME(Descriptor, getOneofDeclCount, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(Descriptor, getPublicDescriptor, arginfo_void, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -781,7 +785,7 @@ upb_symtab *DescriptorPool_GetSymbolTable() { PHP_METHOD(DescriptorPool, getGeneratedPool) { zval ret; ZVAL_COPY(&ret, get_generated_pool()); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /* @@ -810,7 +814,7 @@ PHP_METHOD(DescriptorPool, getDescriptorByClassName) { } Descriptor_FromClassEntry(&ret, ce); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } /* @@ -839,7 +843,7 @@ PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) { } EnumDescriptor_FromClassEntry(&ret, ce); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } /* @@ -863,9 +867,7 @@ PHP_METHOD(DescriptorPool, getDescriptorByProtoName) { m = upb_symtab_lookupmsg(intern->symtab, protoname); if (m) { - zval ret; - ZVAL_OBJ(&ret, &Descriptor_GetFromMessageDef(m)->std); - RETURN_ZVAL(&ret, 1, 0); + RETURN_OBJ_COPY(&Descriptor_GetFromMessageDef(m)->std); } else { RETURN_NULL(); } @@ -1003,6 +1005,10 @@ PHP_METHOD(DescriptorPool, internalAddGeneratedFile) { upb_arena_free(arena); } +ZEND_BEGIN_ARG_INFO_EX(arginfo_lookupByName, 0, 0, 1) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_addgeneratedfile, 0, 0, 2) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, data_len) @@ -1011,9 +1017,9 @@ ZEND_END_ARG_INFO() static zend_function_entry DescriptorPool_methods[] = { PHP_ME(DescriptorPool, getGeneratedPool, arginfo_void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(DescriptorPool, getDescriptorByClassName, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(DescriptorPool, getDescriptorByProtoName, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(DescriptorPool, getEnumDescriptorByClassName, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, getDescriptorByClassName, arginfo_lookupByName, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, getDescriptorByProtoName, arginfo_lookupByName, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, getEnumDescriptorByClassName, arginfo_lookupByName, ZEND_ACC_PUBLIC) PHP_ME(DescriptorPool, internalAddGeneratedFile, arginfo_addgeneratedfile, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1036,9 +1042,7 @@ zend_class_entry *InternalDescriptorPool_class_entry; * instance. */ PHP_METHOD(InternalDescriptorPool, getGeneratedPool) { - zval ret; - ZVAL_COPY(&ret, get_generated_pool()); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY(get_generated_pool()); } static zend_function_entry InternalDescriptorPool_methods[] = { @@ -1072,6 +1076,7 @@ void Def_ModuleInit() { OneofDescriptor_class_entry->create_object = CreateHandler_ReturnNull; h = &OneofDescriptor_object_handlers; memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = &OneofDescriptor_destructor; INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumValueDescriptor", EnumValueDescriptor_methods); @@ -1081,7 +1086,6 @@ void Def_ModuleInit() { h = &EnumValueDescriptor_object_handlers; memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumDescriptor", EnumDescriptor_methods); EnumDescriptor_class_entry = zend_register_internal_class(&tmp_ce); @@ -1089,6 +1093,7 @@ void Def_ModuleInit() { EnumDescriptor_class_entry->create_object = CreateHandler_ReturnNull; h = &EnumDescriptor_object_handlers; memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = &EnumDescriptor_destructor; INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Descriptor", Descriptor_methods); @@ -1107,6 +1112,7 @@ void Def_ModuleInit() { FieldDescriptor_class_entry->create_object = CreateHandler_ReturnNull; h = &FieldDescriptor_object_handlers; memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = &FieldDescriptor_destructor; INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\DescriptorPool", DescriptorPool_methods); diff --git a/php/ext/google/protobuf/def.h b/php/ext/google/protobuf/def.h index 372c889b31cc..e70564260eae 100644 --- a/php/ext/google/protobuf/def.h +++ b/php/ext/google/protobuf/def.h @@ -61,13 +61,10 @@ typedef struct Descriptor { zend_class_entry *class_entry; } Descriptor; -// Gets or creates a PHP Descriptor object for a |ce| and stores it in |val|. -// If this is not a protobuf generated class, |val| will be set to null. -void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce); - // Gets or creates a Descriptor* for the given class entry, upb_msgdef, or // upb_fielddef. The returned Descriptor* will live for the entire request, -// so no ref is necessary to keep it alive. +// so no ref is necessary to keep it alive. The caller does *not* own a ref +// on the returned object. Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce); Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m); Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f); diff --git a/php/ext/google/protobuf/map.c b/php/ext/google/protobuf/map.c index babd638dab8c..f5890d99e4fd 100644 --- a/php/ext/google/protobuf/map.c +++ b/php/ext/google/protobuf/map.c @@ -357,7 +357,7 @@ PHP_METHOD(MapField, offsetGet) { } Convert_UpbToPhp(upb_val, &ret, intern->type.val_type, &intern->arena); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /** @@ -444,7 +444,7 @@ PHP_METHOD(MapField, count) { PHP_METHOD(MapField, getIterator) { zval ret; MapFieldIter_make(&ret, getThis()); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2) @@ -569,7 +569,7 @@ PHP_METHOD(MapFieldIter, current) { upb_msgval upb_val = upb_mapiter_value(field->map, intern->position); zval ret; Convert_UpbToPhp(upb_val, &ret, field->type.val_type, &field->arena); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /** @@ -583,7 +583,7 @@ PHP_METHOD(MapFieldIter, key) { upb_msgval upb_key = upb_mapiter_key(field->map, intern->position); zval ret; Convert_UpbToPhp(upb_key, &ret, KeyType(field->type), NULL); - RETURN_ZVAL(&ret, 0, 1); + RETURN_COPY_VALUE(&ret); } /** diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 0f1f4c964e6b..b32b325555dc 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -198,8 +198,6 @@ static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); - upb_msgval val1 = upb_msg_get(m1, f); - upb_msgval val2 = upb_msg_get(m2, f); if (upb_fielddef_haspresence(f)) { if (upb_msg_has(m1, f) != upb_msg_has(m2, f)) { @@ -208,6 +206,9 @@ static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) if (!upb_msg_has(m1, f)) continue; } + upb_msgval val1 = upb_msg_get(m1, f); + upb_msgval val2 = upb_msg_get(m2, f); + if (upb_fielddef_ismap(f)) { if (!MapEq(val1.map_val, val2.map_val, MapType_Get(f))) return false; } else if (upb_fielddef_isseq(f)) { @@ -268,7 +269,7 @@ static int Message_has_property(PROTO_VAL *obj, PROTO_STR *member, zend_throw_exception_ex( NULL, 0, "Cannot call isset() on field %s which does not have presence.", - ZSTR_VAL(intern->desc->class_entry->name)); + upb_fielddef_name(f)); return 0; } @@ -303,7 +304,7 @@ static void Message_unset_property(PROTO_VAL *obj, PROTO_STR *member, zend_throw_exception_ex( NULL, 0, "Cannot call unset() on field %s which does not have presence.", - ZSTR_VAL(intern->desc->class_entry->name)); + upb_fielddef_name(f)); return; } @@ -596,7 +597,6 @@ PHP_METHOD(Message, __construct) { return; } - Message_Initialize(intern, desc); if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) { @@ -847,7 +847,7 @@ PHP_METHOD(Message, readWrapperValue) { upb_msgval msgval = upb_msg_get(wrapper, val_f); zval ret; Convert_UpbToPhp(msgval, &ret, TypeInfo_Get(val_f), &intern->arena); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } else { RETURN_NULL(); } @@ -1014,7 +1014,7 @@ PHP_METHOD(Message, readOneof) { Convert_UpbToPhp(msgval, &ret, TypeInfo_Get(f), &intern->arena); } - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } /** @@ -1059,10 +1059,19 @@ PHP_METHOD(Message, writeOneof) { upb_msg_set(intern->msg, f, msgval, arena); } +ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 0) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_mergeFrom, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_mergeFromWithArg, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, arg) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_read, 0, 0, 1) ZEND_ARG_INFO(0, field) ZEND_END_ARG_INFO() @@ -1078,7 +1087,7 @@ static zend_function_entry Message_methods[] = { PHP_ME(Message, serializeToString, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(Message, mergeFromString, arginfo_mergeFrom, ZEND_ACC_PUBLIC) PHP_ME(Message, serializeToJsonString, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFromJsonString, arginfo_mergeFrom, ZEND_ACC_PUBLIC) + PHP_ME(Message, mergeFromJsonString, arginfo_mergeFromWithArg, ZEND_ACC_PUBLIC) PHP_ME(Message, mergeFrom, arginfo_mergeFrom, ZEND_ACC_PUBLIC) PHP_ME(Message, readWrapperValue, arginfo_read, ZEND_ACC_PROTECTED) PHP_ME(Message, writeWrapperValue, arginfo_write, ZEND_ACC_PROTECTED) @@ -1086,7 +1095,7 @@ static zend_function_entry Message_methods[] = { PHP_ME(Message, readOneof, arginfo_read, ZEND_ACC_PROTECTED) PHP_ME(Message, writeOneof, arginfo_write, ZEND_ACC_PROTECTED) PHP_ME(Message, whichOneof, arginfo_read, ZEND_ACC_PROTECTED) - PHP_ME(Message, __construct, arginfo_void, ZEND_ACC_PROTECTED) + PHP_ME(Message, __construct, arginfo_construct, ZEND_ACC_PROTECTED) ZEND_FE_END }; @@ -1165,13 +1174,14 @@ PHP_METHOD(google_protobuf_Any, unpack) { if (!upb_decode(value.data, value.size, msg->msg, upb_msgdef_layout(desc->msgdef), Arena_Get(&msg->arena))) { zend_throw_exception_ex(NULL, 0, "Error occurred during parsing"); + zval_dtor(&ret); return; } // Fuse since the parsed message could alias "value". upb_arena_fuse(Arena_Get(&intern->arena), Arena_Get(&msg->arena)); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } PHP_METHOD(google_protobuf_Any, pack) { @@ -1238,6 +1248,7 @@ PHP_METHOD(google_protobuf_Timestamp, fromDateTime) { const char *classname = "\\DatetimeInterface"; zend_string *classname_str = zend_string_init(classname, strlen(classname), 0); zend_class_entry *date_interface_ce = zend_lookup_class(classname_str); + zend_string_release(classname_str); if (date_interface_ce == NULL) { zend_error(E_ERROR, "Make sure date extension is enabled."); diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 913dfad7e97a..774c8d22eb79 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -1,27 +1,54 @@ /* Amalgamated source file */ #include "php-upb.h" /* -* This is where we define macros used across upb. -* -* All of these macros are undef'd in port_undef.inc to avoid leaking them to -* users. -* -* The correct usage is: -* -* #include "upb/foobar.h" -* #include "upb/baz.h" -* -* // MUST be last included header. -* #include "upb/port_def.inc" -* -* // Code for this file. -* // <...> -* -* // Can be omitted for .c files, required for .h. -* #include "upb/port_undef.inc" -* -* This file is private and must not be included by users! -*/ + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is where we define macros used across upb. + * + * All of these macros are undef'd in port_undef.inc to avoid leaking them to + * users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port_def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port_undef.inc" + * + * This file is private and must not be included by users! + */ #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (defined(__cplusplus) && __cplusplus >= 201103L) || \ @@ -137,9 +164,40 @@ #define UPB_LONGJMP(buf, val) longjmp(buf, val) #endif +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + /* Configure whether fasttable is switched on or not. *************************/ -#if defined(__x86_64__) && defined(__GNUC__) +#if defined(__has_attribute) +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#undef UPB_HAS_ATTRIBUTE + +/* This check is not fully robust: it does not require that we have "musttail" + * support available. We need tail calls to avoid consuming arbitrary amounts + * of stack space. + * + * GCC/Clang can mostly be trusted to generate tail calls as long as + * optimization is enabled, but, debug builds will not generate tail calls + * unless "musttail" is available. + * + * We should probably either: + * 1. require that the compiler supports musttail. + * 2. add some fallback code for when musttail isn't available (ie. return + * instead of tail calling). This is safe and portable, but this comes at + * a CPU cost. + */ +#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) #define UPB_FASTTABLE_SUPPORTED 1 #else #define UPB_FASTTABLE_SUPPORTED 0 @@ -150,7 +208,7 @@ * for example for testing or benchmarking. */ #if defined(UPB_ENABLE_FASTTABLE) #if !UPB_FASTTABLE_SUPPORTED -#error fasttable is x86-64 + Clang/GCC only +#error fasttable is x86-64/ARM64 only and requires GCC or Clang. #endif #define UPB_FASTTABLE 1 /* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. @@ -194,8 +252,9 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) -#endif +#endif +/** upb/decode.c ************************************************************/ #include #include @@ -891,7 +950,7 @@ bool _upb_decode(const char *buf, size_t size, void *msg, state.end_group = DECODE_NOGROUP; state.arena.head = arena->head; state.arena.last_size = arena->last_size; - state.arena.cleanups = arena->cleanups; + state.arena.cleanup_metadata = arena->cleanup_metadata; state.arena.parent = arena; if (UPB_UNLIKELY(UPB_SETJMP(state.err))) { @@ -902,7 +961,7 @@ bool _upb_decode(const char *buf, size_t size, void *msg, arena->head.ptr = state.arena.head.ptr; arena->head.end = state.arena.head.end; - arena->cleanups = state.arena.cleanups; + arena->cleanup_metadata = state.arena.cleanup_metadata; return ok; } @@ -911,6 +970,8 @@ bool _upb_decode(const char *buf, size_t size, void *msg, #undef OP_VARPCK_LG2 #undef OP_STRING #undef OP_SUBMSG + +/** upb/encode.c ************************************************************/ /* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ @@ -1386,7 +1447,7 @@ char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options, return ret; } - +/** upb/msg.c ************************************************************/ /** upb_msg *******************************************************************/ @@ -1517,7 +1578,7 @@ upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) { return NULL; } - upb_strtable_init2(&map->table, UPB_CTYPE_INT32, 4, upb_arena_alloc(a)); + upb_strtable_init(&map->table, 4, a); map->key_size = key_size; map->val_size = value_size; @@ -1638,11 +1699,13 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type, qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); return true; } + +/** upb/table.c ************************************************************/ /* -** upb_table Implementation -** -** Implementation is heavily inspired by Lua's ltable.c. -*/ + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ #include @@ -1663,9 +1726,15 @@ static const double MAX_LOAD = 0.85; * cache effects). The lower this is, the more memory we'll use. */ static const double MIN_DENSITY = 0.1; -bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } -int log2ceil(uint64_t v) { +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; +} + +static int log2ceil(uint64_t v) { int ret = 0; bool pow2 = is_pow2(v); while (v >>= 1) ret++; @@ -1673,11 +1742,7 @@ int log2ceil(uint64_t v) { return UPB_MIN(UPB_MAXARRSIZE, ret); } -char *upb_strdup(const char *s, upb_alloc *a) { - return upb_strdup2(s, strlen(s), a); -} - -char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { +char *upb_strdup2(const char *s, size_t len, upb_arena *a) { size_t n; char *p; @@ -1686,7 +1751,7 @@ char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { /* Always null-terminate, even if binary data; but don't rely on the input to * have a null-terminating byte since it may be a raw binary buffer. */ n = len + 1; - p = upb_malloc(a, n); + p = upb_arena_malloc(a, n); if (p) { memcpy(p, s, len); p[len] = 0; @@ -1721,16 +1786,24 @@ typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); /* Base table (shared code) ***************************************************/ -/* For when we need to cast away const. */ -static upb_tabent *mutable_entries(upb_table *t) { - return (upb_tabent*)t->entries; +static uint32_t upb_inthash(uintptr_t key) { + return (uint32_t)key; +} + +static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { + return t->entries + (hash & t->mask); +} + +static bool upb_arrhas(upb_tabval key) { + return key.val != (uint64_t)-1; } + static bool isfull(upb_table *t) { return t->count == t->max_count; } -static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { +static bool init(upb_table *t, uint8_t size_lg2, upb_arena *a) { size_t bytes; t->count = 0; @@ -1739,21 +1812,17 @@ static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { t->max_count = upb_table_size(t) * MAX_LOAD; bytes = upb_table_size(t) * sizeof(upb_tabent); if (bytes > 0) { - t->entries = upb_malloc(a, bytes); + t->entries = upb_arena_malloc(a, bytes); if (!t->entries) return false; - memset(mutable_entries(t), 0, bytes); + memset(t->entries, 0, bytes); } else { t->entries = NULL; } return true; } -static void uninit(upb_table *t, upb_alloc *a) { - upb_free(a, mutable_entries(t)); -} - static upb_tabent *emptyent(upb_table *t, upb_tabent *e) { - upb_tabent *begin = mutable_entries(t); + upb_tabent *begin = t->entries; upb_tabent *end = begin + upb_table_size(t); for (e = e + 1; e < end; e++) { if (upb_tabent_isempty(e)) return e; @@ -1903,9 +1972,9 @@ static size_t begin(const upb_table *t) { /* A simple "subclass" of upb_table that only adds a hash function for strings. */ -static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) { +static upb_tabkey strcopy(lookupkey_t k2, upb_arena *a) { uint32_t len = (uint32_t) k2.str.len; - char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1); + char *str = upb_arena_malloc(a, k2.str.len + sizeof(uint32_t) + 1); if (str == NULL) return 0; memcpy(str, &len, sizeof(uint32_t)); if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); @@ -1929,9 +1998,7 @@ static bool streql(upb_tabkey k1, lookupkey_t k2) { return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, - size_t expected_size, upb_alloc *a) { - UPB_UNUSED(ctype); /* TODO(haberman): rm */ +bool upb_strtable_init(upb_strtable *t, size_t expected_size, upb_arena *a) { // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 denominator. size_t need_entries = (expected_size + 1) * 1204 / 1024; UPB_ASSERT(need_entries >= expected_size * 0.85); @@ -1945,14 +2012,7 @@ void upb_strtable_clear(upb_strtable *t) { memset((char*)t->t.entries, 0, bytes); } -void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) { - size_t i; - for (i = 0; i < upb_table_size(&t->t); i++) - upb_free(a, (void*)t->t.entries[i].key); - uninit(&t->t, a); -} - -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a) { upb_strtable new_table; upb_strtable_iter i; @@ -1961,17 +2021,15 @@ bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { upb_strtable_begin(&i, t); for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_strview key = upb_strtable_iter_key(&i); - upb_strtable_insert3( - &new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); + upb_strtable_insert(&new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); } - upb_strtable_uninit2(t, a); *t = new_table; return true; } -bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, - upb_value v, upb_alloc *a) { +bool upb_strtable_insert(upb_strtable *t, const char *k, size_t len, + upb_value v, upb_arena *a) { lookupkey_t key; upb_tabkey tabkey; uint32_t hash; @@ -1998,19 +2056,11 @@ bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, - upb_value *val, upb_alloc *alloc) { +bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len, + upb_value *val) { uint32_t hash = table_hash(key, len); upb_tabkey tabkey; - if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { - if (alloc) { - /* Arena-based allocs don't need to free and won't pass this. */ - upb_free(alloc, (void*)tabkey); - } - return true; - } else { - return false; - } + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } /* Iteration */ @@ -2108,7 +2158,7 @@ static void check(upb_inttable *t) { } bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, - upb_alloc *a) { + upb_arena *a) { size_t array_bytes; if (!init(&t->t, hsize_lg2, a)) return false; @@ -2117,9 +2167,8 @@ bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, t->array_size = UPB_MAX(1, asize); t->array_count = 0; array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_malloc(a, array_bytes); + t->array = upb_arena_malloc(a, array_bytes); if (!t->array) { - uninit(&t->t, a); return false; } memset(mutable_array(t), 0xff, array_bytes); @@ -2127,18 +2176,12 @@ bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, return true; } -bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) { - UPB_UNUSED(ctype); /* TODO(haberman): rm */ +bool upb_inttable_init(upb_inttable *t, upb_arena *a) { return upb_inttable_sizedinit(t, 0, 4, a); } -void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) { - uninit(&t->t, a); - upb_free(a, mutable_array(t)); -} - -bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, - upb_alloc *a) { +bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val, + upb_arena *a) { upb_tabval tabval; tabval.val = val.val; UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ @@ -2169,7 +2212,6 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, UPB_ASSERT(t->t.count == new_table.count); - uninit(&t->t, a); t->t = new_table; } insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); @@ -2213,21 +2255,7 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { return success; } -bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, - upb_alloc *a) { - return upb_inttable_insert2(t, (uintptr_t)key, val, a); -} - -bool upb_inttable_lookupptr(const upb_inttable *t, const void *key, - upb_value *v) { - return upb_inttable_lookup(t, (uintptr_t)key, v); -} - -bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { - return upb_inttable_remove(t, (uintptr_t)key, val); -} - -void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { +void upb_inttable_compact(upb_inttable *t, upb_arena *a) { /* A power-of-two histogram of the table keys. */ size_t counts[UPB_MAXARRSIZE + 1] = {0}; @@ -2275,12 +2303,11 @@ void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); } UPB_ASSERT(new_t.array_size == arr_size); UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } - upb_inttable_uninit2(t, a); *t = new_t; } @@ -2354,6 +2381,7 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, i1->array_part == i2->array_part; } +/** upb/upb.c ************************************************************/ #include #include @@ -2420,6 +2448,19 @@ static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, } } +static uint32_t *upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t *)(cleanup_metadata & ~0x1); +} + +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; +} + +static uintptr_t upb_cleanup_metadata(uint32_t *cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} + upb_alloc upb_alloc_global = {&upb_global_allocfunc}; /* upb_arena ******************************************************************/ @@ -2465,7 +2506,8 @@ static void upb_arena_addblock(upb_arena *a, upb_arena *root, void *ptr, a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); a->head.end = UPB_PTR_AT(block, size, char); - a->cleanups = &block->cleanups; + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); } @@ -2513,6 +2555,7 @@ upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) { a->refcount = 1; a->freelist = NULL; a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); upb_arena_addblock(a, a, mem, n); @@ -2540,7 +2583,7 @@ upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) { a->head.ptr = mem; a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); a->freelist = NULL; - a->cleanups = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); return a; } @@ -2575,15 +2618,17 @@ void upb_arena_free(upb_arena *a) { bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { cleanup_ent *ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); - if (!a->cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { + if (!cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { if (!upb_arena_allocblock(a, 128)) return false; /* Out of memory. */ UPB_ASSERT(_upb_arenahas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); } a->head.end -= sizeof(cleanup_ent); ent = (cleanup_ent*)a->head.end; - (*a->cleanups)++; + (*cleanups)++; UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); ent->cleanup = func; @@ -2592,11 +2637,18 @@ bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { return true; } -void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { +bool upb_arena_fuse(upb_arena *a1, upb_arena *a2) { upb_arena *r1 = arena_findroot(a1); upb_arena *r2 = arena_findroot(a2); - if (r1 == r2) return; /* Already fused. */ + if (r1 == r2) return true; /* Already fused. */ + + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; + + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; /* We want to join the smaller tree to the larger tree. * So swap first if they are backwards. */ @@ -2614,12 +2666,15 @@ void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { r1->freelist = r2->freelist; } r2->parent = r1; + return true; } -// Fast decoder: ~3x the speed of decode.c, but x86-64 specific. + +/** upb/decode_fast.c ************************************************************/ +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. // Also the table size grows by 2x. // -// Could potentially be ported to ARM64 or other 64-bit archs that pass at -// least six arguments in registers. +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. // // The overall design is to create specialized functions for every possible // field type (eg. oneof boolean field with a 1 byte tag) and then dispatch @@ -2639,8 +2694,10 @@ void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { #define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data -#define RETURN_GENERIC(m) \ - /* fprintf(stderr, m); */ \ +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ return fastdecode_generic(d, ptr, msg, table, hasbits, 0); typedef enum { @@ -2651,21 +2708,18 @@ typedef enum { } upb_card; UPB_NOINLINE -static const char *fastdecode_isdonefallback(upb_decstate *d, const char *ptr, - upb_msg *msg, intptr_t table, - uint64_t hasbits, int overrun) { +static const char *fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; ptr = decode_isdonefallback_inl(d, ptr, overrun); if (ptr == NULL) { return fastdecode_err(d); } - uint16_t tag = fastdecode_loadtag(ptr); - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag); + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); } UPB_FORCEINLINE -static const char *fastdecode_dispatch(upb_decstate *d, const char *ptr, - upb_msg *msg, intptr_t table, - uint64_t hasbits) { +static const char *fastdecode_dispatch(UPB_PARSE_PARAMS) { if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { int overrun = ptr - d->end; if (UPB_LIKELY(overrun == d->limit)) { @@ -2673,21 +2727,22 @@ static const char *fastdecode_dispatch(upb_decstate *d, const char *ptr, *(uint32_t*)msg |= hasbits; // Sync hasbits. return ptr; } else { - return fastdecode_isdonefallback(d, ptr, msg, table, hasbits, overrun); + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); } } // Read two bytes of tag data (for a one-byte tag, the high byte is junk). - uint16_t tag = fastdecode_loadtag(ptr); - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag); + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); } UPB_FORCEINLINE -static bool fastdecode_checktag(uint64_t data, int tagbytes) { +static bool fastdecode_checktag(uint16_t data, int tagbytes) { if (tagbytes == 1) { return (data & 0xff) == 0; } else { - return (data & 0xffff) == 0; + return data == 0; } } @@ -2911,6 +2966,14 @@ static bool fastdecode_flippacked(uint64_t *data, int tagbytes) { return fastdecode_checktag(*data, tagbytes); } +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ + } + /* varint fields **************************************************************/ UPB_FORCEINLINE @@ -2953,57 +3016,50 @@ static const char *fastdecode_varint64(const char *ptr, uint64_t *val) { return ptr; } -UPB_FORCEINLINE -static const char *fastdecode_unpackedvarint(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, - bool zigzag, - _upb_field_parser *packed) { - uint64_t val; - void *dst; - fastdecode_arr farr; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { - return packed(UPB_PARSE_ARGS); - } - RETURN_GENERIC("varint field tag mismatch\n"); - } - - dst = - fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card); - if (card == CARD_r) { - if (UPB_UNLIKELY(!dst)) { - RETURN_GENERIC("need array resize\n"); - } - } - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, valbytes); - } - - ptr += tagbytes; - ptr = fastdecode_varint64(ptr, &val); - if (ptr == NULL) return fastdecode_err(d); - val = fastdecode_munge(val, valbytes, zigzag); - memcpy(dst, &val, valbytes); - - if (card == CARD_r) { - fastdecode_nextret ret = - fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void *dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) \ + return fastdecode_err(d); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); typedef struct { uint8_t valbytes; @@ -3032,50 +3088,37 @@ static const char *fastdecode_topackedvarint(upb_decstate *d, const char *ptr, return ptr; } -UPB_FORCEINLINE -static const char *fastdecode_packedvarint(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, bool zigzag, - _upb_field_parser *unpacked) { - fastdecode_varintdata ctx = {valbytes, zigzag}; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (fastdecode_flippacked(&data, tagbytes)) { - return unpacked(UPB_PARSE_ARGS); - } else { - RETURN_GENERIC("varint field tag mismatch\n"); - } - } - - ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, - valbytes, CARD_r); - if (UPB_UNLIKELY(!ctx.dst)) { - RETURN_GENERIC("need array resize\n"); - } - - ptr += tagbytes; - ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); - - if (UPB_UNLIKELY(ptr == NULL)) { - return fastdecode_err(d); +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + return fastdecode_err(d); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); + +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ } - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, bool zigzag, - _upb_field_parser *unpacked, - _upb_field_parser *packed) { - if (card == CARD_p) { - return fastdecode_packedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, zigzag, - unpacked); - } else { - return fastdecode_unpackedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, card, - zigzag, packed); - } -} - #define z_ZZ true #define b_ZZ false #define v_ZZ false @@ -3086,10 +3129,10 @@ static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes, #define F(card, type, valbytes, tagbytes) \ UPB_NOINLINE \ const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_varint(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \ - type##_ZZ, \ - &upb_pr##type##valbytes##_##tagbytes##bt, \ - &upb_pp##type##valbytes##_##tagbytes##bt); \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ } #define TYPES(card, tagbytes) \ @@ -3117,126 +3160,110 @@ TAGBYTES(p) #undef F #undef TYPES #undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT /* fixed fields ***************************************************************/ -UPB_FORCEINLINE -static const char *fastdecode_unpackedfixed(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, - _upb_field_parser *packed) { - void *dst; - fastdecode_arr farr; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { - return packed(UPB_PARSE_ARGS); - } - RETURN_GENERIC("fixed field tag mismatch\n"); - } - - dst = - fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card); - if (card == CARD_r) { - if (UPB_UNLIKELY(!dst)) { - RETURN_GENERIC("couldn't allocate array in arena\n"); - } - } - - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, valbytes); - } - - ptr += tagbytes; - memcpy(dst, ptr, valbytes); - ptr += valbytes; - - if (card == CARD_r) { - fastdecode_nextret ret = - fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_packedfixed(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, - _upb_field_parser *unpacked) { - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (fastdecode_flippacked(&data, tagbytes)) { - return unpacked(UPB_PARSE_ARGS); - } else { - RETURN_GENERIC("varint field tag mismatch\n"); - } - } - - ptr += tagbytes; - int size = (uint8_t)ptr[0]; - ptr++; - if (size & 0x80) { - ptr = fastdecode_longsize(ptr, &size); - } - - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr)) || - (size % valbytes) != 0) { - return fastdecode_err(d); +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void *dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ + (size % valbytes) != 0)) { \ + return fastdecode_err(d); \ + } \ + \ + upb_array **arr_p = fastdecode_fieldmem(msg, data); \ + upb_array *arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + return fastdecode_err(d); \ + } \ + } else { \ + _upb_array_resize(arr, elems, &d->arena); \ + } \ + \ + char *dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->len = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ } - upb_array **arr_p = fastdecode_fieldmem(msg, data); - upb_array *arr = *arr_p; - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - int elems = size / valbytes; - - if (UPB_LIKELY(!arr)) { - *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2); - if (!arr) { - return fastdecode_err(d); - } - } else { - _upb_array_resize(arr, elems, &d->arena); - } - - char *dst = _upb_array_ptr(arr); - memcpy(dst, ptr, size); - arr->len = elems; - - return fastdecode_dispatch(d, ptr + size, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_fixed(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, - _upb_field_parser *unpacked, - _upb_field_parser *packed) { - if (card == CARD_p) { - return fastdecode_packedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, unpacked); - } else { - return fastdecode_unpackedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, card, - packed); - } -} - /* Generate all combinations: * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ -#define F(card, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_fixed(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \ - &upb_ppf##valbytes##_##tagbytes##bt, \ - &upb_prf##valbytes##_##tagbytes##bt); \ +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ } #define TYPES(card, tagbytes) \ @@ -3255,6 +3282,8 @@ TAGBYTES(p) #undef F #undef TYPES #undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED /* string fields **************************************************************/ @@ -3266,56 +3295,54 @@ typedef const char *fastdecode_copystr_func(struct upb_decstate *d, UPB_NOINLINE static const char *fastdecode_verifyutf8(upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, - uint64_t hasbits, upb_strview *dst) { + uint64_t hasbits, uint64_t data) { + upb_strview *dst = (upb_strview*)data; if (!decode_verifyutf8_inl(dst->data, dst->size)) { return fastdecode_err(d); } - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_longstring(struct upb_decstate *d, - const char *ptr, upb_msg *msg, - intptr_t table, uint64_t hasbits, - upb_strview *dst, - bool validate_utf8) { - int size = (uint8_t)ptr[0]; // Could plumb through hasbits. - ptr++; - if (size & 0x80) { - ptr = fastdecode_longsize(ptr, &size); + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +} + +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ + dst->size = 0; \ + return fastdecode_err(d); \ + } \ + \ + if (d->alias) { \ + dst->data = ptr; \ + dst->size = size; \ + } else { \ + char *data = upb_arena_malloc(&d->arena, size); \ + if (!data) { \ + return fastdecode_err(d); \ + } \ + memcpy(data, ptr, size); \ + dst->data = data; \ + dst->size = size; \ + } \ + \ + ptr += size; \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ } - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { - dst->size = 0; - return fastdecode_err(d); - } - - if (d->alias) { - dst->data = ptr; - dst->size = size; - } else { - char *data = upb_arena_malloc(&d->arena, size); - if (!data) { - return fastdecode_err(d); - } - memcpy(data, ptr, size); - dst->data = data; - dst->size = size; - } - - if (validate_utf8) { - return fastdecode_verifyutf8(d, ptr + size, msg, table, hasbits, dst); - } else { - return fastdecode_dispatch(d, ptr + size, msg, table, hasbits); - } -} - UPB_NOINLINE static const char *fastdecode_longstring_utf8(struct upb_decstate *d, - const char *ptr, upb_msg *msg, - intptr_t table, uint64_t hasbits, - upb_strview *dst) { - return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, true); + const char *ptr, upb_msg *msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_strview *dst = (upb_strview*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); } UPB_NOINLINE @@ -3323,8 +3350,9 @@ static const char *fastdecode_longstring_noutf8(struct upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, uint64_t hasbits, - upb_strview *dst) { - return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, false); + uint64_t data) { + upb_strview *dst = (upb_strview*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); } UPB_FORCEINLINE @@ -3337,156 +3365,165 @@ static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size, UPB_POISON_MEMORY_REGION(data + size, copy - size); } -UPB_FORCEINLINE -static const char *fastdecode_copystring(UPB_PARSE_PARAMS, int tagbytes, - upb_card card, bool validate_utf8) { - upb_strview *dst; - fastdecode_arr farr; - int64_t size; - size_t arena_has; - size_t common_has; - char *buf; - - UPB_ASSERT(!d->alias); - UPB_ASSERT(fastdecode_checktag(data, tagbytes)); - - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, - sizeof(upb_strview), card); - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); - } - - size = (uint8_t)ptr[tagbytes]; - ptr += tagbytes + 1; - dst->size = size; - - buf = d->arena.head.ptr; - arena_has = _upb_arenahas(&d->arena); - common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); - - if (UPB_LIKELY(size <= 15 - tagbytes)) { - if (arena_has < 16) goto longstr; - d->arena.head.ptr += 16; - memcpy(buf, ptr - tagbytes - 1, 16); - dst->data = buf + tagbytes + 1; - } else if (UPB_LIKELY(size <= 32)) { - if (UPB_UNLIKELY(common_has < 32)) goto longstr; - fastdecode_docopy(d, ptr, size, 32, buf, dst); - } else if (UPB_LIKELY(size <= 64)) { - if (UPB_UNLIKELY(common_has < 64)) goto longstr; - fastdecode_docopy(d, ptr, size, 64, buf, dst); - } else if (UPB_LIKELY(size < 128)) { - if (UPB_UNLIKELY(common_has < 128)) goto longstr; - fastdecode_docopy(d, ptr, size, 128, buf, dst); - } else { - goto longstr; - } - - ptr += size; - - if (card == CARD_r) { - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d); - } - fastdecode_nextret ret = fastdecode_nextrepeated( - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - if (card != CARD_r && validate_utf8) { - return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst); - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); - -longstr: - ptr--; - if (validate_utf8) { - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst); - } else { - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst); - } -} - -UPB_FORCEINLINE -static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes, - upb_card card, _upb_field_parser *copyfunc, - bool validate_utf8) { - upb_strview *dst; - fastdecode_arr farr; - int64_t size; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - RETURN_GENERIC("string field tag mismatch\n"); - } - - if (UPB_UNLIKELY(!d->alias)) { - return copyfunc(UPB_PARSE_ARGS); - } - - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, - sizeof(upb_strview), card); - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); - } - - size = (int8_t)ptr[tagbytes]; - ptr += tagbytes + 1; - dst->data = ptr; - dst->size = size; - - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { - ptr--; - if (validate_utf8) { - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst); - } else { - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst); - } - } - - ptr += size; - - if (card == CARD_r) { - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d); - } - fastdecode_nextret ret = fastdecode_nextrepeated( - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - if (UPB_UNLIKELY(!d->alias)) { - // Buffer flipped and we can't alias any more. Bounce to copyfunc(), - // but via dispatch since we need to reload table data also. - fastdecode_commitarr(dst, &farr, sizeof(upb_strview)); - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - } - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - if (card != CARD_r && validate_utf8) { - return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst); - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_strview *dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char *buf; \ + \ + UPB_ASSERT(!d->alias); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_strview), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.head.ptr; \ + arena_has = _upb_arenahas(&d->arena); \ + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) \ + goto longstr; \ + d->arena.head.ptr += 16; \ + memcpy(buf, ptr - tagbytes - 1, 16); \ + dst->data = buf + tagbytes + 1; \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) \ + goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) \ + goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) \ + goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } + +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_strview *dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY(!d->alias)) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_strview), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->data = ptr; \ + dst->size = size; \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + if (UPB_UNLIKELY(!d->alias)) { \ + /* Buffer flipped and we can't alias any more. Bounce to */ \ + /* copyfunc(), but via dispatch since we need to reload table */ \ + /* data also. */ \ + fastdecode_commitarr(dst, &farr, sizeof(upb_strview)); \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); /* Generate all combinations: * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ @@ -3494,16 +3531,16 @@ static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes, #define s_VALIDATE true #define b_VALIDATE false -#define F(card, tagbytes, type) \ - UPB_NOINLINE \ - const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_copystring(UPB_PARSE_ARGS, tagbytes, CARD_##card, \ - type##_VALIDATE); \ - } \ - const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_string(UPB_PARSE_ARGS, tagbytes, CARD_##card, \ - &upb_c##card##type##_##tagbytes##bt, \ - type##_VALIDATE); \ +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ } #define UTF8(card, tagbytes) \ @@ -3522,6 +3559,9 @@ TAGBYTES(r) #undef b_VALIDATE #undef F #undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING /* message fields *************************************************************/ @@ -3554,82 +3594,82 @@ UPB_FORCEINLINE static const char *fastdecode_tosubmsg(upb_decstate *d, const char *ptr, void *ctx) { fastdecode_submsgdata *submsg = ctx; - ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0); + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); UPB_ASSUME(ptr != NULL); return ptr; } -UPB_FORCEINLINE -static const char *fastdecode_submsg(UPB_PARSE_PARAMS, int tagbytes, - int msg_ceil_bytes, upb_card card) { - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - RETURN_GENERIC("submessage field tag mismatch\n"); - } - - if (--d->depth == 0) return fastdecode_err(d); - - upb_msg **dst; - uint32_t submsg_idx = (data >> 16) & 0xff; - const upb_msglayout *tablep = decode_totablep(table); - const upb_msglayout *subtablep = tablep->submsgs[submsg_idx]; - fastdecode_submsgdata submsg = {decode_totable(subtablep)}; - fastdecode_arr farr; - - if (subtablep->table_mask == (uint8_t)-1) { - RETURN_GENERIC("submessage doesn't have fast tables."); - } - - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, - sizeof(upb_msg *), card); - - if (card == CARD_s) { - *(uint32_t*)msg |= hasbits; - hasbits = 0; - } - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg*)); - } - - submsg.msg = *dst; - - if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { - *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); - } - - ptr += tagbytes; - ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); - - if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { - return fastdecode_err(d); - } - - if (card == CARD_r) { - fastdecode_nextret ret = fastdecode_nextrepeated( - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *)); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - d->depth++; - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - d->depth++; - return ptr; - } - } - - d->depth++; - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ - UPB_PARSE_PARAMS) { \ - return fastdecode_submsg(UPB_PARSE_ARGS, tagbytes, ceil_arg, CARD_##card); \ +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) return fastdecode_err(d); \ + \ + upb_msg **dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_msglayout *tablep = decode_totablep(table); \ + const upb_msglayout *subtablep = tablep->submsgs[submsg_idx]; \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->table_mask == (uint8_t)-1) { \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_msg *), card); \ + \ + if (card == CARD_s) { \ + *(uint32_t *)msg |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg *)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + return fastdecode_err(d); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ } #define SIZES(card, tagbytes) \ @@ -3650,9 +3690,11 @@ TAGBYTES(r) #undef TAGBYTES #undef SIZES #undef F +#undef FASTDECODE_SUBMSG #endif /* UPB_FASTTABLE */ -/* This file was generated by upbc (the upb compiler) from the input + +/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -4134,7 +4176,8 @@ const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = { }; -/* This file was generated by upbc (the upb compiler) from the input + +/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upbdefs.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -4519,6 +4562,7 @@ upb_def_init google_protobuf_descriptor_proto_upbdefinit = { UPB_STRVIEW_INIT(descriptor, 7601) }; +/** upb/def.c ************************************************************/ #include #include @@ -4556,7 +4600,6 @@ struct upb_fielddef { uint32_t number_; uint16_t index_; uint16_t layout_index; - uint32_t selector_base; /* Used to index into a upb::Handlers table. */ bool is_extension_; bool lazy_; bool packed_; @@ -4569,8 +4612,6 @@ struct upb_msgdef { const upb_msglayout *layout; const upb_filedef *file; const char *full_name; - uint32_t selector_count; - uint32_t submsg_field_count; /* Tables for looking up fields by number and name. */ upb_inttable itof; @@ -4700,30 +4741,6 @@ int cmp_fields(const void *p1, const void *p2) { return field_rank(f1) - field_rank(f2); } -/* A few implementation details of handlers. We put these here to avoid - * a def -> handlers dependency. */ - -#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */ - -static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { - return upb_fielddef_isseq(f) ? 2 : 0; -} - -static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { - uint32_t ret = 1; - if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ - if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ - if (upb_fielddef_issubmsg(f)) { - /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ - ret += 0; - if (upb_fielddef_lazy(f)) { - /* STARTSTR/ENDSTR/STRING (for lazy) */ - ret += 3; - } - } - return ret; -} - static void upb_status_setoom(upb_status *status) { upb_status_seterrmsg(status, "out of memory"); } @@ -4815,8 +4832,7 @@ bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { upb_value v; - return upb_inttable_lookup32(&def->iton, num, &v) ? - upb_value_getcstr(v) : NULL; + return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getcstr(v) : NULL; } const char *upb_enum_iter_name(upb_enum_iter *iter) { @@ -4905,10 +4921,6 @@ const char *upb_fielddef_jsonname(const upb_fielddef *f) { return f->json_name; } -uint32_t upb_fielddef_selectorbase(const upb_fielddef *f) { - return f->selector_base; -} - const upb_filedef *upb_fielddef_file(const upb_fielddef *f) { return f->file; } @@ -5071,18 +5083,10 @@ upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) { return m->file->syntax; } -size_t upb_msgdef_selectorcount(const upb_msgdef *m) { - return m->selector_count; -} - -uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m) { - return m->submsg_field_count; -} - const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { upb_value val; - return upb_inttable_lookup32(&m->itof, i, &val) ? - upb_value_getconstptr(val) : NULL; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; } const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, @@ -5290,8 +5294,8 @@ const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) { upb_value val; - return upb_inttable_lookup32(&o->itof, num, &val) ? - upb_value_getptr(val) : NULL; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; } void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) { @@ -5371,7 +5375,6 @@ void upb_symtab_free(upb_symtab *s) { upb_symtab *upb_symtab_new(void) { upb_symtab *s = upb_gmalloc(sizeof(*s)); - upb_alloc *alloc; if (!s) { return NULL; @@ -5379,10 +5382,9 @@ upb_symtab *upb_symtab_new(void) { s->arena = upb_arena_new(); s->bytes_loaded = 0; - alloc = upb_arena_alloc(s->arena); - if (!upb_strtable_init2(&s->syms, UPB_CTYPE_CONSTPTR, 32, alloc) || - !upb_strtable_init2(&s->files, UPB_CTYPE_CONSTPTR, 4, alloc)) { + if (!upb_strtable_init(&s->syms, 32, s->arena) || + !upb_strtable_init(&s->files, 4, s->arena)) { upb_arena_free(s->arena); upb_gfree(s); s = NULL; @@ -5438,8 +5440,7 @@ int upb_symtab_filecount(const upb_symtab *s) { typedef struct { upb_symtab *symtab; upb_filedef *file; /* File we are building. */ - upb_arena *file_arena; /* Allocate defs here. */ - upb_alloc *alloc; /* Alloc of file_arena, for tables. */ + upb_arena *arena; /* Allocate defs here. */ const upb_msglayout **layouts; /* NULL if we should build layouts. */ upb_status *status; /* Record errors here. */ jmp_buf err; /* longjmp() on error. */ @@ -5461,7 +5462,7 @@ static void symtab_oomerr(symtab_addctx *ctx) { } void *symtab_alloc(symtab_addctx *ctx, size_t bytes) { - void *ret = upb_arena_malloc(ctx->file_arena, bytes); + void *ret = upb_arena_malloc(ctx->arena, bytes); if (!ret) symtab_oomerr(ctx); return ret; } @@ -5568,13 +5569,21 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { upb_msg_field_iter it; upb_msg_oneof_iter oit; size_t hasbit; - size_t submsg_count = m->submsg_field_count; + size_t field_count = upb_msgdef_numfields(m); + size_t submsg_count = 0; const upb_msglayout **submsgs; upb_msglayout_field *fields; memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry)); - fields = symtab_alloc(ctx, upb_msgdef_numfields(m) * sizeof(*fields)); + /* Count sub-messages. */ + for (size_t i = 0; i < field_count; i++) { + if (upb_fielddef_issubmsg(&m->fields[i])) { + submsg_count++; + } + } + + fields = symtab_alloc(ctx, field_count * sizeof(*fields)); submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs)); l->field_count = upb_msgdef_numfields(m); @@ -5725,51 +5734,8 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { assign_layout_indices(m, fields); } -static void assign_msg_indices(symtab_addctx *ctx, upb_msgdef *m) { - /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the - * lowest indexes, but we do not publicly guarantee this. */ - upb_msg_field_iter j; - int i; - uint32_t selector; - int n = upb_msgdef_numfields(m); - upb_fielddef **fields; - - if (n == 0) { - m->selector_count = UPB_STATIC_SELECTOR_COUNT; - m->submsg_field_count = 0; - return; - } - - fields = upb_gmalloc(n * sizeof(*fields)); - - m->submsg_field_count = 0; - for(i = 0, upb_msg_field_begin(&j, m); - !upb_msg_field_done(&j); - upb_msg_field_next(&j), i++) { - upb_fielddef *f = upb_msg_iter_field(&j); - UPB_ASSERT(f->msgdef == m); - if (upb_fielddef_issubmsg(f)) { - m->submsg_field_count++; - } - fields[i] = f; - } - - qsort(fields, n, sizeof(*fields), cmp_fields); - - selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; - for (i = 0; i < n; i++) { - upb_fielddef *f = fields[i]; - f->index_ = i; - f->selector_base = selector + upb_handlers_selectorbaseoffset(f); - selector += upb_handlers_selectorcount(f); - } - m->selector_count = selector; - - upb_gfree(fields); -} - static char *strviewdup(symtab_addctx *ctx, upb_strview view) { - return upb_strdup2(view.data, view.size, ctx->alloc); + return upb_strdup2(view.data, view.size, ctx->arena); } static bool streql2(const char *a, size_t n, const char *b) { @@ -5880,9 +5846,9 @@ static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) { if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { symtab_errf(ctx, "duplicate symbol '%s'", name); } - upb_alloc *alloc = upb_arena_alloc(ctx->symtab->arena); size_t len = strlen(name); - CHK_OOM(upb_strtable_insert3(&ctx->symtab->syms, name, len, v, alloc)); + CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, + ctx->symtab->arena)); } /* Given a symbol and the base symbol inside which it is defined, find the @@ -5915,7 +5881,8 @@ static const void *symtab_resolve(symtab_addctx *ctx, const upb_fielddef *f, } notfound: - symtab_errf(ctx, "couldn't resolve name '%s'", sym.data); + symtab_errf(ctx, "couldn't resolve name '" UPB_STRVIEW_FORMAT "'", + UPB_STRVIEW_ARGS(sym)); } static void create_oneofdef( @@ -5933,10 +5900,10 @@ static void create_oneofdef( v = pack_def(o, UPB_DEFTYPE_ONEOF); symtab_add(ctx, o->full_name, v); - CHK_OOM(upb_strtable_insert3(&m->ntof, name.data, name.size, v, ctx->alloc)); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); - CHK_OOM(upb_inttable_init2(&o->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - CHK_OOM(upb_strtable_init2(&o->ntof, UPB_CTYPE_CONSTPTR, 4, ctx->alloc)); + CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); } static str_t *newstr(symtab_addctx *ctx, const char *data, size_t len) { @@ -5992,8 +5959,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len, break; } case UPB_TYPE_INT64: { - /* XXX: Need to write our own strtoll, since it's not available in c89. */ - int64_t val = strtol(str, &end, 0); + long long val = strtoll(str, &end, 0); if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { goto invalid; } @@ -6009,8 +5975,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len, break; } case UPB_TYPE_UINT64: { - /* XXX: Need to write our own strtoull, since it's not available in c89. */ - uint64_t val = strtoul(str, &end, 0); + unsigned long long val = strtoull(str, &end, 0); if (val > UINT64_MAX || errno == ERANGE || *end) { goto invalid; } @@ -6026,8 +5991,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len, break; } case UPB_TYPE_FLOAT: { - /* XXX: Need to write our own strtof, since it's not available in c89. */ - float val = strtod(str, &end); + float val = strtof(str, &end); if (errno == ERANGE || *end) { goto invalid; } @@ -6093,7 +6057,6 @@ static void set_default_default(symtab_addctx *ctx, upb_fielddef *f) { static void create_fielddef( symtab_addctx *ctx, const char *prefix, upb_msgdef *m, const google_protobuf_FieldDescriptorProto *field_proto) { - upb_alloc *alloc = ctx->alloc; upb_fielddef *f; const google_protobuf_FieldOptions *options; upb_strview name; @@ -6129,7 +6092,8 @@ static void create_fielddef( upb_value v, field_v, json_v; size_t json_size; - f = (upb_fielddef*)&m->fields[m->field_count++]; + f = (upb_fielddef*)&m->fields[m->field_count]; + f->index_ = m->field_count++; f->msgdef = m; f->is_extension_ = false; @@ -6150,12 +6114,12 @@ static void create_fielddef( v = upb_value_constptr(f); json_size = strlen(json_name); - CHK_OOM( - upb_strtable_insert3(&m->ntof, name.data, name.size, field_v, alloc)); - CHK_OOM(upb_inttable_insert2(&m->itof, field_number, v, alloc)); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, + ctx->arena)); + CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); if (strcmp(shortname, json_name) != 0) { - upb_strtable_insert3(&m->ntof, json_name, json_size, json_v, alloc); + upb_strtable_insert(&m->ntof, json_name, json_size, json_v, ctx->arena); } if (ctx->layouts) { @@ -6218,15 +6182,16 @@ static void create_fielddef( symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); } - oneof = (upb_oneofdef*)&m->oneofs[oneof_index]; + oneof = (upb_oneofdef *)&m->oneofs[oneof_index]; f->oneof = oneof; oneof->field_count++; if (f->proto3_optional_) { oneof->synthetic = true; } - CHK_OOM(upb_inttable_insert2(&oneof->itof, f->number_, v, alloc)); - CHK_OOM(upb_strtable_insert3(&oneof->ntof, name.data, name.size, v, alloc)); + CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); + CHK_OOM( + upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); } else { f->oneof = NULL; if (f->proto3_optional_) { @@ -6269,8 +6234,8 @@ static void create_enumdef( symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - CHK_OOM(upb_strtable_init2(&e->ntoi, UPB_CTYPE_INT32, n, ctx->alloc)); - CHK_OOM(upb_inttable_init2(&e->iton, UPB_CTYPE_CSTR, ctx->alloc)); + CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); + CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); e->file = ctx->file; e->defaultval = 0; @@ -6297,16 +6262,15 @@ static void create_enumdef( } CHK_OOM(name2) - CHK_OOM( - upb_strtable_insert3(&e->ntoi, name2, strlen(name2), v, ctx->alloc)); + CHK_OOM(upb_strtable_insert(&e->ntoi, name2, strlen(name2), v, ctx->arena)); if (!upb_inttable_lookup(&e->iton, num, NULL)) { upb_value v = upb_value_cstr(name2); - CHK_OOM(upb_inttable_insert2(&e->iton, num, v, ctx->alloc)); + CHK_OOM(upb_inttable_insert(&e->iton, num, v, ctx->arena)); } } - upb_inttable_compact2(&e->iton, ctx->alloc); + upb_inttable_compact(&e->iton, ctx->arena); } static void create_msgdef(symtab_addctx *ctx, const char *prefix, @@ -6330,9 +6294,8 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - CHK_OOM(upb_inttable_init2(&m->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - CHK_OOM(upb_strtable_init2(&m->ntof, UPB_CTYPE_CONSTPTR, n_oneof + n_field, - ctx->alloc)); + CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); m->file = ctx->file; m->map_entry = false; @@ -6364,10 +6327,9 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, create_fielddef(ctx, m->full_name, m, fields[i]); } - assign_msg_indices(ctx, m); finalize_oneofs(ctx, m); assign_msg_wellknowntype(m); - upb_inttable_compact2(&m->itof, ctx->alloc); + upb_inttable_compact(&m->itof, ctx->arena); /* This message is built. Now build nested messages and enums. */ @@ -6596,19 +6558,18 @@ static void build_filedef( } static void remove_filedef(upb_symtab *s, upb_filedef *file) { - upb_alloc *alloc = upb_arena_alloc(s->arena); int i; for (i = 0; i < file->msg_count; i++) { const char *name = file->msgs[i].full_name; - upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + upb_strtable_remove(&s->syms, name, strlen(name), NULL); } for (i = 0; i < file->enum_count; i++) { const char *name = file->enums[i].full_name; - upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + upb_strtable_remove(&s->syms, name, strlen(name), NULL); } for (i = 0; i < file->ext_count; i++) { const char *name = file->exts[i].full_name; - upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + upb_strtable_remove(&s->syms, name, strlen(name), NULL); } } @@ -6626,8 +6587,7 @@ static const upb_filedef *_upb_symtab_addfile( ctx.file = file; ctx.symtab = s; - ctx.file_arena = file_arena; - ctx.alloc = upb_arena_alloc(file_arena); + ctx.arena = file_arena; ctx.layouts = layouts; ctx.status = status; @@ -6642,8 +6602,8 @@ static const upb_filedef *_upb_symtab_addfile( file = NULL; } else { build_filedef(&ctx, file, file_proto); - upb_strtable_insert3(&s->files, file->name, strlen(file->name), - upb_value_constptr(file), ctx.alloc); + upb_strtable_insert(&s->files, file->name, strlen(file->name), + upb_value_constptr(file), ctx.arena); UPB_ASSERT(upb_ok(status)); upb_arena_fuse(s->arena, file_arena); } @@ -6717,6 +6677,7 @@ upb_arena *_upb_symtab_arena(const upb_symtab *s) { #undef CHK_OOM +/** upb/reflection.c ************************************************************/ #include @@ -6827,40 +6788,7 @@ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) { return _upb_msg_getraw(msg, f); } else { - /* TODO(haberman): change upb_fielddef to not require this switch(). */ - upb_msgval val = {0}; - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_ENUM: - val.int32_val = upb_fielddef_defaultint32(f); - break; - case UPB_TYPE_INT64: - val.int64_val = upb_fielddef_defaultint64(f); - break; - case UPB_TYPE_UINT32: - val.uint32_val = upb_fielddef_defaultuint32(f); - break; - case UPB_TYPE_UINT64: - val.uint64_val = upb_fielddef_defaultuint64(f); - break; - case UPB_TYPE_FLOAT: - val.float_val = upb_fielddef_defaultfloat(f); - break; - case UPB_TYPE_DOUBLE: - val.double_val = upb_fielddef_defaultdouble(f); - break; - case UPB_TYPE_BOOL: - val.bool_val = upb_fielddef_defaultbool(f); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - val.str_val.data = upb_fielddef_defaultstr(f, &val.str_val.size); - break; - case UPB_TYPE_MESSAGE: - val.msg_val = NULL; - break; - } - return val; + return upb_fielddef_default(f); } } @@ -7120,6 +7048,7 @@ upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) { /* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */ +/** upb/json_decode.c ************************************************************/ #include #include @@ -8030,17 +7959,17 @@ static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) { return; } - if (upb_fielddef_realcontainingoneof(f) && - upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) { - jsondec_err(d, "More than one field for this oneof."); - } - if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { /* JSON "null" indicates a default value, so no need to set anything. */ jsondec_null(d); return; } + if (upb_fielddef_realcontainingoneof(f) && + upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + preserved = d->debug_field; d->debug_field = f; @@ -8544,6 +8473,9 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, const upb_msgdef *m, const upb_symtab *any_pool, int options, upb_arena *arena, upb_status *status) { jsondec d; + + if (size == 0) return true; + d.ptr = buf; d.end = buf + size; d.arena = arena; @@ -8562,6 +8494,7 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, return true; } +/** upb/json_encode.c ************************************************************/ #include #include @@ -8591,7 +8524,7 @@ static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f); static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg, const upb_msgdef *m); static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg, - const upb_msgdef *m); + const upb_msgdef *m, bool first); static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m); UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) { @@ -8622,8 +8555,10 @@ static void jsonenc_putbytes(jsonenc *e, const void *data, size_t len) { memcpy(e->ptr, data, len); e->ptr += len; } else { - if (have) memcpy(e->ptr, data, have); - e->ptr += have; + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } e->overflow += (len - have); } } @@ -8645,7 +8580,7 @@ static void jsonenc_printf(jsonenc *e, const char *fmt, ...) { if (UPB_LIKELY(have > n)) { e->ptr += n; } else { - e->ptr += have; + e->ptr = UPB_PTRADD(e->ptr, have); e->overflow += (n - have); } } @@ -8749,7 +8684,7 @@ static void jsonenc_bytes(jsonenc *e, upb_strview str) { static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const unsigned char *ptr = (unsigned char*)str.data; - const unsigned char *end = ptr + str.size; + const unsigned char *end = UPB_PTRADD(ptr, str.size); char buf[4]; jsonenc_putstr(e, "\""); @@ -8785,7 +8720,7 @@ static void jsonenc_bytes(jsonenc *e, upb_strview str) { static void jsonenc_stringbody(jsonenc *e, upb_strview str) { const char *ptr = str.data; - const char *end = ptr + str.size; + const char *end = UPB_PTRADD(ptr, str.size); while (ptr < end) { switch (*ptr) { @@ -8901,14 +8836,13 @@ static void jsonenc_any(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) { jsonenc_putstr(e, "{\"@type\":"); jsonenc_string(e, type_url); - jsonenc_putstr(e, ","); if (upb_msgdef_wellknowntype(any_m) == UPB_WELLKNOWN_UNSPECIFIED) { /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ - jsonenc_msgfields(e, any, any_m); + jsonenc_msgfields(e, any, any_m, false); } else { /* Well-known type: {"@type": "...","value": } */ - jsonenc_putstr(e, "\"value\":"); + jsonenc_putstr(e, ",\"value\":"); jsonenc_msgfield(e, any, any_m); } @@ -9211,10 +9145,9 @@ static void jsonenc_fieldval(jsonenc *e, const upb_fielddef *f, } static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg, - const upb_msgdef *m) { + const upb_msgdef *m, bool first) { upb_msgval val; const upb_fielddef *f; - bool first = true; if (e->options & UPB_JSONENC_EMITDEFAULTS) { /* Iterate over all fields. */ @@ -9237,7 +9170,7 @@ static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg, static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) { jsonenc_putstr(e, "{"); - jsonenc_msgfields(e, msg, m); + jsonenc_msgfields(e, msg, m, true); jsonenc_putstr(e, "}"); } @@ -9259,7 +9192,7 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m, e.buf = buf; e.ptr = buf; - e.end = buf + size; + e.end = UPB_PTRADD(buf, size); e.overflow = 0; e.options = options; e.ext_pool = ext_pool; @@ -9272,27 +9205,39 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m, if (e.arena) upb_arena_free(e.arena); return jsonenc_nullz(&e, size); } + +/** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ -#undef UPB_MAPTYPE_STRING #undef UPB_SIZE #undef UPB_PTR_AT #undef UPB_READ_ONEOF #undef UPB_WRITE_ONEOF +#undef UPB_MAPTYPE_STRING #undef UPB_INLINE #undef UPB_ALIGN_UP #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_LIKELY +#undef UPB_UNLIKELY #undef UPB_FORCEINLINE #undef UPB_NOINLINE #undef UPB_NORETURN +#undef UPB_PRINTF #undef UPB_MAX #undef UPB_MIN #undef UPB_UNUSED #undef UPB_ASSUME #undef UPB_ASSERT #undef UPB_UNREACHABLE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index bd72cd9c081f..77a87c769130 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -1,26 +1,53 @@ /* Amalgamated source file */ -#include /* -* This is where we define macros used across upb. -* -* All of these macros are undef'd in port_undef.inc to avoid leaking them to -* users. -* -* The correct usage is: -* -* #include "upb/foobar.h" -* #include "upb/baz.h" -* -* // MUST be last included header. -* #include "upb/port_def.inc" -* -* // Code for this file. -* // <...> -* -* // Can be omitted for .c files, required for .h. -* #include "upb/port_undef.inc" -* -* This file is private and must not be included by users! -*/ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is where we define macros used across upb. + * + * All of these macros are undef'd in port_undef.inc to avoid leaking them to + * users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port_def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port_undef.inc" + * + * This file is private and must not be included by users! + */ #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (defined(__cplusplus) && __cplusplus >= 201103L) || \ @@ -136,9 +163,40 @@ #define UPB_LONGJMP(buf, val) longjmp(buf, val) #endif +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + /* Configure whether fasttable is switched on or not. *************************/ -#if defined(__x86_64__) && defined(__GNUC__) +#if defined(__has_attribute) +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#undef UPB_HAS_ATTRIBUTE + +/* This check is not fully robust: it does not require that we have "musttail" + * support available. We need tail calls to avoid consuming arbitrary amounts + * of stack space. + * + * GCC/Clang can mostly be trusted to generate tail calls as long as + * optimization is enabled, but, debug builds will not generate tail calls + * unless "musttail" is available. + * + * We should probably either: + * 1. require that the compiler supports musttail. + * 2. add some fallback code for when musttail isn't available (ie. return + * instead of tail calling). This is safe and portable, but this comes at + * a CPU cost. + */ +#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) #define UPB_FASTTABLE_SUPPORTED 1 #else #define UPB_FASTTABLE_SUPPORTED 0 @@ -149,7 +207,7 @@ * for example for testing or benchmarking. */ #if defined(UPB_ENABLE_FASTTABLE) #if !UPB_FASTTABLE_SUPPORTED -#error fasttable is x86-64 + Clang/GCC only +#error fasttable is x86-64/ARM64 only and requires GCC or Clang. #endif #define UPB_FASTTABLE 1 /* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. @@ -193,55 +251,36 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) -#endif +#endif + +/** upb/decode.h ************************************************************/ /* -** upb_decode: parsing into a upb_msg using a upb_msglayout. -*/ + * upb_decode: parsing into a upb_msg using a upb_msglayout. + */ #ifndef UPB_DECODE_H_ #define UPB_DECODE_H_ + +/** upb/msg.h ************************************************************/ /* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ + * Public APIs for message operations that do not require descriptors. + * These functions can be used even in build that does not want to depend on + * reflection or descriptors. + * + * Descriptor-based reflection functionality lives in reflection.h. + */ #ifndef UPB_MSG_H_ #define UPB_MSG_H_ -#include -#include -#include - -/* -** upb_table -** -** This header is INTERNAL-ONLY! Its interfaces are not public or stable! -** This file defines very fast int->upb_value (inttable) and string->upb_value -** (strtable) hash tables. -** -** The table uses chained scatter with Brent's variation (inspired by the Lua -** implementation of hash tables). The hash function for strings is Austin -** Appleby's "MurmurHash." -** -** The inttable uses uintptr_t as its key, which guarantees it can be used to -** store pointers or integers of at least 32 bits (upb isn't really useful on -** systems where sizeof(void*) < 4). -** -** The table must be homogeneous (all values of the same type). In debug -** mode, we check this on insert and lookup. -*/ +#include -#ifndef UPB_TABLE_H_ -#define UPB_TABLE_H_ -#include -#include +/** upb/upb.h ************************************************************/ /* -** This file contains shared definitions that are widely used across upb. -*/ + * This file contains shared definitions that are widely used across upb. + */ #ifndef UPB_H_ #define UPB_H_ @@ -399,7 +438,7 @@ typedef struct { upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc); void upb_arena_free(upb_arena *a); bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func); -void upb_arena_fuse(upb_arena *a, upb_arena *b); +bool upb_arena_fuse(upb_arena *a, upb_arena *b); void *_upb_arena_slowmalloc(upb_arena *a, size_t size); UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; } @@ -578,55 +617,134 @@ UPB_INLINE int _upb_lg2ceilsize(int x) { #endif /* UPB_H_ */ +#ifdef __cplusplus +extern "C" { +#endif + +typedef void upb_msg; + +/* For users these are opaque. They can be obtained from upb_msgdef_layout() + * but users cannot access any of the members. */ +struct upb_msglayout; +typedef struct upb_msglayout upb_msglayout; + +/* Adds unknown data (serialized protobuf data) to the given message. The data + * is copied into the message instance. */ +void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, + upb_arena *arena); + +/* Returns a reference to the message's unknown data. */ +const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_MSG_INT_H_ */ + +/* Must be last. */ #ifdef __cplusplus extern "C" { #endif +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + UPB_DECODE_ALIAS = 1, +}; -/* upb_value ******************************************************************/ +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) -/* A tagged union (stored untagged inside the table) so that we can check that - * clients calling table accessors are correctly typed without having to have - * an explosion of accessors. */ -typedef enum { - UPB_CTYPE_INT32 = 1, - UPB_CTYPE_INT64 = 2, - UPB_CTYPE_UINT32 = 3, - UPB_CTYPE_UINT64 = 4, - UPB_CTYPE_BOOL = 5, - UPB_CTYPE_CSTR = 6, - UPB_CTYPE_PTR = 7, - UPB_CTYPE_CONSTPTR = 8, - UPB_CTYPE_FPTR = 9, - UPB_CTYPE_FLOAT = 10, - UPB_CTYPE_DOUBLE = 11 -} upb_ctype_t; +bool _upb_decode(const char *buf, size_t size, upb_msg *msg, + const upb_msglayout *l, upb_arena *arena, int options); + +UPB_INLINE +bool upb_decode(const char *buf, size_t size, upb_msg *msg, + const upb_msglayout *l, upb_arena *arena) { + return _upb_decode(buf, size, msg, l, arena, 0); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_DECODE_H_ */ + +/** upb/decode_internal.h ************************************************************/ +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_DECODE_INT_H_ +#define UPB_DECODE_INT_H_ + +#include + + +/** upb/msg_internal.h ************************************************************//* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ + +#ifndef UPB_MSG_INT_H_ +#define UPB_MSG_INT_H_ + +#include +#include +#include + + +/** upb/table_internal.h ************************************************************/ +/* + * upb_table + * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! + * This file defines very fast int->upb_value (inttable) and string->upb_value + * (strtable) hash tables. + * + * The table uses chained scatter with Brent's variation (inspired by the Lua + * implementation of hash tables). The hash function for strings is Austin + * Appleby's "MurmurHash." + * + * The inttable uses uintptr_t as its key, which guarantees it can be used to + * store pointers or integers of at least 32 bits (upb isn't really useful on + * systems where sizeof(void*) < 4). + * + * The table must be homogeneous (all values of the same type). In debug + * mode, we check this on insert and lookup. + */ + +#ifndef UPB_TABLE_H_ +#define UPB_TABLE_H_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* upb_value ******************************************************************/ typedef struct { uint64_t val; } upb_value; -/* Like strdup(), which isn't always available since it's not ANSI C. */ -char *upb_strdup(const char *s, upb_alloc *a); /* Variant that works with a length-delimited rather than NULL-delimited string, * as supported by strtable. */ -char *upb_strdup2(const char *s, size_t len, upb_alloc *a); - -UPB_INLINE char *upb_gstrdup(const char *s) { - return upb_strdup(s, &upb_alloc_global); -} +char *upb_strdup2(const char *s, size_t len, upb_arena *a); UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val) { v->val = val; } -UPB_INLINE upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; -} - /* For each value ctype, define the following set of functions: * * // Get/set an int32 from a upb_value. @@ -734,14 +852,7 @@ typedef struct { uint32_t mask; /* Mask to turn hash value -> bucket. */ uint32_t max_count; /* Max count before we hit our load limit. */ uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ - - /* Hash table entries. - * Making this const isn't entirely accurate; what we really want is for it to - * have the same const-ness as the table it's inside. But there's no way to - * declare that in C. So we have to make it const so that we can statically - * initialize const hash tables. Then we cast away const when we have to. - */ - const upb_tabent *entries; + upb_tabent *entries; } upb_table; typedef struct { @@ -755,8 +866,6 @@ typedef struct { size_t array_count; /* Array part number of elements. */ } upb_inttable; -#define UPB_ARRAY_EMPTYENT -1 - UPB_INLINE size_t upb_table_size(const upb_table *t) { if (t->size_lg2 == 0) return 0; @@ -769,48 +878,10 @@ UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) { return e->key == 0; } -/* Used by some of the unit tests for generic hashing functionality. */ -uint32_t upb_murmur_hash2(const void * key, size_t len, uint32_t seed); - -UPB_INLINE uintptr_t upb_intkey(uintptr_t key) { - return key; -} - -UPB_INLINE uint32_t upb_inthash(uintptr_t key) { - return (uint32_t)key; -} - -static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { - return t->entries + (hash & t->mask); -} - -UPB_INLINE bool upb_arrhas(upb_tabval key) { - return key.val != (uint64_t)-1; -} - /* Initialize and uninitialize a table, respectively. If memory allocation * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a); -bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, - size_t expected_size, upb_alloc *a); -void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a); -void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a); - -UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) { - return upb_inttable_init2(table, ctype, &upb_alloc_global); -} - -UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) { - return upb_strtable_init2(table, ctype, 4, &upb_alloc_global); -} - -UPB_INLINE void upb_inttable_uninit(upb_inttable *table) { - upb_inttable_uninit2(table, &upb_alloc_global); -} - -UPB_INLINE void upb_strtable_uninit(upb_strtable *table) { - upb_strtable_uninit2(table, &upb_alloc_global); -} +bool upb_inttable_init(upb_inttable *table, upb_arena *a); +bool upb_strtable_init(upb_strtable *table, size_t expected_size, upb_arena *a); /* Returns the number of values in the table. */ size_t upb_inttable_count(const upb_inttable *t); @@ -818,12 +889,6 @@ UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) { return t->t.count; } -void upb_inttable_packedsize(const upb_inttable *t, size_t *size); -void upb_strtable_packedsize(const upb_strtable *t, size_t *size); -upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs, - size_t size); -upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs, - size_t size); void upb_strtable_clear(upb_strtable *t); /* Inserts the given key into the hashtable with the given value. The key must @@ -833,26 +898,10 @@ void upb_strtable_clear(upb_strtable *t); * * If a table resize was required but memory allocation failed, false is * returned and the table is unchanged. */ -bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, - upb_alloc *a); -bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len, - upb_value val, upb_alloc *a); - -UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key, - upb_value val) { - return upb_inttable_insert2(t, key, val, &upb_alloc_global); -} - -UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key, - size_t len, upb_value val) { - return upb_strtable_insert3(t, key, len, val, &upb_alloc_global); -} - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key, - upb_value val) { - return upb_strtable_insert2(t, key, strlen(key), val); -} +bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val, + upb_arena *a); +bool upb_strtable_insert(upb_strtable *t, const char *key, size_t len, + upb_value val, upb_arena *a); /* Looks up key in this table, returning "true" if the key was found. * If v is non-NULL, copies the value for this key into *v. */ @@ -869,74 +918,21 @@ UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key, /* Removes an item from the table. Returns true if the remove was successful, * and stores the removed item in *val if non-NULL. */ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); -bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, - upb_value *val, upb_alloc *alloc); - -UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key, - size_t len, upb_value *val) { - return upb_strtable_remove3(t, key, len, val, &upb_alloc_global); -} - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, - upb_value *v) { - return upb_strtable_remove2(t, key, strlen(key), v); -} +bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len, + upb_value *val); /* Updates an existing entry in an inttable. If the entry does not exist, * returns false and does nothing. Unlike insert/remove, this does not * invalidate iterators. */ bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); -/* Convenience routines for inttables with pointer keys. */ -bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, - upb_alloc *a); -bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); -bool upb_inttable_lookupptr( - const upb_inttable *t, const void *key, upb_value *val); - -UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key, - upb_value val) { - return upb_inttable_insertptr2(t, key, val, &upb_alloc_global); -} - /* Optimizes the table for the current set of entries, for both memory use and * lookup time. Client should call this after all entries have been inserted; * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact2(upb_inttable *t, upb_alloc *a); - -UPB_INLINE void upb_inttable_compact(upb_inttable *t) { - upb_inttable_compact2(t, &upb_alloc_global); -} - -/* A special-case inlinable version of the lookup routine for 32-bit - * integers. */ -UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, - upb_value *v) { - *v = upb_value_int32(0); /* Silence compiler warnings. */ - if (key < t->array_size) { - upb_tabval arrval = t->array[key]; - if (upb_arrhas(arrval)) { - _upb_value_setval(v, arrval.val); - return true; - } else { - return false; - } - } else { - const upb_tabent *e; - if (t->t.entries == NULL) return false; - for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) { - if ((uint32_t)e->key == key) { - _upb_value_setval(v, e->val.val); - return true; - } - if (e->next == NULL) return false; - } - } -} +void upb_inttable_compact(upb_inttable *t, upb_arena *a); /* Exposed for testing only. */ -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a); +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a); /* Iterators ******************************************************************/ @@ -1032,10 +1028,6 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, extern "C" { #endif -#define PTR_AT(msg, ofs, type) (type*)((const char*)msg + ofs) - -typedef void upb_msg; - /** upb_msglayout *************************************************************/ /* upb_msglayout represents the memory layout of a given upb_msgdef. The @@ -1070,7 +1062,7 @@ typedef struct { _upb_field_parser *field_parser; } _upb_fasttable_entry; -typedef struct upb_msglayout { +struct upb_msglayout { const struct upb_msglayout *const* submsgs; const upb_msglayout_field *fields; /* Must be aligned to sizeof(void*). Doesn't include internal members like @@ -1082,7 +1074,7 @@ typedef struct upb_msglayout { /* To constant-initialize the tables of variable length, we need a flexible * array member, and we need to compile in C99 mode. */ _upb_fasttable_entry fasttable[]; -} upb_msglayout; +}; /** upb_msg *******************************************************************/ @@ -1137,21 +1129,18 @@ void _upb_msg_discardunknown_shallow(upb_msg *msg); bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, upb_arena *arena); -/* Returns a reference to the message's unknown data. */ -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); - /** Hasbit access *************************************************************/ UPB_INLINE bool _upb_hasbit(const upb_msg *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; + return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; } UPB_INLINE void _upb_sethas(const upb_msg *msg, size_t idx) { - (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); + (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); } UPB_INLINE void _upb_clearhas(const upb_msg *msg, size_t idx) { - (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); + (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); } UPB_INLINE size_t _upb_msg_hasidx(const upb_msglayout_field *f) { @@ -1177,11 +1166,11 @@ UPB_INLINE void _upb_clearhas_field(const upb_msg *msg, /** Oneof case access *********************************************************/ UPB_INLINE uint32_t *_upb_oneofcase(upb_msg *msg, size_t case_ofs) { - return PTR_AT(msg, case_ofs, uint32_t); + return UPB_PTR_AT(msg, case_ofs, uint32_t); } UPB_INLINE uint32_t _upb_getoneofcase(const void *msg, size_t case_ofs) { - return *PTR_AT(msg, case_ofs, uint32_t); + return *UPB_PTR_AT(msg, case_ofs, uint32_t); } UPB_INLINE size_t _upb_oneofcase_ofs(const upb_msglayout_field *f) { @@ -1200,7 +1189,7 @@ UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_msg *msg, } UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_msg *msg, size_t ofs) { - return *PTR_AT(msg, ofs, const upb_msg*) != NULL; + return *UPB_PTR_AT(msg, ofs, const upb_msg*) != NULL; } UPB_INLINE bool _upb_isrepeated(const upb_msglayout_field *field) { @@ -1277,7 +1266,7 @@ UPB_INLINE bool _upb_array_resize(upb_array *arr, size_t size, UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs, size_t *size) { - const upb_array *arr = *PTR_AT(msg, ofs, const upb_array*); + const upb_array *arr = *UPB_PTR_AT(msg, ofs, const upb_array*); if (arr) { if (size) *size = arr->len; return _upb_array_constptr(arr); @@ -1289,7 +1278,7 @@ UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs, UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, size_t *size) { - upb_array *arr = *PTR_AT(msg, ofs, upb_array*); + upb_array *arr = *UPB_PTR_AT(msg, ofs, upb_array*); if (arr) { if (size) *size = arr->len; return _upb_array_ptr(arr); @@ -1302,7 +1291,7 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, UPB_INLINE void *_upb_array_resize_accessor2(void *msg, size_t ofs, size_t size, int elem_size_lg2, upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *); + upb_array **arr_ptr = UPB_PTR_AT(msg, ofs, upb_array *); upb_array *arr = *arr_ptr; if (!arr || arr->size < size) { return _upb_array_resize_fallback(arr_ptr, size, elem_size_lg2, arena); @@ -1315,7 +1304,7 @@ UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs, int elem_size_lg2, const void *value, upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *); + upb_array **arr_ptr = UPB_PTR_AT(msg, ofs, upb_array *); size_t elem_size = 1 << elem_size_lg2; upb_array *arr = *arr_ptr; void *ptr; @@ -1323,7 +1312,7 @@ UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs, return _upb_array_append_fallback(arr_ptr, value, elem_size_lg2, arena); } ptr = _upb_array_ptr(arr); - memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); + memcpy(UPB_PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); arr->len++; return true; } @@ -1470,20 +1459,19 @@ UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) { } UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size, - void *val, size_t val_size, upb_arena *arena) { + void *val, size_t val_size, upb_arena *a) { upb_strview strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, arena)) return false; - upb_alloc *a = upb_arena_alloc(arena); + if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); - return upb_strtable_insert3(&map->table, strkey.data, strkey.size, tabval, a); + upb_strtable_remove(&map->table, strkey.data, strkey.size, NULL); + return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); } UPB_INLINE bool _upb_map_delete(upb_map *map, const void *key, size_t key_size) { upb_strview k = _upb_map_tokey(key, key_size); - return upb_strtable_remove3(&map->table, k.data, k.size, NULL, NULL); + return upb_strtable_remove(&map->table, k.data, k.size, NULL); } UPB_INLINE void _upb_map_clear(upb_map *map) { @@ -1515,7 +1503,7 @@ UPB_INLINE void *_upb_msg_map_next(const upb_msg *msg, size_t ofs, UPB_INLINE bool _upb_msg_map_set(upb_msg *msg, size_t ofs, const void *key, size_t key_size, void *val, size_t val_size, upb_arena *arena) { - upb_map **map = PTR_AT(msg, ofs, upb_map *); + upb_map **map = UPB_PTR_AT(msg, ofs, upb_map *); if (!*map) { *map = _upb_map_new(arena, key_size, val_size); } @@ -1548,8 +1536,7 @@ UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { const upb_tabent *ent = (const upb_tabent*)msg; - upb_value v; - _upb_value_setval(&v, ent->val.val); + upb_value v = {ent->val.val}; _upb_map_fromvalue(v, val, size); } @@ -1612,55 +1599,14 @@ UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter *s, const upb_map *map, return true; } -#undef PTR_AT - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MSG_H_ */ - -/* Must be last. */ - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* If set, strings will alias the input buffer instead of copying into the - * arena. */ - UPB_DECODE_ALIAS = 1, -}; - -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) - -bool _upb_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msglayout *l, upb_arena *arena, int options); - -UPB_INLINE -bool upb_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msglayout *l, upb_arena *arena) { - return _upb_decode(buf, size, msg, l, arena, 0); -} - #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_DECODE_H_ */ -/* -** Internal implementation details of the decoder that are shared between -** decode.c and decode_fast.c. -*/ - -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ - -#include - +#endif /* UPB_MSG_INT_H_ */ +/** upb/upb_internal.h ************************************************************/ #ifndef UPB_INT_H_ #define UPB_INT_H_ @@ -1670,7 +1616,10 @@ typedef struct mem_block mem_block; struct upb_arena { _upb_arena_head head; - uint32_t *cleanups; + /* Stores cleanup metadata for this arena. + * - a pointer to the current cleanup counter. + * - a boolean indicating if there is an unowned initial block. */ + uintptr_t cleanup_metadata; /* Allocator to allocate arena blocks. We are responsible for freeing these * when we are destroyed. */ @@ -1792,10 +1741,11 @@ bool decode_isdone(upb_decstate *d, const char **ptr) { } } +#if UPB_FASTTABLE UPB_INLINE const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, - uint64_t hasbits, uint32_t tag) { + uint64_t hasbits, uint64_t tag) { const upb_msglayout *table_p = decode_totablep(table); uint8_t mask = table; uint64_t data; @@ -1803,8 +1753,10 @@ const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr, UPB_ASSUME((idx & 7) == 0); idx >>= 3; data = table_p->fasttable[idx].field_data ^ tag; - return table_p->fasttable[idx].field_parser(d, ptr, msg, table, hasbits, data); + UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, + hasbits, data); } +#endif UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { uint16_t tag; @@ -1837,9 +1789,11 @@ UPB_INLINE void decode_poplimit(upb_decstate *d, const char *ptr, #endif /* UPB_DECODE_INT_H_ */ + +/** upb/encode.h ************************************************************/ /* -** upb_encode: parsing into a upb_msg using a upb_msglayout. -*/ + * upb_encode: parsing into a upb_msg using a upb_msglayout. + */ #ifndef UPB_ENCODE_H_ #define UPB_ENCODE_H_ @@ -1880,6 +1834,8 @@ UPB_INLINE char *upb_encode(const void *msg, const upb_msglayout *l, #endif #endif /* UPB_ENCODE_H_ */ + +/** upb/decode_fast.h ************************************************************/ // These are the specialized field parser functions for the fast parser. // Generated tables will refer to these by name. // @@ -2005,7 +1961,8 @@ TAGBYTES(r) #undef UPB_PARSE_PARAMS #endif /* UPB_DECODE_FAST_H_ */ -/* This file was generated by upbc (the upb compiler) from the input + +/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -3884,18 +3841,20 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_prot #endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ + +/** upb/def.h ************************************************************/ /* -** Defs are upb's internal representation of the constructs that can appear -** in a .proto file: -** -** - upb_msgdef: describes a "message" construct. -** - upb_fielddef: describes a message field. -** - upb_filedef: describes a .proto file and its defs. -** - upb_enumdef: describes an enum. -** - upb_oneofdef: describes a oneof. -** -** TODO: definitions of services. -*/ + * Defs are upb's internal representation of the constructs that can appear + * in a .proto file: + * + * - upb_msgdef: describes a "message" construct. + * - upb_fielddef: describes a message field. + * - upb_filedef: describes a .proto file and its defs. + * - upb_enumdef: describes an enum. + * - upb_oneofdef: describes a oneof. + * + * TODO: definitions of services. + */ #ifndef UPB_DEF_H_ #define UPB_DEF_H_ @@ -3991,9 +3950,6 @@ const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f); -/* Internal only. */ -uint32_t upb_fielddef_selectorbase(const upb_fielddef *f); - /* upb_oneofdef ***************************************************************/ typedef upb_inttable_iter upb_oneof_iter; @@ -4078,10 +4034,6 @@ UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m, return upb_msgdef_ntof(m, name, strlen(name)); } -/* Internal-only. */ -size_t upb_msgdef_selectorcount(const upb_msgdef *m); -uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m); - /* Lookup of either field or oneof by name. Returns whether either was found. * If the return is true, then the found def will be set, and the non-found * one set to NULL. */ @@ -4196,7 +4148,8 @@ bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init); #endif /* __cplusplus */ #endif /* UPB_DEF_H_ */ -/* This file was generated by upbc (the upb compiler) from the input + +/** google/protobuf/descriptor.upbdefs.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -4357,6 +4310,7 @@ UPB_INLINE const upb_msgdef *google_protobuf_GeneratedCodeInfo_Annotation_getmsg #endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ */ +/** upb/reflection.h ************************************************************/ #ifndef UPB_REFLECTION_H_ #define UPB_REFLECTION_H_ @@ -4438,17 +4392,9 @@ bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, const upb_symtab *ext_pool, const upb_fielddef **f, upb_msgval *val, size_t *iter); -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena); - /* Clears all unknown field data from this message and all submessages. */ bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth); -/* Returns a reference to the message's unknown data. */ -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); - /** upb_array *****************************************************************/ /* Creates a new array on the given arena that holds elements of this type. */ @@ -4530,6 +4476,7 @@ void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); #endif /* UPB_REFLECTION_H_ */ +/** upb/json_decode.h ************************************************************/ #ifndef UPB_JSONDECODE_H_ #define UPB_JSONDECODE_H_ @@ -4552,6 +4499,7 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, #endif /* UPB_JSONDECODE_H_ */ +/** upb/json_encode.h ************************************************************/ #ifndef UPB_JSONENCODE_H_ #define UPB_JSONENCODE_H_ @@ -4586,27 +4534,39 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m, #endif #endif /* UPB_JSONENCODE_H_ */ + +/** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ -#undef UPB_MAPTYPE_STRING #undef UPB_SIZE #undef UPB_PTR_AT #undef UPB_READ_ONEOF #undef UPB_WRITE_ONEOF +#undef UPB_MAPTYPE_STRING #undef UPB_INLINE #undef UPB_ALIGN_UP #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_LIKELY +#undef UPB_UNLIKELY #undef UPB_FORCEINLINE #undef UPB_NOINLINE #undef UPB_NORETURN +#undef UPB_PRINTF #undef UPB_MAX #undef UPB_MIN #undef UPB_UNUSED #undef UPB_ASSUME #undef UPB_ASSERT #undef UPB_UNREACHABLE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c index dbdd22a8f624..888b434b7b68 100644 --- a/php/ext/google/protobuf/protobuf.c +++ b/php/ext/google/protobuf/protobuf.c @@ -74,6 +74,12 @@ ZEND_BEGIN_MODULE_GLOBALS(protobuf) // Name cache (see interface in protobuf.h). HashTable name_msg_cache; HashTable name_enum_cache; + + // An array of descriptor objects constructed during this request. These are + // logically referenced by the corresponding class entry, but since we can't + // actually write a class entry destructor, we reference them here, to be + // destroyed on request shutdown. + HashTable descriptors; ZEND_END_MODULE_GLOBALS(protobuf) ZEND_DECLARE_MODULE_GLOBALS(protobuf) @@ -164,6 +170,7 @@ static PHP_RINIT_FUNCTION(protobuf) { zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0); zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, 0); zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0); + zend_hash_init(&PROTOBUF_G(descriptors), 64, NULL, ZVAL_PTR_DTOR, 0); return SUCCESS; } @@ -184,6 +191,7 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) { zend_hash_destroy(&PROTOBUF_G(object_cache)); zend_hash_destroy(&PROTOBUF_G(name_msg_cache)); zend_hash_destroy(&PROTOBUF_G(name_enum_cache)); + zend_hash_destroy(&PROTOBUF_G(descriptors)); return SUCCESS; } @@ -192,6 +200,15 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) { // Object Cache. // ----------------------------------------------------------------------------- +void Descriptors_Add(zend_object *desc) { + // The hash table will own a ref (it will destroy it when the table is + // destroyed), but for some reason the insert operation does not add a ref, so + // we do that here with ZVAL_OBJ_COPY(). + zval zv; + ZVAL_OBJ_COPY(&zv, desc); + zend_hash_next_index_insert(&PROTOBUF_G(descriptors), &zv); +} + void ObjCache_Add(const void *upb_obj, zend_object *php_obj) { zend_ulong k = (zend_ulong)upb_obj; zend_hash_index_add_ptr(&PROTOBUF_G(object_cache), k, php_obj); @@ -210,8 +227,7 @@ bool ObjCache_Get(const void *upb_obj, zval *val) { zend_object *obj = zend_hash_index_find_ptr(&PROTOBUF_G(object_cache), k); if (obj) { - GC_ADDREF(obj); - ZVAL_OBJ(val, obj); + ZVAL_OBJ_COPY(val, obj); return true; } else { ZVAL_NULL(val); diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 858b520a7fd9..a32bac426b04 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -58,9 +58,14 @@ const zval *get_generated_pool(); #if PHP_VERSION_ID < 80000 #define PROTO_VAL zval #define PROTO_STR zval -#define PROTO_VAL_P(obj) Z_OBJ_P(obj) +#define PROTO_VAL_P(obj) (void*)Z_OBJ_P(obj) #define PROTO_STRVAL_P(obj) Z_STRVAL_P(obj) #define PROTO_STRLEN_P(obj) Z_STRLEN_P(obj) +#define ZVAL_OBJ_COPY(z, o) do { ZVAL_OBJ(z, o); GC_ADDREF(o); } while (0) +#define RETVAL_OBJ_COPY(r) ZVAL_OBJ_COPY(return_value, r) +#define RETURN_OBJ_COPY(r) do { RETVAL_OBJ_COPY(r); return; } while (0) +#define RETURN_COPY(zv) do { ZVAL_COPY(return_value, zv); return; } while (0) +#define RETURN_COPY_VALUE(zv) do { ZVAL_COPY_VALUE(return_value, zv); return; } while (0) #else #define PROTO_VAL zend_object #define PROTO_STR zend_string @@ -85,7 +90,7 @@ ZEND_END_ARG_INFO() // * upb_map*, -> MapField // * upb_msgdef* -> Descriptor // * upb_enumdef* -> EnumDescriptor -// * zend_class_entry* -> Descriptor +// * upb_msgdef* -> Descriptor // // Each wrapped object should add itself to the map when it is constructed, and // remove itself from the map when it is destroyed. This is how we ensure that @@ -105,6 +110,11 @@ void NameMap_AddEnum(const upb_enumdef *m); const upb_msgdef *NameMap_GetMessage(zend_class_entry *ce); const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce); +// Add this descriptor object to the global list of descriptors that will be +// kept alive for the duration of the request but destroyed when the request +// is ending. +void Descriptors_Add(zend_object *desc); + // We need our own assert() because PHP takes control of NDEBUG in its headers. #ifdef PBPHP_ENABLE_ASSERTS #define PBPHP_ASSERT(x) \ diff --git a/php/ext/google/protobuf/wkt.inc b/php/ext/google/protobuf/wkt.inc index 401f2e825b0c..df3cce9136d9 100644 --- a/php/ext/google/protobuf/wkt.inc +++ b/php/ext/google/protobuf/wkt.inc @@ -1,5 +1,10 @@ // This file is generated from the .proto files for the well-known // types. Do not edit! + +ZEND_BEGIN_ARG_INFO_EX(arginfo_lookup, 0, 0, 1) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + static void google_protobuf_any_proto_AddDescriptor(); static void google_protobuf_api_proto_AddDescriptor(); static void google_protobuf_duration_proto_AddDescriptor(); @@ -65,7 +70,7 @@ static PHP_METHOD(google_protobuf_Any, getTypeUrl) { "type_url"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Any, setTypeUrl) { @@ -78,7 +83,7 @@ static PHP_METHOD(google_protobuf_Any, setTypeUrl) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Any, getValue) { @@ -87,7 +92,7 @@ static PHP_METHOD(google_protobuf_Any, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Any, setValue) { @@ -100,7 +105,7 @@ static PHP_METHOD(google_protobuf_Any, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } ZEND_BEGIN_ARG_INFO_EX(arginfo_is, 0, 0, 1) @@ -108,7 +113,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_is, 0, 0, 1) ZEND_END_ARG_INFO() static zend_function_entry google_protobuf_Any_phpmethods[] = { - PHP_ME(google_protobuf_Any, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Any, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Any, getTypeUrl, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Any, setTypeUrl, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Any, getValue, arginfo_void, ZEND_ACC_PUBLIC) @@ -210,7 +215,7 @@ static PHP_METHOD(google_protobuf_Api, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setName) { @@ -223,7 +228,7 @@ static PHP_METHOD(google_protobuf_Api, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Api, getMethods) { @@ -232,7 +237,7 @@ static PHP_METHOD(google_protobuf_Api, getMethods) { "methods"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setMethods) { @@ -245,7 +250,7 @@ static PHP_METHOD(google_protobuf_Api, setMethods) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Api, getOptions) { @@ -254,7 +259,7 @@ static PHP_METHOD(google_protobuf_Api, getOptions) { "options"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setOptions) { @@ -267,7 +272,7 @@ static PHP_METHOD(google_protobuf_Api, setOptions) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Api, getVersion) { @@ -276,7 +281,7 @@ static PHP_METHOD(google_protobuf_Api, getVersion) { "version"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setVersion) { @@ -289,7 +294,7 @@ static PHP_METHOD(google_protobuf_Api, setVersion) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Api, getSourceContext) { @@ -298,7 +303,7 @@ static PHP_METHOD(google_protobuf_Api, getSourceContext) { "source_context"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setSourceContext) { @@ -311,7 +316,7 @@ static PHP_METHOD(google_protobuf_Api, setSourceContext) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Api, getMixins) { @@ -320,7 +325,7 @@ static PHP_METHOD(google_protobuf_Api, getMixins) { "mixins"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setMixins) { @@ -333,7 +338,7 @@ static PHP_METHOD(google_protobuf_Api, setMixins) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Api, getSyntax) { @@ -342,7 +347,7 @@ static PHP_METHOD(google_protobuf_Api, getSyntax) { "syntax"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Api, setSyntax) { @@ -355,11 +360,11 @@ static PHP_METHOD(google_protobuf_Api, setSyntax) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Api_phpmethods[] = { - PHP_ME(google_protobuf_Api, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Api, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Api, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Api, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Api, getMethods, arginfo_void, ZEND_ACC_PUBLIC) @@ -404,7 +409,7 @@ static PHP_METHOD(google_protobuf_Method, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setName) { @@ -417,7 +422,7 @@ static PHP_METHOD(google_protobuf_Method, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Method, getRequestTypeUrl) { @@ -426,7 +431,7 @@ static PHP_METHOD(google_protobuf_Method, getRequestTypeUrl) { "request_type_url"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setRequestTypeUrl) { @@ -439,7 +444,7 @@ static PHP_METHOD(google_protobuf_Method, setRequestTypeUrl) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Method, getRequestStreaming) { @@ -448,7 +453,7 @@ static PHP_METHOD(google_protobuf_Method, getRequestStreaming) { "request_streaming"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setRequestStreaming) { @@ -461,7 +466,7 @@ static PHP_METHOD(google_protobuf_Method, setRequestStreaming) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Method, getResponseTypeUrl) { @@ -470,7 +475,7 @@ static PHP_METHOD(google_protobuf_Method, getResponseTypeUrl) { "response_type_url"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setResponseTypeUrl) { @@ -483,7 +488,7 @@ static PHP_METHOD(google_protobuf_Method, setResponseTypeUrl) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Method, getResponseStreaming) { @@ -492,7 +497,7 @@ static PHP_METHOD(google_protobuf_Method, getResponseStreaming) { "response_streaming"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setResponseStreaming) { @@ -505,7 +510,7 @@ static PHP_METHOD(google_protobuf_Method, setResponseStreaming) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Method, getOptions) { @@ -514,7 +519,7 @@ static PHP_METHOD(google_protobuf_Method, getOptions) { "options"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setOptions) { @@ -527,7 +532,7 @@ static PHP_METHOD(google_protobuf_Method, setOptions) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Method, getSyntax) { @@ -536,7 +541,7 @@ static PHP_METHOD(google_protobuf_Method, getSyntax) { "syntax"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Method, setSyntax) { @@ -549,11 +554,11 @@ static PHP_METHOD(google_protobuf_Method, setSyntax) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Method_phpmethods[] = { - PHP_ME(google_protobuf_Method, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Method, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Method, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Method, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Method, getRequestTypeUrl, arginfo_void, ZEND_ACC_PUBLIC) @@ -598,7 +603,7 @@ static PHP_METHOD(google_protobuf_Mixin, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Mixin, setName) { @@ -611,7 +616,7 @@ static PHP_METHOD(google_protobuf_Mixin, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Mixin, getRoot) { @@ -620,7 +625,7 @@ static PHP_METHOD(google_protobuf_Mixin, getRoot) { "root"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Mixin, setRoot) { @@ -633,11 +638,11 @@ static PHP_METHOD(google_protobuf_Mixin, setRoot) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Mixin_phpmethods[] = { - PHP_ME(google_protobuf_Mixin, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Mixin, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Mixin, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Mixin, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Mixin, getRoot, arginfo_void, ZEND_ACC_PUBLIC) @@ -713,7 +718,7 @@ static PHP_METHOD(google_protobuf_Duration, getSeconds) { "seconds"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Duration, setSeconds) { @@ -726,7 +731,7 @@ static PHP_METHOD(google_protobuf_Duration, setSeconds) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Duration, getNanos) { @@ -735,7 +740,7 @@ static PHP_METHOD(google_protobuf_Duration, getNanos) { "nanos"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Duration, setNanos) { @@ -748,11 +753,11 @@ static PHP_METHOD(google_protobuf_Duration, setNanos) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Duration_phpmethods[] = { - PHP_ME(google_protobuf_Duration, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Duration, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Duration, getSeconds, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Duration, setSeconds, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Duration, getNanos, arginfo_void, ZEND_ACC_PUBLIC) @@ -821,7 +826,7 @@ static PHP_METHOD(google_protobuf_Empty, __construct) { } static zend_function_entry google_protobuf_Empty_phpmethods[] = { - PHP_ME(google_protobuf_Empty, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Empty, __construct, arginfo_construct, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -892,7 +897,7 @@ static PHP_METHOD(google_protobuf_FieldMask, getPaths) { "paths"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_FieldMask, setPaths) { @@ -905,11 +910,11 @@ static PHP_METHOD(google_protobuf_FieldMask, setPaths) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_FieldMask_phpmethods[] = { - PHP_ME(google_protobuf_FieldMask, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_FieldMask, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_FieldMask, getPaths, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_FieldMask, setPaths, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -983,7 +988,7 @@ static PHP_METHOD(google_protobuf_SourceContext, getFileName) { "file_name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_SourceContext, setFileName) { @@ -996,11 +1001,11 @@ static PHP_METHOD(google_protobuf_SourceContext, setFileName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_SourceContext_phpmethods[] = { - PHP_ME(google_protobuf_SourceContext, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_SourceContext, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_SourceContext, getFileName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_SourceContext, setFileName, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -1090,7 +1095,7 @@ static PHP_METHOD(google_protobuf_Struct, getFields) { "fields"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Struct, setFields) { @@ -1103,11 +1108,11 @@ static PHP_METHOD(google_protobuf_Struct, setFields) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Struct_phpmethods[] = { - PHP_ME(google_protobuf_Struct, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Struct, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Struct, getFields, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Struct, setFields, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -1140,7 +1145,7 @@ static PHP_METHOD(google_protobuf_Struct_FieldsEntry, getKey) { "key"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Struct_FieldsEntry, setKey) { @@ -1153,7 +1158,7 @@ static PHP_METHOD(google_protobuf_Struct_FieldsEntry, setKey) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Struct_FieldsEntry, getValue) { @@ -1162,7 +1167,7 @@ static PHP_METHOD(google_protobuf_Struct_FieldsEntry, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Struct_FieldsEntry, setValue) { @@ -1175,11 +1180,11 @@ static PHP_METHOD(google_protobuf_Struct_FieldsEntry, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Struct_FieldsEntry_phpmethods[] = { - PHP_ME(google_protobuf_Struct_FieldsEntry, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Struct_FieldsEntry, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Struct_FieldsEntry, getKey, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Struct_FieldsEntry, setKey, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Struct_FieldsEntry, getValue, arginfo_void, ZEND_ACC_PUBLIC) @@ -1214,7 +1219,7 @@ static PHP_METHOD(google_protobuf_Value, getNullValue) { "null_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Value, setNullValue) { @@ -1227,7 +1232,7 @@ static PHP_METHOD(google_protobuf_Value, setNullValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Value, getNumberValue) { @@ -1236,7 +1241,7 @@ static PHP_METHOD(google_protobuf_Value, getNumberValue) { "number_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Value, setNumberValue) { @@ -1249,7 +1254,7 @@ static PHP_METHOD(google_protobuf_Value, setNumberValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Value, getStringValue) { @@ -1258,7 +1263,7 @@ static PHP_METHOD(google_protobuf_Value, getStringValue) { "string_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Value, setStringValue) { @@ -1271,7 +1276,7 @@ static PHP_METHOD(google_protobuf_Value, setStringValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Value, getBoolValue) { @@ -1280,7 +1285,7 @@ static PHP_METHOD(google_protobuf_Value, getBoolValue) { "bool_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Value, setBoolValue) { @@ -1293,7 +1298,7 @@ static PHP_METHOD(google_protobuf_Value, setBoolValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Value, getStructValue) { @@ -1302,7 +1307,7 @@ static PHP_METHOD(google_protobuf_Value, getStructValue) { "struct_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Value, setStructValue) { @@ -1315,7 +1320,7 @@ static PHP_METHOD(google_protobuf_Value, setStructValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Value, getListValue) { @@ -1324,7 +1329,7 @@ static PHP_METHOD(google_protobuf_Value, getListValue) { "list_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Value, setListValue) { @@ -1337,7 +1342,7 @@ static PHP_METHOD(google_protobuf_Value, setListValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Value, getKind) { @@ -1348,7 +1353,7 @@ static PHP_METHOD(google_protobuf_Value, getKind) { RETURN_STRING(field ? upb_fielddef_name(field) : ""); } static zend_function_entry google_protobuf_Value_phpmethods[] = { - PHP_ME(google_protobuf_Value, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Value, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Value, getNullValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Value, setNullValue, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Value, getNumberValue, arginfo_void, ZEND_ACC_PUBLIC) @@ -1392,7 +1397,7 @@ static PHP_METHOD(google_protobuf_ListValue, getValues) { "values"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_ListValue, setValues) { @@ -1405,11 +1410,11 @@ static PHP_METHOD(google_protobuf_ListValue, setValues) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_ListValue_phpmethods[] = { - PHP_ME(google_protobuf_ListValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_ListValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_ListValue, getValues, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_ListValue, setValues, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -1474,8 +1479,8 @@ PHP_METHOD(google_protobuf_NullValue, value) { } static zend_function_entry google_protobuf_NullValue_phpmethods[] = { - PHP_ME(google_protobuf_NullValue, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(google_protobuf_NullValue, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_NullValue, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_NullValue, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) ZEND_FE_END }; @@ -1602,7 +1607,7 @@ static PHP_METHOD(google_protobuf_Type, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Type, setName) { @@ -1615,7 +1620,7 @@ static PHP_METHOD(google_protobuf_Type, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Type, getFields) { @@ -1624,7 +1629,7 @@ static PHP_METHOD(google_protobuf_Type, getFields) { "fields"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Type, setFields) { @@ -1637,7 +1642,7 @@ static PHP_METHOD(google_protobuf_Type, setFields) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Type, getOneofs) { @@ -1646,7 +1651,7 @@ static PHP_METHOD(google_protobuf_Type, getOneofs) { "oneofs"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Type, setOneofs) { @@ -1659,7 +1664,7 @@ static PHP_METHOD(google_protobuf_Type, setOneofs) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Type, getOptions) { @@ -1668,7 +1673,7 @@ static PHP_METHOD(google_protobuf_Type, getOptions) { "options"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Type, setOptions) { @@ -1681,7 +1686,7 @@ static PHP_METHOD(google_protobuf_Type, setOptions) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Type, getSourceContext) { @@ -1690,7 +1695,7 @@ static PHP_METHOD(google_protobuf_Type, getSourceContext) { "source_context"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Type, setSourceContext) { @@ -1703,7 +1708,7 @@ static PHP_METHOD(google_protobuf_Type, setSourceContext) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Type, getSyntax) { @@ -1712,7 +1717,7 @@ static PHP_METHOD(google_protobuf_Type, getSyntax) { "syntax"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Type, setSyntax) { @@ -1725,11 +1730,11 @@ static PHP_METHOD(google_protobuf_Type, setSyntax) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Type_phpmethods[] = { - PHP_ME(google_protobuf_Type, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Type, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Type, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Type, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Type, getFields, arginfo_void, ZEND_ACC_PUBLIC) @@ -1772,7 +1777,7 @@ static PHP_METHOD(google_protobuf_Field, getKind) { "kind"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setKind) { @@ -1785,7 +1790,7 @@ static PHP_METHOD(google_protobuf_Field, setKind) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getCardinality) { @@ -1794,7 +1799,7 @@ static PHP_METHOD(google_protobuf_Field, getCardinality) { "cardinality"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setCardinality) { @@ -1807,7 +1812,7 @@ static PHP_METHOD(google_protobuf_Field, setCardinality) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getNumber) { @@ -1816,7 +1821,7 @@ static PHP_METHOD(google_protobuf_Field, getNumber) { "number"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setNumber) { @@ -1829,7 +1834,7 @@ static PHP_METHOD(google_protobuf_Field, setNumber) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getName) { @@ -1838,7 +1843,7 @@ static PHP_METHOD(google_protobuf_Field, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setName) { @@ -1851,7 +1856,7 @@ static PHP_METHOD(google_protobuf_Field, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getTypeUrl) { @@ -1860,7 +1865,7 @@ static PHP_METHOD(google_protobuf_Field, getTypeUrl) { "type_url"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setTypeUrl) { @@ -1873,7 +1878,7 @@ static PHP_METHOD(google_protobuf_Field, setTypeUrl) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getOneofIndex) { @@ -1882,7 +1887,7 @@ static PHP_METHOD(google_protobuf_Field, getOneofIndex) { "oneof_index"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setOneofIndex) { @@ -1895,7 +1900,7 @@ static PHP_METHOD(google_protobuf_Field, setOneofIndex) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getPacked) { @@ -1904,7 +1909,7 @@ static PHP_METHOD(google_protobuf_Field, getPacked) { "packed"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setPacked) { @@ -1917,7 +1922,7 @@ static PHP_METHOD(google_protobuf_Field, setPacked) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getOptions) { @@ -1926,7 +1931,7 @@ static PHP_METHOD(google_protobuf_Field, getOptions) { "options"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setOptions) { @@ -1939,7 +1944,7 @@ static PHP_METHOD(google_protobuf_Field, setOptions) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getJsonName) { @@ -1948,7 +1953,7 @@ static PHP_METHOD(google_protobuf_Field, getJsonName) { "json_name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setJsonName) { @@ -1961,7 +1966,7 @@ static PHP_METHOD(google_protobuf_Field, setJsonName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Field, getDefaultValue) { @@ -1970,7 +1975,7 @@ static PHP_METHOD(google_protobuf_Field, getDefaultValue) { "default_value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Field, setDefaultValue) { @@ -1983,11 +1988,11 @@ static PHP_METHOD(google_protobuf_Field, setDefaultValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Field_phpmethods[] = { - PHP_ME(google_protobuf_Field, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Field, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Field, getKind, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Field, setKind, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Field, getCardinality, arginfo_void, ZEND_ACC_PUBLIC) @@ -2070,8 +2075,8 @@ PHP_METHOD(google_protobuf_Field_Kind, value) { } static zend_function_entry google_protobuf_Field_Kind_phpmethods[] = { - PHP_ME(google_protobuf_Field_Kind, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(google_protobuf_Field_Kind, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_Field_Kind, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_Field_Kind, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) ZEND_FE_END }; @@ -2169,8 +2174,8 @@ PHP_METHOD(google_protobuf_Field_Cardinality, value) { } static zend_function_entry google_protobuf_Field_Cardinality_phpmethods[] = { - PHP_ME(google_protobuf_Field_Cardinality, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(google_protobuf_Field_Cardinality, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_Field_Cardinality, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_Field_Cardinality, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) ZEND_FE_END }; @@ -2206,7 +2211,7 @@ static PHP_METHOD(google_protobuf_Enum, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Enum, setName) { @@ -2219,7 +2224,7 @@ static PHP_METHOD(google_protobuf_Enum, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Enum, getEnumvalue) { @@ -2228,7 +2233,7 @@ static PHP_METHOD(google_protobuf_Enum, getEnumvalue) { "enumvalue"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Enum, setEnumvalue) { @@ -2241,7 +2246,7 @@ static PHP_METHOD(google_protobuf_Enum, setEnumvalue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Enum, getOptions) { @@ -2250,7 +2255,7 @@ static PHP_METHOD(google_protobuf_Enum, getOptions) { "options"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Enum, setOptions) { @@ -2263,7 +2268,7 @@ static PHP_METHOD(google_protobuf_Enum, setOptions) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Enum, getSourceContext) { @@ -2272,7 +2277,7 @@ static PHP_METHOD(google_protobuf_Enum, getSourceContext) { "source_context"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Enum, setSourceContext) { @@ -2285,7 +2290,7 @@ static PHP_METHOD(google_protobuf_Enum, setSourceContext) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Enum, getSyntax) { @@ -2294,7 +2299,7 @@ static PHP_METHOD(google_protobuf_Enum, getSyntax) { "syntax"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Enum, setSyntax) { @@ -2307,11 +2312,11 @@ static PHP_METHOD(google_protobuf_Enum, setSyntax) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Enum_phpmethods[] = { - PHP_ME(google_protobuf_Enum, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Enum, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Enum, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Enum, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Enum, getEnumvalue, arginfo_void, ZEND_ACC_PUBLIC) @@ -2352,7 +2357,7 @@ static PHP_METHOD(google_protobuf_EnumValue, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_EnumValue, setName) { @@ -2365,7 +2370,7 @@ static PHP_METHOD(google_protobuf_EnumValue, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_EnumValue, getNumber) { @@ -2374,7 +2379,7 @@ static PHP_METHOD(google_protobuf_EnumValue, getNumber) { "number"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_EnumValue, setNumber) { @@ -2387,7 +2392,7 @@ static PHP_METHOD(google_protobuf_EnumValue, setNumber) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_EnumValue, getOptions) { @@ -2396,7 +2401,7 @@ static PHP_METHOD(google_protobuf_EnumValue, getOptions) { "options"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_EnumValue, setOptions) { @@ -2409,11 +2414,11 @@ static PHP_METHOD(google_protobuf_EnumValue, setOptions) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_EnumValue_phpmethods[] = { - PHP_ME(google_protobuf_EnumValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_EnumValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_EnumValue, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_EnumValue, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_EnumValue, getNumber, arginfo_void, ZEND_ACC_PUBLIC) @@ -2450,7 +2455,7 @@ static PHP_METHOD(google_protobuf_Option, getName) { "name"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Option, setName) { @@ -2463,7 +2468,7 @@ static PHP_METHOD(google_protobuf_Option, setName) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Option, getValue) { @@ -2472,7 +2477,7 @@ static PHP_METHOD(google_protobuf_Option, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Option, setValue) { @@ -2485,11 +2490,11 @@ static PHP_METHOD(google_protobuf_Option, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Option_phpmethods[] = { - PHP_ME(google_protobuf_Option, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Option, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Option, getName, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Option, setName, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Option, getValue, arginfo_void, ZEND_ACC_PUBLIC) @@ -2556,8 +2561,8 @@ PHP_METHOD(google_protobuf_Syntax, value) { } static zend_function_entry google_protobuf_Syntax_phpmethods[] = { - PHP_ME(google_protobuf_Syntax, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(google_protobuf_Syntax, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_Syntax, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(google_protobuf_Syntax, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) ZEND_FE_END }; @@ -2630,7 +2635,7 @@ static PHP_METHOD(google_protobuf_Timestamp, getSeconds) { "seconds"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Timestamp, setSeconds) { @@ -2643,7 +2648,7 @@ static PHP_METHOD(google_protobuf_Timestamp, setSeconds) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static PHP_METHOD(google_protobuf_Timestamp, getNanos) { @@ -2652,7 +2657,7 @@ static PHP_METHOD(google_protobuf_Timestamp, getNanos) { "nanos"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Timestamp, setNanos) { @@ -2665,7 +2670,7 @@ static PHP_METHOD(google_protobuf_Timestamp, setNanos) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } ZEND_BEGIN_ARG_INFO_EX(arginfo_timestamp_fromdatetime, 0, 0, 1) @@ -2673,7 +2678,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timestamp_fromdatetime, 0, 0, 1) ZEND_END_ARG_INFO() static zend_function_entry google_protobuf_Timestamp_phpmethods[] = { - PHP_ME(google_protobuf_Timestamp, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Timestamp, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Timestamp, getSeconds, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Timestamp, setSeconds, arginfo_setter, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Timestamp, getNanos, arginfo_void, ZEND_ACC_PUBLIC) @@ -2760,7 +2765,7 @@ static PHP_METHOD(google_protobuf_DoubleValue, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_DoubleValue, setValue) { @@ -2773,11 +2778,11 @@ static PHP_METHOD(google_protobuf_DoubleValue, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_DoubleValue_phpmethods[] = { - PHP_ME(google_protobuf_DoubleValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_DoubleValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_DoubleValue, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_DoubleValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -2810,7 +2815,7 @@ static PHP_METHOD(google_protobuf_FloatValue, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_FloatValue, setValue) { @@ -2823,11 +2828,11 @@ static PHP_METHOD(google_protobuf_FloatValue, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_FloatValue_phpmethods[] = { - PHP_ME(google_protobuf_FloatValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_FloatValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_FloatValue, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_FloatValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -2860,7 +2865,7 @@ static PHP_METHOD(google_protobuf_Int64Value, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Int64Value, setValue) { @@ -2873,11 +2878,11 @@ static PHP_METHOD(google_protobuf_Int64Value, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Int64Value_phpmethods[] = { - PHP_ME(google_protobuf_Int64Value, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Int64Value, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Int64Value, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Int64Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -2910,7 +2915,7 @@ static PHP_METHOD(google_protobuf_UInt64Value, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_UInt64Value, setValue) { @@ -2923,11 +2928,11 @@ static PHP_METHOD(google_protobuf_UInt64Value, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_UInt64Value_phpmethods[] = { - PHP_ME(google_protobuf_UInt64Value, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_UInt64Value, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_UInt64Value, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_UInt64Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -2960,7 +2965,7 @@ static PHP_METHOD(google_protobuf_Int32Value, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_Int32Value, setValue) { @@ -2973,11 +2978,11 @@ static PHP_METHOD(google_protobuf_Int32Value, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_Int32Value_phpmethods[] = { - PHP_ME(google_protobuf_Int32Value, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_Int32Value, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Int32Value, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_Int32Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -3010,7 +3015,7 @@ static PHP_METHOD(google_protobuf_UInt32Value, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_UInt32Value, setValue) { @@ -3023,11 +3028,11 @@ static PHP_METHOD(google_protobuf_UInt32Value, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_UInt32Value_phpmethods[] = { - PHP_ME(google_protobuf_UInt32Value, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_UInt32Value, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_UInt32Value, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_UInt32Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -3060,7 +3065,7 @@ static PHP_METHOD(google_protobuf_BoolValue, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_BoolValue, setValue) { @@ -3073,11 +3078,11 @@ static PHP_METHOD(google_protobuf_BoolValue, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_BoolValue_phpmethods[] = { - PHP_ME(google_protobuf_BoolValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_BoolValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_BoolValue, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_BoolValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -3110,7 +3115,7 @@ static PHP_METHOD(google_protobuf_StringValue, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_StringValue, setValue) { @@ -3123,11 +3128,11 @@ static PHP_METHOD(google_protobuf_StringValue, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_StringValue_phpmethods[] = { - PHP_ME(google_protobuf_StringValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_StringValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_StringValue, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_StringValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -3160,7 +3165,7 @@ static PHP_METHOD(google_protobuf_BytesValue, getValue) { "value"); zval ret; Message_get(intern, f, &ret); - RETURN_ZVAL(&ret, 1, 0); + RETURN_COPY_VALUE(&ret); } static PHP_METHOD(google_protobuf_BytesValue, setValue) { @@ -3173,11 +3178,11 @@ static PHP_METHOD(google_protobuf_BytesValue, setValue) { return; } Message_set(intern, f, val); - RETURN_ZVAL(getThis(), 1, 0); + RETURN_COPY(getThis()); } static zend_function_entry google_protobuf_BytesValue_phpmethods[] = { - PHP_ME(google_protobuf_BytesValue, __construct, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(google_protobuf_BytesValue, __construct, arginfo_construct, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_BytesValue, getValue, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(google_protobuf_BytesValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC) ZEND_FE_END diff --git a/php/generate_test_protos.sh b/php/generate_test_protos.sh index 0aa4bdbe4314..e86ca07a687c 100755 --- a/php/generate_test_protos.sh +++ b/php/generate_test_protos.sh @@ -4,7 +4,17 @@ set -e cd `dirname $0` -if [[ -d tmp && -z $(find tests/proto ../src/protoc -newer tmp) ]]; then +./prepare_c_extension.sh + +if ../src/protoc --help > /dev/null; then + PROTOC=src/protoc +else + (cd .. && bazel build -c opt :protoc) + PROTOC=bazel-bin/protoc +fi + + +if [[ -d tmp && -z $(find tests/proto ../$PROTOC -newer tmp) ]]; then # Generated protos are already present and up to date, so we can skip protoc. # # Protoc is very fast, but sometimes it is not available (like if we haven't @@ -16,12 +26,13 @@ fi rm -rf tmp mkdir -p tmp -find tests/proto -type f -name "*.proto"| xargs ../src/protoc --php_out=tmp -I../src -Itests +cd .. +find php/tests/proto -type f -name "*.proto"| xargs $PROTOC --php_out=php/tmp -Isrc -Iphp/tests if [ "$1" = "--aggregate_metadata" ]; then # Overwrite some of the files to use aggregation. AGGREGATED_FILES="tests/proto/test.proto tests/proto/test_include.proto tests/proto/test_import_descriptor_proto.proto" - ../src/protoc --php_out=aggregate_metadata=foo#bar:tmp -I../src -Itests $AGGREGATED_FILES + $PROTOC --php_out=aggregate_metadata=foo#bar:php/tmp -Isrc -Iphp/tests $AGGREGATED_FILES fi echo "Generated test protos from tests/proto -> tmp" diff --git a/php/prepare_c_extension.sh b/php/prepare_c_extension.sh index 84cd1aa3d155..1b6b9f1dae9d 100755 --- a/php/prepare_c_extension.sh +++ b/php/prepare_c_extension.sh @@ -1,6 +1,20 @@ +cd $(dirname $0) + +if [[ -f ext/google/protobuf/third_party/wyhash/wyhash.h && -z $(find ../third_party/wyhash -newer ext/google/protobuf/third_party) ]]; then + # Generated protos are already present and up to date, so we can skip protoc. + # + # Protoc is very fast, but sometimes it is not available (like if we haven't + # built it in Docker). Skipping it helps us proceed in this case. + echo "wyhash is up to date, skipping." + exit 0 +fi + # wyhash has to live in the base third_party directory. # We copy it into the ext/google/protobuf directory for the build # (and for the release to PECL). -mkdir -p ../ext/google/protobuf/third_party/wyhash -cp ../../third_party/wyhash/* ../ext/google/protobuf/third_party/wyhash +rm -rf ext/google/protobuf/third_party +mkdir -p ext/google/protobuf/third_party/wyhash +cp ../third_party/wyhash/* ext/google/protobuf/third_party/wyhash + +echo "Copied wyhash from ../third_party -> ext/google/protobuf/third_party" diff --git a/php/tests/ArrayTest.php b/php/tests/ArrayTest.php index 0585ca5b1c8f..b68708529932 100644 --- a/php/tests/ArrayTest.php +++ b/php/tests/ArrayTest.php @@ -577,6 +577,14 @@ public function testArrayElementIsReferenceInSetters() public function testCycleLeak() { + if (getenv("USE_ZEND_ALLOC") === "0") { + // If we are disabling Zend's internal allocator (as we do for + // Valgrind tests, for example) then memory_get_usage() will not + // return a useful value. + $this->markTestSkipped(); + return; + } + gc_collect_cycles(); $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); $arr[] = new TestMessage; diff --git a/php/tests/EncodeDecodeTest.php b/php/tests/EncodeDecodeTest.php index b7c1ab24ca2d..273010e2eda7 100644 --- a/php/tests/EncodeDecodeTest.php +++ b/php/tests/EncodeDecodeTest.php @@ -57,6 +57,7 @@ public function testDecodeJsonIgnoreUnknown() { $m = new TestMessage(); $m->mergeFromJsonString("{\"unknown\":1}", true); + $this->assertEquals("{}", $m->serializeToJsonString()); } public function testDecodeTopLevelBoolValue() diff --git a/php/tests/GeneratedClassTest.php b/php/tests/GeneratedClassTest.php index 87593912872e..5c0f0c70d0ee 100644 --- a/php/tests/GeneratedClassTest.php +++ b/php/tests/GeneratedClassTest.php @@ -1755,9 +1755,18 @@ public function testHasOneof() { ######################################################### public function testUserDefinedClass() { - # This is not allowed, but at least we shouldn't crash. - $this->expectException(Exception::class); - $p = new C(); + if (getenv("USE_ZEND_ALLOC") === "0") { + // We're running a memory test. This test appears to leak in a way + // we cannot control, PHP bug? + // + // TODO: investigate further. + $this->markTestSkipped(); + return; + } + + # This is not allowed, but at least we shouldn't crash. + $this->expectException(Exception::class); + new C(); } ######################################################### @@ -1768,9 +1777,16 @@ function throwIntendedException() { throw new Exception('Intended'); } - public function testNoSegfaultWithError() { + if (getenv("USE_ZEND_ALLOC") === "0") { + // We're running a memory test. This test appears to leak in a way + // we cannot control, PHP bug? + // + // TODO: investigate further. + $this->markTestSkipped(); + return; + } $this->expectException(Exception::class); new TestMessage(['optional_int32' => $this->throwIntendedException()]); diff --git a/php/tests/compile_extension.sh b/php/tests/compile_extension.sh index d26fcb472ee9..fce046952600 100755 --- a/php/tests/compile_extension.sh +++ b/php/tests/compile_extension.sh @@ -10,16 +10,19 @@ pushd ../ext/google/protobuf > /dev/null CONFIGURE_OPTIONS=("./configure" "--with-php-config=$(which php-config)") if [ "$1" != "--release" ]; then - CONFIGURE_OPTIONS+=("CFLAGS=-g -O0 -Wall") + CONFIGURE_OPTIONS+=("CFLAGS=-g -O0 -Wall -DPBPHP_ENABLE_ASSERTS") fi +FINGERPRINT="$(sha256sum $(which php)) ${CONFIGURE_OPTIONS[@]}" + # If the PHP interpreter we are building against or the arguments # have changed, we must regenerated the Makefile. -if [[ ! -f Makefile ]] || [[ "$(grep ' \$ ./configure' config.log)" != " $ ${CONFIGURE_OPTIONS[@]}" ]]; then +if [[ ! -f BUILD_STAMP ]] || [[ "$(cat BUILD_STAMP)" != "$FINGERPRINT" ]]; then phpize --clean rm -f configure.in configure.ac phpize "${CONFIGURE_OPTIONS[@]}" + echo "$FINGERPRINT" > BUILD_STAMP fi make diff --git a/ruby/Rakefile b/ruby/Rakefile index 11397b0eb94f..221e9b507f52 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -18,6 +18,18 @@ well_known_protos = %w[ google/protobuf/wrappers.proto ] +test_protos = %w[ + tests/basic_test.proto + tests/basic_test_proto2.proto + tests/generated_code.proto + tests/generated_code_proto2.proto + tests/multi_level_nesting_test.proto + tests/test_import.proto + tests/test_import_proto2.proto + tests/test_ruby_package.proto + tests/test_ruby_package_proto2.proto +] + # These are omitted for now because we don't support proto2. proto2_protos = %w[ google/protobuf/descriptor.proto @@ -43,6 +55,14 @@ unless ENV['IN_DOCKER'] == 'true' sh "#{protoc_command} -I../src --ruby_out=lib #{input_file}" end end + + test_protos.each do |proto_file| + output_file = proto_file.sub(/\.proto$/, "_pb.rb") + genproto_output << output_file + file output_file => proto_file do |file_task| + sh "#{protoc_command} -I../src -I. --ruby_out=. #{proto_file}" + end + end end if RUBY_PLATFORM == "java" @@ -100,59 +120,6 @@ else end end - -# Proto for tests. -genproto_output << "tests/generated_code.rb" -genproto_output << "tests/generated_code_proto2.rb" -genproto_output << "tests/test_import.rb" -genproto_output << "tests/test_import_proto2.rb" -genproto_output << "tests/test_ruby_package.rb" -genproto_output << "tests/test_ruby_package_proto2.rb" -genproto_output << "tests/basic_test.rb" -genproto_output << "tests/basic_test_proto2.rb" -genproto_output << "tests/multi_level_nesting_test.rb" -genproto_output << "tests/wrappers.rb" - -file "tests/generated_code.rb" => "tests/generated_code.proto" do |file_task| - sh "#{protoc_command} --ruby_out=. tests/generated_code.proto" -end - -file "tests/generated_code_proto2.rb" => "tests/generated_code_proto2.proto" do |file_task| - sh "#{protoc_command} --ruby_out=. tests/generated_code_proto2.proto" -end - -file "tests/test_import.rb" => "tests/test_import.proto" do |file_task| - sh "#{protoc_command} --ruby_out=. tests/test_import.proto" -end - -file "tests/test_import_proto2.rb" => "tests/test_import_proto2.proto" do |file_task| - sh "#{protoc_command} --ruby_out=. tests/test_import_proto2.proto" -end - -file "tests/test_ruby_package.rb" => "tests/test_ruby_package.proto" do |file_task| - sh "#{protoc_command} --ruby_out=. tests/test_ruby_package.proto" -end - -file "tests/test_ruby_package_proto2.rb" => "tests/test_ruby_package_proto2.proto" do |file_task| - sh "#{protoc_command} --ruby_out=. tests/test_ruby_package_proto2.proto" -end - -file "tests/basic_test.rb" => "tests/basic_test.proto" do |file_task| - sh "#{protoc_command} --experimental_allow_proto3_optional -I../src -I. --ruby_out=. tests/basic_test.proto" -end - -file "tests/basic_test_proto2.rb" => "tests/basic_test_proto2.proto" do |file_task| - sh "#{protoc_command} -I../src -I. --ruby_out=. tests/basic_test_proto2.proto" -end - -file "tests/multi_level_nesting_test.rb" => "tests/multi_level_nesting_test.proto" do |file_task| - sh "#{protoc_command} -I../src -I. --ruby_out=. tests/multi_level_nesting_test.proto" -end - -file "tests/wrappers.rb" => "../src/google/protobuf/wrappers.proto" do |file_task| - sh "#{protoc_command} -I../src -I. --ruby_out=tests ../src/google/protobuf/wrappers.proto" -end - task :genproto => genproto_output task :clean do @@ -162,7 +129,7 @@ end Gem::PackageTask.new(spec) do |pkg| end -Rake::TestTask.new(:test => :build) do |t| +Rake::TestTask.new(:test => [:build, :genproto]) do |t| t.test_files = FileList["tests/*.rb"].exclude("tests/gc_test.rb", "tests/common_tests.rb") end @@ -172,7 +139,7 @@ Rake::TestTask.new(:gc_test => :build) do |t| t.test_files = FileList["tests/gc_test.rb"] end -task :build => [:clean, :compile, :genproto] +task :build => [:clean, :genproto, :compile] task :default => [:build] # vim:sw=2:et diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index ffdae6a4017f..c1b9b8633032 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -794,6 +794,14 @@ static VALUE Message_CreateHash(const upb_msg *msg, const upb_msgdef *m) { VALUE msg_value; VALUE msg_key; + if (!is_proto2 && upb_fielddef_issubmsg(field) && + !upb_fielddef_isseq(field) && !upb_msg_has(msg, field)) { + // TODO: Legacy behavior, remove when we fix the is_proto2 differences. + msg_key = ID2SYM(rb_intern(upb_fielddef_name(field))); + rb_hash_aset(hash, msg_key, Qnil); + continue; + } + // Do not include fields that are not present (oneof or optional fields). if (is_proto2 && upb_fielddef_haspresence(field) && !upb_msg_has(msg, field)) { diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 61762fcd9904..b1b701b4eef5 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -1,27 +1,54 @@ /* Amalgamated source file */ #include "ruby-upb.h" /* -* This is where we define macros used across upb. -* -* All of these macros are undef'd in port_undef.inc to avoid leaking them to -* users. -* -* The correct usage is: -* -* #include "upb/foobar.h" -* #include "upb/baz.h" -* -* // MUST be last included header. -* #include "upb/port_def.inc" -* -* // Code for this file. -* // <...> -* -* // Can be omitted for .c files, required for .h. -* #include "upb/port_undef.inc" -* -* This file is private and must not be included by users! -*/ + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is where we define macros used across upb. + * + * All of these macros are undef'd in port_undef.inc to avoid leaking them to + * users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port_def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port_undef.inc" + * + * This file is private and must not be included by users! + */ #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (defined(__cplusplus) && __cplusplus >= 201103L) || \ @@ -137,9 +164,40 @@ #define UPB_LONGJMP(buf, val) longjmp(buf, val) #endif +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + /* Configure whether fasttable is switched on or not. *************************/ -#if defined(__x86_64__) && defined(__GNUC__) +#ifdef __has_attribute +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#undef UPB_HAS_ATTRIBUTE + +/* This check is not fully robust: it does not require that we have "musttail" + * support available. We need tail calls to avoid consuming arbitrary amounts + * of stack space. + * + * GCC/Clang can mostly be trusted to generate tail calls as long as + * optimization is enabled, but, debug builds will not generate tail calls + * unless "musttail" is available. + * + * We should probably either: + * 1. require that the compiler supports musttail. + * 2. add some fallback code for when musttail isn't available (ie. return + * instead of tail calling). This is safe and portable, but this comes at + * a CPU cost. + */ +#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) #define UPB_FASTTABLE_SUPPORTED 1 #else #define UPB_FASTTABLE_SUPPORTED 0 @@ -150,7 +208,7 @@ * for example for testing or benchmarking. */ #if defined(UPB_ENABLE_FASTTABLE) #if !UPB_FASTTABLE_SUPPORTED -#error fasttable is x86-64 + Clang/GCC only +#error fasttable is x86-64/ARM64 only and requires GCC or Clang. #endif #define UPB_FASTTABLE 1 /* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. @@ -194,8 +252,9 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) -#endif +#endif +/** upb/decode.c ************************************************************/ #include #include @@ -891,7 +950,7 @@ bool _upb_decode(const char *buf, size_t size, void *msg, state.end_group = DECODE_NOGROUP; state.arena.head = arena->head; state.arena.last_size = arena->last_size; - state.arena.cleanups = arena->cleanups; + state.arena.cleanup_metadata = arena->cleanup_metadata; state.arena.parent = arena; if (UPB_UNLIKELY(UPB_SETJMP(state.err))) { @@ -902,7 +961,7 @@ bool _upb_decode(const char *buf, size_t size, void *msg, arena->head.ptr = state.arena.head.ptr; arena->head.end = state.arena.head.end; - arena->cleanups = state.arena.cleanups; + arena->cleanup_metadata = state.arena.cleanup_metadata; return ok; } @@ -911,6 +970,8 @@ bool _upb_decode(const char *buf, size_t size, void *msg, #undef OP_VARPCK_LG2 #undef OP_STRING #undef OP_SUBMSG + +/** upb/encode.c ************************************************************/ /* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ @@ -1386,7 +1447,7 @@ char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options, return ret; } - +/** upb/msg.c ************************************************************/ /** upb_msg *******************************************************************/ @@ -1517,7 +1578,7 @@ upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) { return NULL; } - upb_strtable_init2(&map->table, UPB_CTYPE_INT32, 4, upb_arena_alloc(a)); + upb_strtable_init(&map->table, 4, a); map->key_size = key_size; map->val_size = value_size; @@ -1638,11 +1699,13 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type, qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); return true; } + +/** upb/table.c ************************************************************/ /* -** upb_table Implementation -** -** Implementation is heavily inspired by Lua's ltable.c. -*/ + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ #include @@ -1663,9 +1726,15 @@ static const double MAX_LOAD = 0.85; * cache effects). The lower this is, the more memory we'll use. */ static const double MIN_DENSITY = 0.1; -bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } -int log2ceil(uint64_t v) { +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; +} + +static int log2ceil(uint64_t v) { int ret = 0; bool pow2 = is_pow2(v); while (v >>= 1) ret++; @@ -1673,11 +1742,7 @@ int log2ceil(uint64_t v) { return UPB_MIN(UPB_MAXARRSIZE, ret); } -char *upb_strdup(const char *s, upb_alloc *a) { - return upb_strdup2(s, strlen(s), a); -} - -char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { +char *upb_strdup2(const char *s, size_t len, upb_arena *a) { size_t n; char *p; @@ -1686,7 +1751,7 @@ char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { /* Always null-terminate, even if binary data; but don't rely on the input to * have a null-terminating byte since it may be a raw binary buffer. */ n = len + 1; - p = upb_malloc(a, n); + p = upb_arena_malloc(a, n); if (p) { memcpy(p, s, len); p[len] = 0; @@ -1721,16 +1786,24 @@ typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); /* Base table (shared code) ***************************************************/ -/* For when we need to cast away const. */ -static upb_tabent *mutable_entries(upb_table *t) { - return (upb_tabent*)t->entries; +static uint32_t upb_inthash(uintptr_t key) { + return (uint32_t)key; +} + +static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { + return t->entries + (hash & t->mask); +} + +static bool upb_arrhas(upb_tabval key) { + return key.val != (uint64_t)-1; } + static bool isfull(upb_table *t) { return t->count == t->max_count; } -static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { +static bool init(upb_table *t, uint8_t size_lg2, upb_arena *a) { size_t bytes; t->count = 0; @@ -1739,21 +1812,17 @@ static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { t->max_count = upb_table_size(t) * MAX_LOAD; bytes = upb_table_size(t) * sizeof(upb_tabent); if (bytes > 0) { - t->entries = upb_malloc(a, bytes); + t->entries = upb_arena_malloc(a, bytes); if (!t->entries) return false; - memset(mutable_entries(t), 0, bytes); + memset(t->entries, 0, bytes); } else { t->entries = NULL; } return true; } -static void uninit(upb_table *t, upb_alloc *a) { - upb_free(a, mutable_entries(t)); -} - static upb_tabent *emptyent(upb_table *t, upb_tabent *e) { - upb_tabent *begin = mutable_entries(t); + upb_tabent *begin = t->entries; upb_tabent *end = begin + upb_table_size(t); for (e = e + 1; e < end; e++) { if (upb_tabent_isempty(e)) return e; @@ -1903,9 +1972,9 @@ static size_t begin(const upb_table *t) { /* A simple "subclass" of upb_table that only adds a hash function for strings. */ -static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) { +static upb_tabkey strcopy(lookupkey_t k2, upb_arena *a) { uint32_t len = (uint32_t) k2.str.len; - char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1); + char *str = upb_arena_malloc(a, k2.str.len + sizeof(uint32_t) + 1); if (str == NULL) return 0; memcpy(str, &len, sizeof(uint32_t)); if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); @@ -1929,9 +1998,7 @@ static bool streql(upb_tabkey k1, lookupkey_t k2) { return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, - size_t expected_size, upb_alloc *a) { - UPB_UNUSED(ctype); /* TODO(haberman): rm */ +bool upb_strtable_init(upb_strtable *t, size_t expected_size, upb_arena *a) { // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 denominator. size_t need_entries = (expected_size + 1) * 1204 / 1024; UPB_ASSERT(need_entries >= expected_size * 0.85); @@ -1945,14 +2012,7 @@ void upb_strtable_clear(upb_strtable *t) { memset((char*)t->t.entries, 0, bytes); } -void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) { - size_t i; - for (i = 0; i < upb_table_size(&t->t); i++) - upb_free(a, (void*)t->t.entries[i].key); - uninit(&t->t, a); -} - -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a) { upb_strtable new_table; upb_strtable_iter i; @@ -1961,17 +2021,15 @@ bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { upb_strtable_begin(&i, t); for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_strview key = upb_strtable_iter_key(&i); - upb_strtable_insert3( - &new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); + upb_strtable_insert(&new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); } - upb_strtable_uninit2(t, a); *t = new_table; return true; } -bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, - upb_value v, upb_alloc *a) { +bool upb_strtable_insert(upb_strtable *t, const char *k, size_t len, + upb_value v, upb_arena *a) { lookupkey_t key; upb_tabkey tabkey; uint32_t hash; @@ -1998,19 +2056,11 @@ bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, - upb_value *val, upb_alloc *alloc) { +bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len, + upb_value *val) { uint32_t hash = table_hash(key, len); upb_tabkey tabkey; - if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { - if (alloc) { - /* Arena-based allocs don't need to free and won't pass this. */ - upb_free(alloc, (void*)tabkey); - } - return true; - } else { - return false; - } + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } /* Iteration */ @@ -2108,7 +2158,7 @@ static void check(upb_inttable *t) { } bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, - upb_alloc *a) { + upb_arena *a) { size_t array_bytes; if (!init(&t->t, hsize_lg2, a)) return false; @@ -2117,9 +2167,8 @@ bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, t->array_size = UPB_MAX(1, asize); t->array_count = 0; array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_malloc(a, array_bytes); + t->array = upb_arena_malloc(a, array_bytes); if (!t->array) { - uninit(&t->t, a); return false; } memset(mutable_array(t), 0xff, array_bytes); @@ -2127,18 +2176,12 @@ bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, return true; } -bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) { - UPB_UNUSED(ctype); /* TODO(haberman): rm */ +bool upb_inttable_init(upb_inttable *t, upb_arena *a) { return upb_inttable_sizedinit(t, 0, 4, a); } -void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) { - uninit(&t->t, a); - upb_free(a, mutable_array(t)); -} - -bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, - upb_alloc *a) { +bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val, + upb_arena *a) { upb_tabval tabval; tabval.val = val.val; UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ @@ -2169,7 +2212,6 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, UPB_ASSERT(t->t.count == new_table.count); - uninit(&t->t, a); t->t = new_table; } insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); @@ -2213,21 +2255,7 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { return success; } -bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, - upb_alloc *a) { - return upb_inttable_insert2(t, (uintptr_t)key, val, a); -} - -bool upb_inttable_lookupptr(const upb_inttable *t, const void *key, - upb_value *v) { - return upb_inttable_lookup(t, (uintptr_t)key, v); -} - -bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { - return upb_inttable_remove(t, (uintptr_t)key, val); -} - -void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { +void upb_inttable_compact(upb_inttable *t, upb_arena *a) { /* A power-of-two histogram of the table keys. */ size_t counts[UPB_MAXARRSIZE + 1] = {0}; @@ -2275,12 +2303,11 @@ void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); } UPB_ASSERT(new_t.array_size == arr_size); UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } - upb_inttable_uninit2(t, a); *t = new_t; } @@ -2354,6 +2381,7 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, i1->array_part == i2->array_part; } +/** upb/upb.c ************************************************************/ #include #include @@ -2420,6 +2448,19 @@ static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, } } +static uint32_t *upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t *)(cleanup_metadata & ~0x1); +} + +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; +} + +static uintptr_t upb_cleanup_metadata(uint32_t *cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} + upb_alloc upb_alloc_global = {&upb_global_allocfunc}; /* upb_arena ******************************************************************/ @@ -2465,7 +2506,8 @@ static void upb_arena_addblock(upb_arena *a, upb_arena *root, void *ptr, a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); a->head.end = UPB_PTR_AT(block, size, char); - a->cleanups = &block->cleanups; + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); } @@ -2513,6 +2555,7 @@ upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) { a->refcount = 1; a->freelist = NULL; a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); upb_arena_addblock(a, a, mem, n); @@ -2540,7 +2583,7 @@ upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) { a->head.ptr = mem; a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); a->freelist = NULL; - a->cleanups = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); return a; } @@ -2575,15 +2618,17 @@ void upb_arena_free(upb_arena *a) { bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { cleanup_ent *ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); - if (!a->cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { + if (!cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { if (!upb_arena_allocblock(a, 128)) return false; /* Out of memory. */ UPB_ASSERT(_upb_arenahas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); } a->head.end -= sizeof(cleanup_ent); ent = (cleanup_ent*)a->head.end; - (*a->cleanups)++; + (*cleanups)++; UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); ent->cleanup = func; @@ -2592,11 +2637,18 @@ bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { return true; } -void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { +bool upb_arena_fuse(upb_arena *a1, upb_arena *a2) { upb_arena *r1 = arena_findroot(a1); upb_arena *r2 = arena_findroot(a2); - if (r1 == r2) return; /* Already fused. */ + if (r1 == r2) return true; /* Already fused. */ + + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; + + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; /* We want to join the smaller tree to the larger tree. * So swap first if they are backwards. */ @@ -2614,12 +2666,15 @@ void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { r1->freelist = r2->freelist; } r2->parent = r1; + return true; } -// Fast decoder: ~3x the speed of decode.c, but x86-64 specific. + +/** upb/decode_fast.c ************************************************************/ +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. // Also the table size grows by 2x. // -// Could potentially be ported to ARM64 or other 64-bit archs that pass at -// least six arguments in registers. +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. // // The overall design is to create specialized functions for every possible // field type (eg. oneof boolean field with a 1 byte tag) and then dispatch @@ -2639,8 +2694,10 @@ void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { #define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data -#define RETURN_GENERIC(m) \ - /* fprintf(stderr, m); */ \ +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ return fastdecode_generic(d, ptr, msg, table, hasbits, 0); typedef enum { @@ -2651,21 +2708,18 @@ typedef enum { } upb_card; UPB_NOINLINE -static const char *fastdecode_isdonefallback(upb_decstate *d, const char *ptr, - upb_msg *msg, intptr_t table, - uint64_t hasbits, int overrun) { +static const char *fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; ptr = decode_isdonefallback_inl(d, ptr, overrun); if (ptr == NULL) { return fastdecode_err(d); } - uint16_t tag = fastdecode_loadtag(ptr); - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag); + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); } UPB_FORCEINLINE -static const char *fastdecode_dispatch(upb_decstate *d, const char *ptr, - upb_msg *msg, intptr_t table, - uint64_t hasbits) { +static const char *fastdecode_dispatch(UPB_PARSE_PARAMS) { if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { int overrun = ptr - d->end; if (UPB_LIKELY(overrun == d->limit)) { @@ -2673,21 +2727,22 @@ static const char *fastdecode_dispatch(upb_decstate *d, const char *ptr, *(uint32_t*)msg |= hasbits; // Sync hasbits. return ptr; } else { - return fastdecode_isdonefallback(d, ptr, msg, table, hasbits, overrun); + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); } } // Read two bytes of tag data (for a one-byte tag, the high byte is junk). - uint16_t tag = fastdecode_loadtag(ptr); - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag); + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); } UPB_FORCEINLINE -static bool fastdecode_checktag(uint64_t data, int tagbytes) { +static bool fastdecode_checktag(uint16_t data, int tagbytes) { if (tagbytes == 1) { return (data & 0xff) == 0; } else { - return (data & 0xffff) == 0; + return data == 0; } } @@ -2911,6 +2966,14 @@ static bool fastdecode_flippacked(uint64_t *data, int tagbytes) { return fastdecode_checktag(*data, tagbytes); } +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ + } + /* varint fields **************************************************************/ UPB_FORCEINLINE @@ -2953,57 +3016,50 @@ static const char *fastdecode_varint64(const char *ptr, uint64_t *val) { return ptr; } -UPB_FORCEINLINE -static const char *fastdecode_unpackedvarint(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, - bool zigzag, - _upb_field_parser *packed) { - uint64_t val; - void *dst; - fastdecode_arr farr; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { - return packed(UPB_PARSE_ARGS); - } - RETURN_GENERIC("varint field tag mismatch\n"); - } - - dst = - fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card); - if (card == CARD_r) { - if (UPB_UNLIKELY(!dst)) { - RETURN_GENERIC("need array resize\n"); - } - } - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, valbytes); - } - - ptr += tagbytes; - ptr = fastdecode_varint64(ptr, &val); - if (ptr == NULL) return fastdecode_err(d); - val = fastdecode_munge(val, valbytes, zigzag); - memcpy(dst, &val, valbytes); - - if (card == CARD_r) { - fastdecode_nextret ret = - fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void *dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) \ + return fastdecode_err(d); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); typedef struct { uint8_t valbytes; @@ -3032,50 +3088,37 @@ static const char *fastdecode_topackedvarint(upb_decstate *d, const char *ptr, return ptr; } -UPB_FORCEINLINE -static const char *fastdecode_packedvarint(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, bool zigzag, - _upb_field_parser *unpacked) { - fastdecode_varintdata ctx = {valbytes, zigzag}; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (fastdecode_flippacked(&data, tagbytes)) { - return unpacked(UPB_PARSE_ARGS); - } else { - RETURN_GENERIC("varint field tag mismatch\n"); - } - } - - ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, - valbytes, CARD_r); - if (UPB_UNLIKELY(!ctx.dst)) { - RETURN_GENERIC("need array resize\n"); - } - - ptr += tagbytes; - ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); - - if (UPB_UNLIKELY(ptr == NULL)) { - return fastdecode_err(d); +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + return fastdecode_err(d); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); + +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ } - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, bool zigzag, - _upb_field_parser *unpacked, - _upb_field_parser *packed) { - if (card == CARD_p) { - return fastdecode_packedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, zigzag, - unpacked); - } else { - return fastdecode_unpackedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, card, - zigzag, packed); - } -} - #define z_ZZ true #define b_ZZ false #define v_ZZ false @@ -3086,10 +3129,10 @@ static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes, #define F(card, type, valbytes, tagbytes) \ UPB_NOINLINE \ const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_varint(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \ - type##_ZZ, \ - &upb_pr##type##valbytes##_##tagbytes##bt, \ - &upb_pp##type##valbytes##_##tagbytes##bt); \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ } #define TYPES(card, tagbytes) \ @@ -3117,126 +3160,110 @@ TAGBYTES(p) #undef F #undef TYPES #undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT /* fixed fields ***************************************************************/ -UPB_FORCEINLINE -static const char *fastdecode_unpackedfixed(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, - _upb_field_parser *packed) { - void *dst; - fastdecode_arr farr; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { - return packed(UPB_PARSE_ARGS); - } - RETURN_GENERIC("fixed field tag mismatch\n"); - } - - dst = - fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card); - if (card == CARD_r) { - if (UPB_UNLIKELY(!dst)) { - RETURN_GENERIC("couldn't allocate array in arena\n"); - } +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void *dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ + (size % valbytes) != 0)) { \ + return fastdecode_err(d); \ + } \ + \ + upb_array **arr_p = fastdecode_fieldmem(msg, data); \ + upb_array *arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + return fastdecode_err(d); \ + } \ + } else { \ + _upb_array_resize(arr, elems, &d->arena); \ + } \ + \ + char *dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->len = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ } - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, valbytes); - } - - ptr += tagbytes; - memcpy(dst, ptr, valbytes); - ptr += valbytes; - - if (card == CARD_r) { - fastdecode_nextret ret = - fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_packedfixed(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, - _upb_field_parser *unpacked) { - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - if (fastdecode_flippacked(&data, tagbytes)) { - return unpacked(UPB_PARSE_ARGS); - } else { - RETURN_GENERIC("varint field tag mismatch\n"); - } - } - - ptr += tagbytes; - int size = (uint8_t)ptr[0]; - ptr++; - if (size & 0x80) { - ptr = fastdecode_longsize(ptr, &size); - } - - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr)) || - (size % valbytes) != 0) { - return fastdecode_err(d); - } - - upb_array **arr_p = fastdecode_fieldmem(msg, data); - upb_array *arr = *arr_p; - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - int elems = size / valbytes; - - if (UPB_LIKELY(!arr)) { - *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2); - if (!arr) { - return fastdecode_err(d); - } - } else { - _upb_array_resize(arr, elems, &d->arena); - } - - char *dst = _upb_array_ptr(arr); - memcpy(dst, ptr, size); - arr->len = elems; - - return fastdecode_dispatch(d, ptr + size, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_fixed(UPB_PARSE_PARAMS, int tagbytes, - int valbytes, upb_card card, - _upb_field_parser *unpacked, - _upb_field_parser *packed) { - if (card == CARD_p) { - return fastdecode_packedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, unpacked); - } else { - return fastdecode_unpackedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, card, - packed); - } -} - /* Generate all combinations: * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ -#define F(card, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_fixed(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \ - &upb_ppf##valbytes##_##tagbytes##bt, \ - &upb_prf##valbytes##_##tagbytes##bt); \ +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ } #define TYPES(card, tagbytes) \ @@ -3255,6 +3282,8 @@ TAGBYTES(p) #undef F #undef TYPES #undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED /* string fields **************************************************************/ @@ -3266,56 +3295,54 @@ typedef const char *fastdecode_copystr_func(struct upb_decstate *d, UPB_NOINLINE static const char *fastdecode_verifyutf8(upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, - uint64_t hasbits, upb_strview *dst) { + uint64_t hasbits, uint64_t data) { + upb_strview *dst = (upb_strview*)data; if (!decode_verifyutf8_inl(dst->data, dst->size)) { return fastdecode_err(d); } - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -UPB_FORCEINLINE -static const char *fastdecode_longstring(struct upb_decstate *d, - const char *ptr, upb_msg *msg, - intptr_t table, uint64_t hasbits, - upb_strview *dst, - bool validate_utf8) { - int size = (uint8_t)ptr[0]; // Could plumb through hasbits. - ptr++; - if (size & 0x80) { - ptr = fastdecode_longsize(ptr, &size); - } - - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { - dst->size = 0; - return fastdecode_err(d); - } - - if (d->alias) { - dst->data = ptr; - dst->size = size; - } else { - char *data = upb_arena_malloc(&d->arena, size); - if (!data) { - return fastdecode_err(d); - } - memcpy(data, ptr, size); - dst->data = data; - dst->size = size; + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +} + +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ + dst->size = 0; \ + return fastdecode_err(d); \ + } \ + \ + if (d->alias) { \ + dst->data = ptr; \ + dst->size = size; \ + } else { \ + char *data = upb_arena_malloc(&d->arena, size); \ + if (!data) { \ + return fastdecode_err(d); \ + } \ + memcpy(data, ptr, size); \ + dst->data = data; \ + dst->size = size; \ + } \ + \ + ptr += size; \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ } - if (validate_utf8) { - return fastdecode_verifyutf8(d, ptr + size, msg, table, hasbits, dst); - } else { - return fastdecode_dispatch(d, ptr + size, msg, table, hasbits); - } -} - UPB_NOINLINE static const char *fastdecode_longstring_utf8(struct upb_decstate *d, - const char *ptr, upb_msg *msg, - intptr_t table, uint64_t hasbits, - upb_strview *dst) { - return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, true); + const char *ptr, upb_msg *msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_strview *dst = (upb_strview*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); } UPB_NOINLINE @@ -3323,8 +3350,9 @@ static const char *fastdecode_longstring_noutf8(struct upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, uint64_t hasbits, - upb_strview *dst) { - return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, false); + uint64_t data) { + upb_strview *dst = (upb_strview*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); } UPB_FORCEINLINE @@ -3337,156 +3365,165 @@ static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size, UPB_POISON_MEMORY_REGION(data + size, copy - size); } -UPB_FORCEINLINE -static const char *fastdecode_copystring(UPB_PARSE_PARAMS, int tagbytes, - upb_card card, bool validate_utf8) { - upb_strview *dst; - fastdecode_arr farr; - int64_t size; - size_t arena_has; - size_t common_has; - char *buf; - - UPB_ASSERT(!d->alias); - UPB_ASSERT(fastdecode_checktag(data, tagbytes)); - - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, - sizeof(upb_strview), card); - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); - } - - size = (uint8_t)ptr[tagbytes]; - ptr += tagbytes + 1; - dst->size = size; - - buf = d->arena.head.ptr; - arena_has = _upb_arenahas(&d->arena); - common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); - - if (UPB_LIKELY(size <= 15 - tagbytes)) { - if (arena_has < 16) goto longstr; - d->arena.head.ptr += 16; - memcpy(buf, ptr - tagbytes - 1, 16); - dst->data = buf + tagbytes + 1; - } else if (UPB_LIKELY(size <= 32)) { - if (UPB_UNLIKELY(common_has < 32)) goto longstr; - fastdecode_docopy(d, ptr, size, 32, buf, dst); - } else if (UPB_LIKELY(size <= 64)) { - if (UPB_UNLIKELY(common_has < 64)) goto longstr; - fastdecode_docopy(d, ptr, size, 64, buf, dst); - } else if (UPB_LIKELY(size < 128)) { - if (UPB_UNLIKELY(common_has < 128)) goto longstr; - fastdecode_docopy(d, ptr, size, 128, buf, dst); - } else { - goto longstr; - } - - ptr += size; - - if (card == CARD_r) { - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d); - } - fastdecode_nextret ret = fastdecode_nextrepeated( - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - if (card != CARD_r && validate_utf8) { - return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst); - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); - -longstr: - ptr--; - if (validate_utf8) { - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst); - } else { - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst); - } -} - -UPB_FORCEINLINE -static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes, - upb_card card, _upb_field_parser *copyfunc, - bool validate_utf8) { - upb_strview *dst; - fastdecode_arr farr; - int64_t size; - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - RETURN_GENERIC("string field tag mismatch\n"); - } - - if (UPB_UNLIKELY(!d->alias)) { - return copyfunc(UPB_PARSE_ARGS); - } - - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, - sizeof(upb_strview), card); - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); - } - - size = (int8_t)ptr[tagbytes]; - ptr += tagbytes + 1; - dst->data = ptr; - dst->size = size; - - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { - ptr--; - if (validate_utf8) { - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst); - } else { - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst); - } - } - - ptr += size; - - if (card == CARD_r) { - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d); - } - fastdecode_nextret ret = fastdecode_nextrepeated( - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - if (UPB_UNLIKELY(!d->alias)) { - // Buffer flipped and we can't alias any more. Bounce to copyfunc(), - // but via dispatch since we need to reload table data also. - fastdecode_commitarr(dst, &farr, sizeof(upb_strview)); - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - } - goto again; - case FD_NEXT_OTHERFIELD: - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - return ptr; - } - } - - if (card != CARD_r && validate_utf8) { - return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst); - } - - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_strview *dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char *buf; \ + \ + UPB_ASSERT(!d->alias); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_strview), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.head.ptr; \ + arena_has = _upb_arenahas(&d->arena); \ + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) \ + goto longstr; \ + d->arena.head.ptr += 16; \ + memcpy(buf, ptr - tagbytes - 1, 16); \ + dst->data = buf + tagbytes + 1; \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) \ + goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) \ + goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) \ + goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } + +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_strview *dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY(!d->alias)) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_strview), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->data = ptr; \ + dst->size = size; \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + if (UPB_UNLIKELY(!d->alias)) { \ + /* Buffer flipped and we can't alias any more. Bounce to */ \ + /* copyfunc(), but via dispatch since we need to reload table */ \ + /* data also. */ \ + fastdecode_commitarr(dst, &farr, sizeof(upb_strview)); \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); /* Generate all combinations: * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ @@ -3494,16 +3531,16 @@ static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes, #define s_VALIDATE true #define b_VALIDATE false -#define F(card, tagbytes, type) \ - UPB_NOINLINE \ - const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_copystring(UPB_PARSE_ARGS, tagbytes, CARD_##card, \ - type##_VALIDATE); \ - } \ - const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - return fastdecode_string(UPB_PARSE_ARGS, tagbytes, CARD_##card, \ - &upb_c##card##type##_##tagbytes##bt, \ - type##_VALIDATE); \ +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ } #define UTF8(card, tagbytes) \ @@ -3522,6 +3559,9 @@ TAGBYTES(r) #undef b_VALIDATE #undef F #undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING /* message fields *************************************************************/ @@ -3554,82 +3594,82 @@ UPB_FORCEINLINE static const char *fastdecode_tosubmsg(upb_decstate *d, const char *ptr, void *ctx) { fastdecode_submsgdata *submsg = ctx; - ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0); + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); UPB_ASSUME(ptr != NULL); return ptr; } -UPB_FORCEINLINE -static const char *fastdecode_submsg(UPB_PARSE_PARAMS, int tagbytes, - int msg_ceil_bytes, upb_card card) { - - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { - RETURN_GENERIC("submessage field tag mismatch\n"); - } - - if (--d->depth == 0) return fastdecode_err(d); - - upb_msg **dst; - uint32_t submsg_idx = (data >> 16) & 0xff; - const upb_msglayout *tablep = decode_totablep(table); - const upb_msglayout *subtablep = tablep->submsgs[submsg_idx]; - fastdecode_submsgdata submsg = {decode_totable(subtablep)}; - fastdecode_arr farr; - - if (subtablep->table_mask == (uint8_t)-1) { - RETURN_GENERIC("submessage doesn't have fast tables."); - } - - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, - sizeof(upb_msg *), card); - - if (card == CARD_s) { - *(uint32_t*)msg |= hasbits; - hasbits = 0; - } - -again: - if (card == CARD_r) { - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg*)); - } - - submsg.msg = *dst; - - if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { - *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); - } - - ptr += tagbytes; - ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); - - if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { - return fastdecode_err(d); - } - - if (card == CARD_r) { - fastdecode_nextret ret = fastdecode_nextrepeated( - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *)); - switch (ret.next) { - case FD_NEXT_SAMEFIELD: - dst = ret.dst; - goto again; - case FD_NEXT_OTHERFIELD: - d->depth++; - return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); - case FD_NEXT_ATLIMIT: - d->depth++; - return ptr; - } - } - - d->depth++; - return fastdecode_dispatch(d, ptr, msg, table, hasbits); -} - -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ - UPB_PARSE_PARAMS) { \ - return fastdecode_submsg(UPB_PARSE_ARGS, tagbytes, ceil_arg, CARD_##card); \ +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) return fastdecode_err(d); \ + \ + upb_msg **dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_msglayout *tablep = decode_totablep(table); \ + const upb_msglayout *subtablep = tablep->submsgs[submsg_idx]; \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->table_mask == (uint8_t)-1) { \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_msg *), card); \ + \ + if (card == CARD_s) { \ + *(uint32_t *)msg |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg *)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + return fastdecode_err(d); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ } #define SIZES(card, tagbytes) \ @@ -3650,9 +3690,11 @@ TAGBYTES(r) #undef TAGBYTES #undef SIZES #undef F +#undef FASTDECODE_SUBMSG #endif /* UPB_FASTTABLE */ -/* This file was generated by upbc (the upb compiler) from the input + +/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -4135,6 +4177,7 @@ const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = { +/** upb/def.c ************************************************************/ #include #include @@ -4172,7 +4215,6 @@ struct upb_fielddef { uint32_t number_; uint16_t index_; uint16_t layout_index; - uint32_t selector_base; /* Used to index into a upb::Handlers table. */ bool is_extension_; bool lazy_; bool packed_; @@ -4185,8 +4227,6 @@ struct upb_msgdef { const upb_msglayout *layout; const upb_filedef *file; const char *full_name; - uint32_t selector_count; - uint32_t submsg_field_count; /* Tables for looking up fields by number and name. */ upb_inttable itof; @@ -4316,30 +4356,6 @@ int cmp_fields(const void *p1, const void *p2) { return field_rank(f1) - field_rank(f2); } -/* A few implementation details of handlers. We put these here to avoid - * a def -> handlers dependency. */ - -#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */ - -static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { - return upb_fielddef_isseq(f) ? 2 : 0; -} - -static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { - uint32_t ret = 1; - if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ - if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ - if (upb_fielddef_issubmsg(f)) { - /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ - ret += 0; - if (upb_fielddef_lazy(f)) { - /* STARTSTR/ENDSTR/STRING (for lazy) */ - ret += 3; - } - } - return ret; -} - static void upb_status_setoom(upb_status *status) { upb_status_seterrmsg(status, "out of memory"); } @@ -4431,8 +4447,7 @@ bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { upb_value v; - return upb_inttable_lookup32(&def->iton, num, &v) ? - upb_value_getcstr(v) : NULL; + return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getcstr(v) : NULL; } const char *upb_enum_iter_name(upb_enum_iter *iter) { @@ -4521,10 +4536,6 @@ const char *upb_fielddef_jsonname(const upb_fielddef *f) { return f->json_name; } -uint32_t upb_fielddef_selectorbase(const upb_fielddef *f) { - return f->selector_base; -} - const upb_filedef *upb_fielddef_file(const upb_fielddef *f) { return f->file; } @@ -4687,18 +4698,10 @@ upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) { return m->file->syntax; } -size_t upb_msgdef_selectorcount(const upb_msgdef *m) { - return m->selector_count; -} - -uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m) { - return m->submsg_field_count; -} - const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { upb_value val; - return upb_inttable_lookup32(&m->itof, i, &val) ? - upb_value_getconstptr(val) : NULL; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; } const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, @@ -4906,8 +4909,8 @@ const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) { upb_value val; - return upb_inttable_lookup32(&o->itof, num, &val) ? - upb_value_getptr(val) : NULL; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; } void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) { @@ -4987,7 +4990,6 @@ void upb_symtab_free(upb_symtab *s) { upb_symtab *upb_symtab_new(void) { upb_symtab *s = upb_gmalloc(sizeof(*s)); - upb_alloc *alloc; if (!s) { return NULL; @@ -4995,10 +4997,9 @@ upb_symtab *upb_symtab_new(void) { s->arena = upb_arena_new(); s->bytes_loaded = 0; - alloc = upb_arena_alloc(s->arena); - if (!upb_strtable_init2(&s->syms, UPB_CTYPE_CONSTPTR, 32, alloc) || - !upb_strtable_init2(&s->files, UPB_CTYPE_CONSTPTR, 4, alloc)) { + if (!upb_strtable_init(&s->syms, 32, s->arena) || + !upb_strtable_init(&s->files, 4, s->arena)) { upb_arena_free(s->arena); upb_gfree(s); s = NULL; @@ -5054,8 +5055,7 @@ int upb_symtab_filecount(const upb_symtab *s) { typedef struct { upb_symtab *symtab; upb_filedef *file; /* File we are building. */ - upb_arena *file_arena; /* Allocate defs here. */ - upb_alloc *alloc; /* Alloc of file_arena, for tables. */ + upb_arena *arena; /* Allocate defs here. */ const upb_msglayout **layouts; /* NULL if we should build layouts. */ upb_status *status; /* Record errors here. */ jmp_buf err; /* longjmp() on error. */ @@ -5077,7 +5077,7 @@ static void symtab_oomerr(symtab_addctx *ctx) { } void *symtab_alloc(symtab_addctx *ctx, size_t bytes) { - void *ret = upb_arena_malloc(ctx->file_arena, bytes); + void *ret = upb_arena_malloc(ctx->arena, bytes); if (!ret) symtab_oomerr(ctx); return ret; } @@ -5184,13 +5184,21 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { upb_msg_field_iter it; upb_msg_oneof_iter oit; size_t hasbit; - size_t submsg_count = m->submsg_field_count; + size_t field_count = upb_msgdef_numfields(m); + size_t submsg_count = 0; const upb_msglayout **submsgs; upb_msglayout_field *fields; memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry)); - fields = symtab_alloc(ctx, upb_msgdef_numfields(m) * sizeof(*fields)); + /* Count sub-messages. */ + for (size_t i = 0; i < field_count; i++) { + if (upb_fielddef_issubmsg(&m->fields[i])) { + submsg_count++; + } + } + + fields = symtab_alloc(ctx, field_count * sizeof(*fields)); submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs)); l->field_count = upb_msgdef_numfields(m); @@ -5341,51 +5349,8 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { assign_layout_indices(m, fields); } -static void assign_msg_indices(symtab_addctx *ctx, upb_msgdef *m) { - /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the - * lowest indexes, but we do not publicly guarantee this. */ - upb_msg_field_iter j; - int i; - uint32_t selector; - int n = upb_msgdef_numfields(m); - upb_fielddef **fields; - - if (n == 0) { - m->selector_count = UPB_STATIC_SELECTOR_COUNT; - m->submsg_field_count = 0; - return; - } - - fields = upb_gmalloc(n * sizeof(*fields)); - - m->submsg_field_count = 0; - for(i = 0, upb_msg_field_begin(&j, m); - !upb_msg_field_done(&j); - upb_msg_field_next(&j), i++) { - upb_fielddef *f = upb_msg_iter_field(&j); - UPB_ASSERT(f->msgdef == m); - if (upb_fielddef_issubmsg(f)) { - m->submsg_field_count++; - } - fields[i] = f; - } - - qsort(fields, n, sizeof(*fields), cmp_fields); - - selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; - for (i = 0; i < n; i++) { - upb_fielddef *f = fields[i]; - f->index_ = i; - f->selector_base = selector + upb_handlers_selectorbaseoffset(f); - selector += upb_handlers_selectorcount(f); - } - m->selector_count = selector; - - upb_gfree(fields); -} - static char *strviewdup(symtab_addctx *ctx, upb_strview view) { - return upb_strdup2(view.data, view.size, ctx->alloc); + return upb_strdup2(view.data, view.size, ctx->arena); } static bool streql2(const char *a, size_t n, const char *b) { @@ -5496,9 +5461,9 @@ static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) { if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { symtab_errf(ctx, "duplicate symbol '%s'", name); } - upb_alloc *alloc = upb_arena_alloc(ctx->symtab->arena); size_t len = strlen(name); - CHK_OOM(upb_strtable_insert3(&ctx->symtab->syms, name, len, v, alloc)); + CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, + ctx->symtab->arena)); } /* Given a symbol and the base symbol inside which it is defined, find the @@ -5531,7 +5496,8 @@ static const void *symtab_resolve(symtab_addctx *ctx, const upb_fielddef *f, } notfound: - symtab_errf(ctx, "couldn't resolve name '%s'", sym.data); + symtab_errf(ctx, "couldn't resolve name '" UPB_STRVIEW_FORMAT "'", + UPB_STRVIEW_ARGS(sym)); } static void create_oneofdef( @@ -5549,10 +5515,10 @@ static void create_oneofdef( v = pack_def(o, UPB_DEFTYPE_ONEOF); symtab_add(ctx, o->full_name, v); - CHK_OOM(upb_strtable_insert3(&m->ntof, name.data, name.size, v, ctx->alloc)); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); - CHK_OOM(upb_inttable_init2(&o->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - CHK_OOM(upb_strtable_init2(&o->ntof, UPB_CTYPE_CONSTPTR, 4, ctx->alloc)); + CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); } static str_t *newstr(symtab_addctx *ctx, const char *data, size_t len) { @@ -5608,8 +5574,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len, break; } case UPB_TYPE_INT64: { - /* XXX: Need to write our own strtoll, since it's not available in c89. */ - int64_t val = strtol(str, &end, 0); + long long val = strtoll(str, &end, 0); if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { goto invalid; } @@ -5625,8 +5590,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len, break; } case UPB_TYPE_UINT64: { - /* XXX: Need to write our own strtoull, since it's not available in c89. */ - uint64_t val = strtoul(str, &end, 0); + unsigned long long val = strtoull(str, &end, 0); if (val > UINT64_MAX || errno == ERANGE || *end) { goto invalid; } @@ -5642,8 +5606,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len, break; } case UPB_TYPE_FLOAT: { - /* XXX: Need to write our own strtof, since it's not available in c89. */ - float val = strtod(str, &end); + float val = strtof(str, &end); if (errno == ERANGE || *end) { goto invalid; } @@ -5709,7 +5672,6 @@ static void set_default_default(symtab_addctx *ctx, upb_fielddef *f) { static void create_fielddef( symtab_addctx *ctx, const char *prefix, upb_msgdef *m, const google_protobuf_FieldDescriptorProto *field_proto) { - upb_alloc *alloc = ctx->alloc; upb_fielddef *f; const google_protobuf_FieldOptions *options; upb_strview name; @@ -5745,7 +5707,8 @@ static void create_fielddef( upb_value v, field_v, json_v; size_t json_size; - f = (upb_fielddef*)&m->fields[m->field_count++]; + f = (upb_fielddef*)&m->fields[m->field_count]; + f->index_ = m->field_count++; f->msgdef = m; f->is_extension_ = false; @@ -5766,12 +5729,12 @@ static void create_fielddef( v = upb_value_constptr(f); json_size = strlen(json_name); - CHK_OOM( - upb_strtable_insert3(&m->ntof, name.data, name.size, field_v, alloc)); - CHK_OOM(upb_inttable_insert2(&m->itof, field_number, v, alloc)); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, + ctx->arena)); + CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); if (strcmp(shortname, json_name) != 0) { - upb_strtable_insert3(&m->ntof, json_name, json_size, json_v, alloc); + upb_strtable_insert(&m->ntof, json_name, json_size, json_v, ctx->arena); } if (ctx->layouts) { @@ -5834,15 +5797,16 @@ static void create_fielddef( symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); } - oneof = (upb_oneofdef*)&m->oneofs[oneof_index]; + oneof = (upb_oneofdef *)&m->oneofs[oneof_index]; f->oneof = oneof; oneof->field_count++; if (f->proto3_optional_) { oneof->synthetic = true; } - CHK_OOM(upb_inttable_insert2(&oneof->itof, f->number_, v, alloc)); - CHK_OOM(upb_strtable_insert3(&oneof->ntof, name.data, name.size, v, alloc)); + CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); + CHK_OOM( + upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); } else { f->oneof = NULL; if (f->proto3_optional_) { @@ -5885,8 +5849,8 @@ static void create_enumdef( symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - CHK_OOM(upb_strtable_init2(&e->ntoi, UPB_CTYPE_INT32, n, ctx->alloc)); - CHK_OOM(upb_inttable_init2(&e->iton, UPB_CTYPE_CSTR, ctx->alloc)); + CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); + CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); e->file = ctx->file; e->defaultval = 0; @@ -5913,16 +5877,15 @@ static void create_enumdef( } CHK_OOM(name2) - CHK_OOM( - upb_strtable_insert3(&e->ntoi, name2, strlen(name2), v, ctx->alloc)); + CHK_OOM(upb_strtable_insert(&e->ntoi, name2, strlen(name2), v, ctx->arena)); if (!upb_inttable_lookup(&e->iton, num, NULL)) { upb_value v = upb_value_cstr(name2); - CHK_OOM(upb_inttable_insert2(&e->iton, num, v, ctx->alloc)); + CHK_OOM(upb_inttable_insert(&e->iton, num, v, ctx->arena)); } } - upb_inttable_compact2(&e->iton, ctx->alloc); + upb_inttable_compact(&e->iton, ctx->arena); } static void create_msgdef(symtab_addctx *ctx, const char *prefix, @@ -5946,9 +5909,8 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - CHK_OOM(upb_inttable_init2(&m->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - CHK_OOM(upb_strtable_init2(&m->ntof, UPB_CTYPE_CONSTPTR, n_oneof + n_field, - ctx->alloc)); + CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); m->file = ctx->file; m->map_entry = false; @@ -5980,10 +5942,9 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, create_fielddef(ctx, m->full_name, m, fields[i]); } - assign_msg_indices(ctx, m); finalize_oneofs(ctx, m); assign_msg_wellknowntype(m); - upb_inttable_compact2(&m->itof, ctx->alloc); + upb_inttable_compact(&m->itof, ctx->arena); /* This message is built. Now build nested messages and enums. */ @@ -6212,19 +6173,18 @@ static void build_filedef( } static void remove_filedef(upb_symtab *s, upb_filedef *file) { - upb_alloc *alloc = upb_arena_alloc(s->arena); int i; for (i = 0; i < file->msg_count; i++) { const char *name = file->msgs[i].full_name; - upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + upb_strtable_remove(&s->syms, name, strlen(name), NULL); } for (i = 0; i < file->enum_count; i++) { const char *name = file->enums[i].full_name; - upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + upb_strtable_remove(&s->syms, name, strlen(name), NULL); } for (i = 0; i < file->ext_count; i++) { const char *name = file->exts[i].full_name; - upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + upb_strtable_remove(&s->syms, name, strlen(name), NULL); } } @@ -6242,8 +6202,7 @@ static const upb_filedef *_upb_symtab_addfile( ctx.file = file; ctx.symtab = s; - ctx.file_arena = file_arena; - ctx.alloc = upb_arena_alloc(file_arena); + ctx.arena = file_arena; ctx.layouts = layouts; ctx.status = status; @@ -6258,8 +6217,8 @@ static const upb_filedef *_upb_symtab_addfile( file = NULL; } else { build_filedef(&ctx, file, file_proto); - upb_strtable_insert3(&s->files, file->name, strlen(file->name), - upb_value_constptr(file), ctx.alloc); + upb_strtable_insert(&s->files, file->name, strlen(file->name), + upb_value_constptr(file), ctx.arena); UPB_ASSERT(upb_ok(status)); upb_arena_fuse(s->arena, file_arena); } @@ -6333,6 +6292,7 @@ upb_arena *_upb_symtab_arena(const upb_symtab *s) { #undef CHK_OOM +/** upb/reflection.c ************************************************************/ #include @@ -6443,40 +6403,7 @@ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) { return _upb_msg_getraw(msg, f); } else { - /* TODO(haberman): change upb_fielddef to not require this switch(). */ - upb_msgval val = {0}; - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_ENUM: - val.int32_val = upb_fielddef_defaultint32(f); - break; - case UPB_TYPE_INT64: - val.int64_val = upb_fielddef_defaultint64(f); - break; - case UPB_TYPE_UINT32: - val.uint32_val = upb_fielddef_defaultuint32(f); - break; - case UPB_TYPE_UINT64: - val.uint64_val = upb_fielddef_defaultuint64(f); - break; - case UPB_TYPE_FLOAT: - val.float_val = upb_fielddef_defaultfloat(f); - break; - case UPB_TYPE_DOUBLE: - val.double_val = upb_fielddef_defaultdouble(f); - break; - case UPB_TYPE_BOOL: - val.bool_val = upb_fielddef_defaultbool(f); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - val.str_val.data = upb_fielddef_defaultstr(f, &val.str_val.size); - break; - case UPB_TYPE_MESSAGE: - val.msg_val = NULL; - break; - } - return val; + return upb_fielddef_default(f); } } @@ -6736,6 +6663,7 @@ upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) { /* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */ +/** upb/json_decode.c ************************************************************/ #include #include @@ -7646,17 +7574,17 @@ static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) { return; } - if (upb_fielddef_realcontainingoneof(f) && - upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) { - jsondec_err(d, "More than one field for this oneof."); - } - if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { /* JSON "null" indicates a default value, so no need to set anything. */ jsondec_null(d); return; } + if (upb_fielddef_realcontainingoneof(f) && + upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + preserved = d->debug_field; d->debug_field = f; @@ -8160,6 +8088,9 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, const upb_msgdef *m, const upb_symtab *any_pool, int options, upb_arena *arena, upb_status *status) { jsondec d; + + if (size == 0) return true; + d.ptr = buf; d.end = buf + size; d.arena = arena; @@ -8178,6 +8109,7 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, return true; } +/** upb/json_encode.c ************************************************************/ #include #include @@ -8207,7 +8139,7 @@ static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f); static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg, const upb_msgdef *m); static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg, - const upb_msgdef *m); + const upb_msgdef *m, bool first); static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m); UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) { @@ -8238,8 +8170,10 @@ static void jsonenc_putbytes(jsonenc *e, const void *data, size_t len) { memcpy(e->ptr, data, len); e->ptr += len; } else { - if (have) memcpy(e->ptr, data, have); - e->ptr += have; + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } e->overflow += (len - have); } } @@ -8261,7 +8195,7 @@ static void jsonenc_printf(jsonenc *e, const char *fmt, ...) { if (UPB_LIKELY(have > n)) { e->ptr += n; } else { - e->ptr += have; + e->ptr = UPB_PTRADD(e->ptr, have); e->overflow += (n - have); } } @@ -8365,7 +8299,7 @@ static void jsonenc_bytes(jsonenc *e, upb_strview str) { static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const unsigned char *ptr = (unsigned char*)str.data; - const unsigned char *end = ptr + str.size; + const unsigned char *end = UPB_PTRADD(ptr, str.size); char buf[4]; jsonenc_putstr(e, "\""); @@ -8401,7 +8335,7 @@ static void jsonenc_bytes(jsonenc *e, upb_strview str) { static void jsonenc_stringbody(jsonenc *e, upb_strview str) { const char *ptr = str.data; - const char *end = ptr + str.size; + const char *end = UPB_PTRADD(ptr, str.size); while (ptr < end) { switch (*ptr) { @@ -8517,14 +8451,13 @@ static void jsonenc_any(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) { jsonenc_putstr(e, "{\"@type\":"); jsonenc_string(e, type_url); - jsonenc_putstr(e, ","); if (upb_msgdef_wellknowntype(any_m) == UPB_WELLKNOWN_UNSPECIFIED) { /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ - jsonenc_msgfields(e, any, any_m); + jsonenc_msgfields(e, any, any_m, false); } else { /* Well-known type: {"@type": "...","value": } */ - jsonenc_putstr(e, "\"value\":"); + jsonenc_putstr(e, ",\"value\":"); jsonenc_msgfield(e, any, any_m); } @@ -8827,10 +8760,9 @@ static void jsonenc_fieldval(jsonenc *e, const upb_fielddef *f, } static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg, - const upb_msgdef *m) { + const upb_msgdef *m, bool first) { upb_msgval val; const upb_fielddef *f; - bool first = true; if (e->options & UPB_JSONENC_EMITDEFAULTS) { /* Iterate over all fields. */ @@ -8853,7 +8785,7 @@ static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg, static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) { jsonenc_putstr(e, "{"); - jsonenc_msgfields(e, msg, m); + jsonenc_msgfields(e, msg, m, true); jsonenc_putstr(e, "}"); } @@ -8875,7 +8807,7 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m, e.buf = buf; e.ptr = buf; - e.end = buf + size; + e.end = UPB_PTRADD(buf, size); e.overflow = 0; e.options = options; e.ext_pool = ext_pool; @@ -8888,27 +8820,39 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m, if (e.arena) upb_arena_free(e.arena); return jsonenc_nullz(&e, size); } + +/** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ -#undef UPB_MAPTYPE_STRING #undef UPB_SIZE #undef UPB_PTR_AT #undef UPB_READ_ONEOF #undef UPB_WRITE_ONEOF +#undef UPB_MAPTYPE_STRING #undef UPB_INLINE #undef UPB_ALIGN_UP #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_LIKELY +#undef UPB_UNLIKELY #undef UPB_FORCEINLINE #undef UPB_NOINLINE #undef UPB_NORETURN +#undef UPB_PRINTF #undef UPB_MAX #undef UPB_MIN #undef UPB_UNUSED #undef UPB_ASSUME #undef UPB_ASSERT #undef UPB_UNREACHABLE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index fa0439355897..68d6345fc508 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -1,26 +1,53 @@ /* Amalgamated source file */ -#include /* -* This is where we define macros used across upb. -* -* All of these macros are undef'd in port_undef.inc to avoid leaking them to -* users. -* -* The correct usage is: -* -* #include "upb/foobar.h" -* #include "upb/baz.h" -* -* // MUST be last included header. -* #include "upb/port_def.inc" -* -* // Code for this file. -* // <...> -* -* // Can be omitted for .c files, required for .h. -* #include "upb/port_undef.inc" -* -* This file is private and must not be included by users! -*/ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is where we define macros used across upb. + * + * All of these macros are undef'd in port_undef.inc to avoid leaking them to + * users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port_def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port_undef.inc" + * + * This file is private and must not be included by users! + */ #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (defined(__cplusplus) && __cplusplus >= 201103L) || \ @@ -136,9 +163,40 @@ #define UPB_LONGJMP(buf, val) longjmp(buf, val) #endif +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + /* Configure whether fasttable is switched on or not. *************************/ -#if defined(__x86_64__) && defined(__GNUC__) +#ifdef __has_attribute +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#undef UPB_HAS_ATTRIBUTE + +/* This check is not fully robust: it does not require that we have "musttail" + * support available. We need tail calls to avoid consuming arbitrary amounts + * of stack space. + * + * GCC/Clang can mostly be trusted to generate tail calls as long as + * optimization is enabled, but, debug builds will not generate tail calls + * unless "musttail" is available. + * + * We should probably either: + * 1. require that the compiler supports musttail. + * 2. add some fallback code for when musttail isn't available (ie. return + * instead of tail calling). This is safe and portable, but this comes at + * a CPU cost. + */ +#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) #define UPB_FASTTABLE_SUPPORTED 1 #else #define UPB_FASTTABLE_SUPPORTED 0 @@ -149,7 +207,7 @@ * for example for testing or benchmarking. */ #if defined(UPB_ENABLE_FASTTABLE) #if !UPB_FASTTABLE_SUPPORTED -#error fasttable is x86-64 + Clang/GCC only +#error fasttable is x86-64/ARM64 only and requires GCC or Clang. #endif #define UPB_FASTTABLE 1 /* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. @@ -193,55 +251,36 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) -#endif +#endif + +/** upb/decode.h ************************************************************/ /* -** upb_decode: parsing into a upb_msg using a upb_msglayout. -*/ + * upb_decode: parsing into a upb_msg using a upb_msglayout. + */ #ifndef UPB_DECODE_H_ #define UPB_DECODE_H_ + +/** upb/msg.h ************************************************************/ /* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ + * Public APIs for message operations that do not require descriptors. + * These functions can be used even in build that does not want to depend on + * reflection or descriptors. + * + * Descriptor-based reflection functionality lives in reflection.h. + */ #ifndef UPB_MSG_H_ #define UPB_MSG_H_ -#include -#include -#include - -/* -** upb_table -** -** This header is INTERNAL-ONLY! Its interfaces are not public or stable! -** This file defines very fast int->upb_value (inttable) and string->upb_value -** (strtable) hash tables. -** -** The table uses chained scatter with Brent's variation (inspired by the Lua -** implementation of hash tables). The hash function for strings is Austin -** Appleby's "MurmurHash." -** -** The inttable uses uintptr_t as its key, which guarantees it can be used to -** store pointers or integers of at least 32 bits (upb isn't really useful on -** systems where sizeof(void*) < 4). -** -** The table must be homogeneous (all values of the same type). In debug -** mode, we check this on insert and lookup. -*/ +#include -#ifndef UPB_TABLE_H_ -#define UPB_TABLE_H_ -#include -#include +/** upb/upb.h ************************************************************/ /* -** This file contains shared definitions that are widely used across upb. -*/ + * This file contains shared definitions that are widely used across upb. + */ #ifndef UPB_H_ #define UPB_H_ @@ -399,7 +438,7 @@ typedef struct { upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc); void upb_arena_free(upb_arena *a); bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func); -void upb_arena_fuse(upb_arena *a, upb_arena *b); +bool upb_arena_fuse(upb_arena *a, upb_arena *b); void *_upb_arena_slowmalloc(upb_arena *a, size_t size); UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; } @@ -578,55 +617,134 @@ UPB_INLINE int _upb_lg2ceilsize(int x) { #endif /* UPB_H_ */ +#ifdef __cplusplus +extern "C" { +#endif + +typedef void upb_msg; + +/* For users these are opaque. They can be obtained from upb_msgdef_layout() + * but users cannot access any of the members. */ +struct upb_msglayout; +typedef struct upb_msglayout upb_msglayout; + +/* Adds unknown data (serialized protobuf data) to the given message. The data + * is copied into the message instance. */ +void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, + upb_arena *arena); + +/* Returns a reference to the message's unknown data. */ +const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_MSG_INT_H_ */ + +/* Must be last. */ #ifdef __cplusplus extern "C" { #endif +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + UPB_DECODE_ALIAS = 1, +}; -/* upb_value ******************************************************************/ +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) -/* A tagged union (stored untagged inside the table) so that we can check that - * clients calling table accessors are correctly typed without having to have - * an explosion of accessors. */ -typedef enum { - UPB_CTYPE_INT32 = 1, - UPB_CTYPE_INT64 = 2, - UPB_CTYPE_UINT32 = 3, - UPB_CTYPE_UINT64 = 4, - UPB_CTYPE_BOOL = 5, - UPB_CTYPE_CSTR = 6, - UPB_CTYPE_PTR = 7, - UPB_CTYPE_CONSTPTR = 8, - UPB_CTYPE_FPTR = 9, - UPB_CTYPE_FLOAT = 10, - UPB_CTYPE_DOUBLE = 11 -} upb_ctype_t; +bool _upb_decode(const char *buf, size_t size, upb_msg *msg, + const upb_msglayout *l, upb_arena *arena, int options); + +UPB_INLINE +bool upb_decode(const char *buf, size_t size, upb_msg *msg, + const upb_msglayout *l, upb_arena *arena) { + return _upb_decode(buf, size, msg, l, arena, 0); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_DECODE_H_ */ + +/** upb/decode_internal.h ************************************************************/ +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_DECODE_INT_H_ +#define UPB_DECODE_INT_H_ + +#include + + +/** upb/msg_internal.h ************************************************************//* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ + +#ifndef UPB_MSG_INT_H_ +#define UPB_MSG_INT_H_ + +#include +#include +#include + + +/** upb/table_internal.h ************************************************************/ +/* + * upb_table + * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! + * This file defines very fast int->upb_value (inttable) and string->upb_value + * (strtable) hash tables. + * + * The table uses chained scatter with Brent's variation (inspired by the Lua + * implementation of hash tables). The hash function for strings is Austin + * Appleby's "MurmurHash." + * + * The inttable uses uintptr_t as its key, which guarantees it can be used to + * store pointers or integers of at least 32 bits (upb isn't really useful on + * systems where sizeof(void*) < 4). + * + * The table must be homogeneous (all values of the same type). In debug + * mode, we check this on insert and lookup. + */ + +#ifndef UPB_TABLE_H_ +#define UPB_TABLE_H_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* upb_value ******************************************************************/ typedef struct { uint64_t val; } upb_value; -/* Like strdup(), which isn't always available since it's not ANSI C. */ -char *upb_strdup(const char *s, upb_alloc *a); /* Variant that works with a length-delimited rather than NULL-delimited string, * as supported by strtable. */ -char *upb_strdup2(const char *s, size_t len, upb_alloc *a); - -UPB_INLINE char *upb_gstrdup(const char *s) { - return upb_strdup(s, &upb_alloc_global); -} +char *upb_strdup2(const char *s, size_t len, upb_arena *a); UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val) { v->val = val; } -UPB_INLINE upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; -} - /* For each value ctype, define the following set of functions: * * // Get/set an int32 from a upb_value. @@ -734,14 +852,7 @@ typedef struct { uint32_t mask; /* Mask to turn hash value -> bucket. */ uint32_t max_count; /* Max count before we hit our load limit. */ uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ - - /* Hash table entries. - * Making this const isn't entirely accurate; what we really want is for it to - * have the same const-ness as the table it's inside. But there's no way to - * declare that in C. So we have to make it const so that we can statically - * initialize const hash tables. Then we cast away const when we have to. - */ - const upb_tabent *entries; + upb_tabent *entries; } upb_table; typedef struct { @@ -755,8 +866,6 @@ typedef struct { size_t array_count; /* Array part number of elements. */ } upb_inttable; -#define UPB_ARRAY_EMPTYENT -1 - UPB_INLINE size_t upb_table_size(const upb_table *t) { if (t->size_lg2 == 0) return 0; @@ -769,48 +878,10 @@ UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) { return e->key == 0; } -/* Used by some of the unit tests for generic hashing functionality. */ -uint32_t upb_murmur_hash2(const void * key, size_t len, uint32_t seed); - -UPB_INLINE uintptr_t upb_intkey(uintptr_t key) { - return key; -} - -UPB_INLINE uint32_t upb_inthash(uintptr_t key) { - return (uint32_t)key; -} - -static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { - return t->entries + (hash & t->mask); -} - -UPB_INLINE bool upb_arrhas(upb_tabval key) { - return key.val != (uint64_t)-1; -} - /* Initialize and uninitialize a table, respectively. If memory allocation * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a); -bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, - size_t expected_size, upb_alloc *a); -void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a); -void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a); - -UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) { - return upb_inttable_init2(table, ctype, &upb_alloc_global); -} - -UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) { - return upb_strtable_init2(table, ctype, 4, &upb_alloc_global); -} - -UPB_INLINE void upb_inttable_uninit(upb_inttable *table) { - upb_inttable_uninit2(table, &upb_alloc_global); -} - -UPB_INLINE void upb_strtable_uninit(upb_strtable *table) { - upb_strtable_uninit2(table, &upb_alloc_global); -} +bool upb_inttable_init(upb_inttable *table, upb_arena *a); +bool upb_strtable_init(upb_strtable *table, size_t expected_size, upb_arena *a); /* Returns the number of values in the table. */ size_t upb_inttable_count(const upb_inttable *t); @@ -818,12 +889,6 @@ UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) { return t->t.count; } -void upb_inttable_packedsize(const upb_inttable *t, size_t *size); -void upb_strtable_packedsize(const upb_strtable *t, size_t *size); -upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs, - size_t size); -upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs, - size_t size); void upb_strtable_clear(upb_strtable *t); /* Inserts the given key into the hashtable with the given value. The key must @@ -833,26 +898,10 @@ void upb_strtable_clear(upb_strtable *t); * * If a table resize was required but memory allocation failed, false is * returned and the table is unchanged. */ -bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, - upb_alloc *a); -bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len, - upb_value val, upb_alloc *a); - -UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key, - upb_value val) { - return upb_inttable_insert2(t, key, val, &upb_alloc_global); -} - -UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key, - size_t len, upb_value val) { - return upb_strtable_insert3(t, key, len, val, &upb_alloc_global); -} - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key, - upb_value val) { - return upb_strtable_insert2(t, key, strlen(key), val); -} +bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val, + upb_arena *a); +bool upb_strtable_insert(upb_strtable *t, const char *key, size_t len, + upb_value val, upb_arena *a); /* Looks up key in this table, returning "true" if the key was found. * If v is non-NULL, copies the value for this key into *v. */ @@ -869,74 +918,21 @@ UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key, /* Removes an item from the table. Returns true if the remove was successful, * and stores the removed item in *val if non-NULL. */ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); -bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, - upb_value *val, upb_alloc *alloc); - -UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key, - size_t len, upb_value *val) { - return upb_strtable_remove3(t, key, len, val, &upb_alloc_global); -} - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, - upb_value *v) { - return upb_strtable_remove2(t, key, strlen(key), v); -} +bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len, + upb_value *val); /* Updates an existing entry in an inttable. If the entry does not exist, * returns false and does nothing. Unlike insert/remove, this does not * invalidate iterators. */ bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); -/* Convenience routines for inttables with pointer keys. */ -bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, - upb_alloc *a); -bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); -bool upb_inttable_lookupptr( - const upb_inttable *t, const void *key, upb_value *val); - -UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key, - upb_value val) { - return upb_inttable_insertptr2(t, key, val, &upb_alloc_global); -} - /* Optimizes the table for the current set of entries, for both memory use and * lookup time. Client should call this after all entries have been inserted; * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact2(upb_inttable *t, upb_alloc *a); - -UPB_INLINE void upb_inttable_compact(upb_inttable *t) { - upb_inttable_compact2(t, &upb_alloc_global); -} - -/* A special-case inlinable version of the lookup routine for 32-bit - * integers. */ -UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, - upb_value *v) { - *v = upb_value_int32(0); /* Silence compiler warnings. */ - if (key < t->array_size) { - upb_tabval arrval = t->array[key]; - if (upb_arrhas(arrval)) { - _upb_value_setval(v, arrval.val); - return true; - } else { - return false; - } - } else { - const upb_tabent *e; - if (t->t.entries == NULL) return false; - for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) { - if ((uint32_t)e->key == key) { - _upb_value_setval(v, e->val.val); - return true; - } - if (e->next == NULL) return false; - } - } -} +void upb_inttable_compact(upb_inttable *t, upb_arena *a); /* Exposed for testing only. */ -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a); +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a); /* Iterators ******************************************************************/ @@ -1032,10 +1028,6 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, extern "C" { #endif -#define PTR_AT(msg, ofs, type) (type*)((const char*)msg + ofs) - -typedef void upb_msg; - /** upb_msglayout *************************************************************/ /* upb_msglayout represents the memory layout of a given upb_msgdef. The @@ -1070,7 +1062,7 @@ typedef struct { _upb_field_parser *field_parser; } _upb_fasttable_entry; -typedef struct upb_msglayout { +struct upb_msglayout { const struct upb_msglayout *const* submsgs; const upb_msglayout_field *fields; /* Must be aligned to sizeof(void*). Doesn't include internal members like @@ -1082,7 +1074,7 @@ typedef struct upb_msglayout { /* To constant-initialize the tables of variable length, we need a flexible * array member, and we need to compile in C99 mode. */ _upb_fasttable_entry fasttable[]; -} upb_msglayout; +}; /** upb_msg *******************************************************************/ @@ -1137,21 +1129,18 @@ void _upb_msg_discardunknown_shallow(upb_msg *msg); bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, upb_arena *arena); -/* Returns a reference to the message's unknown data. */ -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); - /** Hasbit access *************************************************************/ UPB_INLINE bool _upb_hasbit(const upb_msg *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; + return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; } UPB_INLINE void _upb_sethas(const upb_msg *msg, size_t idx) { - (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); + (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); } UPB_INLINE void _upb_clearhas(const upb_msg *msg, size_t idx) { - (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); + (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); } UPB_INLINE size_t _upb_msg_hasidx(const upb_msglayout_field *f) { @@ -1177,11 +1166,11 @@ UPB_INLINE void _upb_clearhas_field(const upb_msg *msg, /** Oneof case access *********************************************************/ UPB_INLINE uint32_t *_upb_oneofcase(upb_msg *msg, size_t case_ofs) { - return PTR_AT(msg, case_ofs, uint32_t); + return UPB_PTR_AT(msg, case_ofs, uint32_t); } UPB_INLINE uint32_t _upb_getoneofcase(const void *msg, size_t case_ofs) { - return *PTR_AT(msg, case_ofs, uint32_t); + return *UPB_PTR_AT(msg, case_ofs, uint32_t); } UPB_INLINE size_t _upb_oneofcase_ofs(const upb_msglayout_field *f) { @@ -1200,7 +1189,7 @@ UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_msg *msg, } UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_msg *msg, size_t ofs) { - return *PTR_AT(msg, ofs, const upb_msg*) != NULL; + return *UPB_PTR_AT(msg, ofs, const upb_msg*) != NULL; } UPB_INLINE bool _upb_isrepeated(const upb_msglayout_field *field) { @@ -1277,7 +1266,7 @@ UPB_INLINE bool _upb_array_resize(upb_array *arr, size_t size, UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs, size_t *size) { - const upb_array *arr = *PTR_AT(msg, ofs, const upb_array*); + const upb_array *arr = *UPB_PTR_AT(msg, ofs, const upb_array*); if (arr) { if (size) *size = arr->len; return _upb_array_constptr(arr); @@ -1289,7 +1278,7 @@ UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs, UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, size_t *size) { - upb_array *arr = *PTR_AT(msg, ofs, upb_array*); + upb_array *arr = *UPB_PTR_AT(msg, ofs, upb_array*); if (arr) { if (size) *size = arr->len; return _upb_array_ptr(arr); @@ -1302,7 +1291,7 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, UPB_INLINE void *_upb_array_resize_accessor2(void *msg, size_t ofs, size_t size, int elem_size_lg2, upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *); + upb_array **arr_ptr = UPB_PTR_AT(msg, ofs, upb_array *); upb_array *arr = *arr_ptr; if (!arr || arr->size < size) { return _upb_array_resize_fallback(arr_ptr, size, elem_size_lg2, arena); @@ -1315,7 +1304,7 @@ UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs, int elem_size_lg2, const void *value, upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *); + upb_array **arr_ptr = UPB_PTR_AT(msg, ofs, upb_array *); size_t elem_size = 1 << elem_size_lg2; upb_array *arr = *arr_ptr; void *ptr; @@ -1323,7 +1312,7 @@ UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs, return _upb_array_append_fallback(arr_ptr, value, elem_size_lg2, arena); } ptr = _upb_array_ptr(arr); - memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); + memcpy(UPB_PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); arr->len++; return true; } @@ -1470,20 +1459,19 @@ UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) { } UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size, - void *val, size_t val_size, upb_arena *arena) { + void *val, size_t val_size, upb_arena *a) { upb_strview strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, arena)) return false; - upb_alloc *a = upb_arena_alloc(arena); + if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); - return upb_strtable_insert3(&map->table, strkey.data, strkey.size, tabval, a); + upb_strtable_remove(&map->table, strkey.data, strkey.size, NULL); + return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); } UPB_INLINE bool _upb_map_delete(upb_map *map, const void *key, size_t key_size) { upb_strview k = _upb_map_tokey(key, key_size); - return upb_strtable_remove3(&map->table, k.data, k.size, NULL, NULL); + return upb_strtable_remove(&map->table, k.data, k.size, NULL); } UPB_INLINE void _upb_map_clear(upb_map *map) { @@ -1515,7 +1503,7 @@ UPB_INLINE void *_upb_msg_map_next(const upb_msg *msg, size_t ofs, UPB_INLINE bool _upb_msg_map_set(upb_msg *msg, size_t ofs, const void *key, size_t key_size, void *val, size_t val_size, upb_arena *arena) { - upb_map **map = PTR_AT(msg, ofs, upb_map *); + upb_map **map = UPB_PTR_AT(msg, ofs, upb_map *); if (!*map) { *map = _upb_map_new(arena, key_size, val_size); } @@ -1548,8 +1536,7 @@ UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { const upb_tabent *ent = (const upb_tabent*)msg; - upb_value v; - _upb_value_setval(&v, ent->val.val); + upb_value v = {ent->val.val}; _upb_map_fromvalue(v, val, size); } @@ -1612,55 +1599,14 @@ UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter *s, const upb_map *map, return true; } -#undef PTR_AT - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MSG_H_ */ - -/* Must be last. */ - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* If set, strings will alias the input buffer instead of copying into the - * arena. */ - UPB_DECODE_ALIAS = 1, -}; - -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) - -bool _upb_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msglayout *l, upb_arena *arena, int options); - -UPB_INLINE -bool upb_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msglayout *l, upb_arena *arena) { - return _upb_decode(buf, size, msg, l, arena, 0); -} - #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_DECODE_H_ */ -/* -** Internal implementation details of the decoder that are shared between -** decode.c and decode_fast.c. -*/ - -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ - -#include - +#endif /* UPB_MSG_INT_H_ */ +/** upb/upb_internal.h ************************************************************/ #ifndef UPB_INT_H_ #define UPB_INT_H_ @@ -1670,7 +1616,10 @@ typedef struct mem_block mem_block; struct upb_arena { _upb_arena_head head; - uint32_t *cleanups; + /* Stores cleanup metadata for this arena. + * - a pointer to the current cleanup counter. + * - a boolean indicating if there is an unowned initial block. */ + uintptr_t cleanup_metadata; /* Allocator to allocate arena blocks. We are responsible for freeing these * when we are destroyed. */ @@ -1792,10 +1741,11 @@ bool decode_isdone(upb_decstate *d, const char **ptr) { } } +#if UPB_FASTTABLE UPB_INLINE const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, - uint64_t hasbits, uint32_t tag) { + uint64_t hasbits, uint64_t tag) { const upb_msglayout *table_p = decode_totablep(table); uint8_t mask = table; uint64_t data; @@ -1803,8 +1753,10 @@ const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr, UPB_ASSUME((idx & 7) == 0); idx >>= 3; data = table_p->fasttable[idx].field_data ^ tag; - return table_p->fasttable[idx].field_parser(d, ptr, msg, table, hasbits, data); + UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, + hasbits, data); } +#endif UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { uint16_t tag; @@ -1837,9 +1789,11 @@ UPB_INLINE void decode_poplimit(upb_decstate *d, const char *ptr, #endif /* UPB_DECODE_INT_H_ */ + +/** upb/encode.h ************************************************************/ /* -** upb_encode: parsing into a upb_msg using a upb_msglayout. -*/ + * upb_encode: parsing into a upb_msg using a upb_msglayout. + */ #ifndef UPB_ENCODE_H_ #define UPB_ENCODE_H_ @@ -1880,6 +1834,8 @@ UPB_INLINE char *upb_encode(const void *msg, const upb_msglayout *l, #endif #endif /* UPB_ENCODE_H_ */ + +/** upb/decode_fast.h ************************************************************/ // These are the specialized field parser functions for the fast parser. // Generated tables will refer to these by name. // @@ -2005,7 +1961,8 @@ TAGBYTES(r) #undef UPB_PARSE_PARAMS #endif /* UPB_DECODE_FAST_H_ */ -/* This file was generated by upbc (the upb compiler) from the input + +/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -3884,18 +3841,20 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_prot #endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ + +/** upb/def.h ************************************************************/ /* -** Defs are upb's internal representation of the constructs that can appear -** in a .proto file: -** -** - upb_msgdef: describes a "message" construct. -** - upb_fielddef: describes a message field. -** - upb_filedef: describes a .proto file and its defs. -** - upb_enumdef: describes an enum. -** - upb_oneofdef: describes a oneof. -** -** TODO: definitions of services. -*/ + * Defs are upb's internal representation of the constructs that can appear + * in a .proto file: + * + * - upb_msgdef: describes a "message" construct. + * - upb_fielddef: describes a message field. + * - upb_filedef: describes a .proto file and its defs. + * - upb_enumdef: describes an enum. + * - upb_oneofdef: describes a oneof. + * + * TODO: definitions of services. + */ #ifndef UPB_DEF_H_ #define UPB_DEF_H_ @@ -3991,9 +3950,6 @@ const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f); -/* Internal only. */ -uint32_t upb_fielddef_selectorbase(const upb_fielddef *f); - /* upb_oneofdef ***************************************************************/ typedef upb_inttable_iter upb_oneof_iter; @@ -4078,10 +4034,6 @@ UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m, return upb_msgdef_ntof(m, name, strlen(name)); } -/* Internal-only. */ -size_t upb_msgdef_selectorcount(const upb_msgdef *m); -uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m); - /* Lookup of either field or oneof by name. Returns whether either was found. * If the return is true, then the found def will be set, and the non-found * one set to NULL. */ @@ -4197,6 +4149,7 @@ bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init); #endif /* UPB_DEF_H_ */ +/** upb/reflection.h ************************************************************/ #ifndef UPB_REFLECTION_H_ #define UPB_REFLECTION_H_ @@ -4278,17 +4231,9 @@ bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, const upb_symtab *ext_pool, const upb_fielddef **f, upb_msgval *val, size_t *iter); -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena); - /* Clears all unknown field data from this message and all submessages. */ bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth); -/* Returns a reference to the message's unknown data. */ -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); - /** upb_array *****************************************************************/ /* Creates a new array on the given arena that holds elements of this type. */ @@ -4370,6 +4315,7 @@ void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); #endif /* UPB_REFLECTION_H_ */ +/** upb/json_decode.h ************************************************************/ #ifndef UPB_JSONDECODE_H_ #define UPB_JSONDECODE_H_ @@ -4392,6 +4338,7 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, #endif /* UPB_JSONDECODE_H_ */ +/** upb/json_encode.h ************************************************************/ #ifndef UPB_JSONENCODE_H_ #define UPB_JSONENCODE_H_ @@ -4426,27 +4373,39 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m, #endif #endif /* UPB_JSONENCODE_H_ */ + +/** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ -#undef UPB_MAPTYPE_STRING #undef UPB_SIZE #undef UPB_PTR_AT #undef UPB_READ_ONEOF #undef UPB_WRITE_ONEOF +#undef UPB_MAPTYPE_STRING #undef UPB_INLINE #undef UPB_ALIGN_UP #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_LIKELY +#undef UPB_UNLIKELY #undef UPB_FORCEINLINE #undef UPB_NOINLINE #undef UPB_NORETURN +#undef UPB_PRINTF #undef UPB_MAX #undef UPB_MIN #undef UPB_UNUSED #undef UPB_ASSUME #undef UPB_ASSERT #undef UPB_UNREACHABLE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc index 203b49f918f4..45eb4c619637 100644 --- a/src/google/protobuf/compiler/php/php_generator.cc +++ b/src/google/protobuf/compiler/php/php_generator.cc @@ -1894,8 +1894,8 @@ void GenerateCEnum(const EnumDescriptor* desc, io::Printer* printer) { "}\n" "\n" "static zend_function_entry $c_name$_phpmethods[] = {\n" - " PHP_ME($c_name$, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" - " PHP_ME($c_name$, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" + " PHP_ME($c_name$, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" + " PHP_ME($c_name$, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n" " ZEND_FE_END\n" "};\n" "\n" @@ -1953,7 +1953,7 @@ void GenerateCMessage(const Descriptor* message, io::Printer* printer) { " \"$name$\");\n" " zval ret;\n" " Message_get(intern, f, &ret);\n" - " RETURN_ZVAL(&ret, 1, 0);\n" + " RETURN_COPY_VALUE(&ret);\n" "}\n" "\n" "static PHP_METHOD($c_name$, set$camel_name$) {\n" @@ -1966,7 +1966,7 @@ void GenerateCMessage(const Descriptor* message, io::Printer* printer) { " return;\n" " }\n" " Message_set(intern, f, val);\n" - " RETURN_ZVAL(getThis(), 1, 0);\n" + " RETURN_COPY(getThis());\n" "}\n" "\n", "c_name", c_name, @@ -2012,7 +2012,7 @@ void GenerateCMessage(const Descriptor* message, io::Printer* printer) { printer->Print( "static zend_function_entry $c_name$_phpmethods[] = {\n" - " PHP_ME($c_name$, __construct, arginfo_void, ZEND_ACC_PUBLIC)\n", + " PHP_ME($c_name$, __construct, arginfo_construct, ZEND_ACC_PUBLIC)\n", "c_name", c_name); for (int i = 0; i < message->field_count(); i++) { @@ -2111,7 +2111,14 @@ void GenerateCWellKnownTypes(const std::vector& files, printer.Print( "// This file is generated from the .proto files for the well-known\n" - "// types. Do not edit!\n"); + "// types. Do not edit!\n\n"); + + printer.Print( + "ZEND_BEGIN_ARG_INFO_EX(arginfo_lookup, 0, 0, 1)\n" + " ZEND_ARG_INFO(0, key)\n" + "ZEND_END_ARG_INFO()\n" + "\n" + ); for (auto file : files) { printer.Print(