pull/7944/head
Joshua Haberman 4 years ago
parent f1256df893
commit a93d840881
  1. 46
      php/ext/google/protobuf/bundled_php.h
  2. 2
      php/ext/google/protobuf/config.m4
  3. 71
      php/ext/google/protobuf/def.c
  4. 6
      php/ext/google/protobuf/def.h
  5. 62
      php/ext/google/protobuf/make-preload.php
  6. 232
      php/ext/google/protobuf/message.c
  7. 348
      php/ext/google/protobuf/php-upb.c
  8. 96
      php/ext/google/protobuf/php-upb.h
  9. 34
      php/ext/google/protobuf/protobuf.c
  10. 2920
      php/ext/google/protobuf/wkt.inc
  11. 1
      php/tests/compile_extension.sh
  12. 236
      src/google/protobuf/compiler/php/php_generator.cc

@ -1,46 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Inc. 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 THE COPYRIGHT
// OWNER OR CONTRIBUTORS 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.
#ifndef PHP_PROTOBUF_BUNDLED_PHP_H_
#define PHP_PROTOBUF_BUNDLED_PHP_H_
// We embed PHP source code into the binary for things we don't want to
// implement in C. This struct serves as a table of contents for all of
// the embedded files.
typedef struct {
const char *filename;
const char *contents;
} BundledPhp_File;
// An array of all the embedded file structs. This array is terminated with a
// {NULL, NULL} entry.
extern BundledPhp_File *bundled_files;
#endif // PHP_PROTOBUF_BUNDLED_PHP_H_

@ -4,7 +4,7 @@ if test "$PHP_PROTOBUF" != "no"; then
PHP_NEW_EXTENSION( PHP_NEW_EXTENSION(
protobuf, protobuf,
arena.c array.c bundled_php.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c, arena.c array.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c,
$ext_shared) $ext_shared)
fi fi

@ -772,6 +772,7 @@ upb_symtab *DescriptorPool_GetSymbolTable() {
return intern->symtab; return intern->symtab;
} }
/* /*
* DescriptorPool::getGeneratedPool() * DescriptorPool::getGeneratedPool()
* *
@ -906,13 +907,38 @@ static void add_name_mappings(const upb_filedef *file) {
} }
} }
static void add_descriptor(DescriptorPool *pool,
const google_protobuf_FileDescriptorProto *file) {
upb_strview name = google_protobuf_FileDescriptorProto_name(file);
upb_status status;
const upb_filedef *file_def;
upb_status_clear(&status);
if (upb_symtab_lookupfile2(pool->symtab, name.data, name.size)) {
// Already added.
fprintf(stderr, "WARNING: file was already added\n");
return;
}
// The PHP code generator currently special-cases descriptor.proto. It
// doesn't add it as a dependency even if the proto file actually does
// depend on it.
if (depends_on_descriptor(file)) {
google_protobuf_FileDescriptorProto_getmsgdef(pool->symtab);
}
file_def = upb_symtab_addfile(pool->symtab, file, &status);
CheckUpbStatus(&status, "Unable to load descriptor");
add_name_mappings(file_def);
}
/* /*
* add_name_mappings() * add_descriptor()
* *
* Adds the given descriptor data to this DescriptorPool. * Adds the given descriptor data to this DescriptorPool.
*/ */
static void add_descriptor(DescriptorPool *pool, const char *data, static void add_descriptor_set(DescriptorPool *pool, const char *data,
int data_len, upb_arena *arena) { int data_len, upb_arena *arena) {
size_t i, n; size_t i, n;
google_protobuf_FileDescriptorSet *set; google_protobuf_FileDescriptorSet *set;
const google_protobuf_FileDescriptorProto* const* files; const google_protobuf_FileDescriptorProto* const* files;
@ -928,27 +954,28 @@ static void add_descriptor(DescriptorPool *pool, const char *data,
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
const google_protobuf_FileDescriptorProto* file = files[i]; const google_protobuf_FileDescriptorProto* file = files[i];
upb_strview name = google_protobuf_FileDescriptorProto_name(file); add_descriptor(pool, file);
upb_status status; }
const upb_filedef *file_def; }
upb_status_clear(&status);
if (upb_symtab_lookupfile2(pool->symtab, name.data, name.size)) {
// Already added.
continue;
}
// The PHP code generator currently special-cases descriptor.proto. It bool DescriptorPool_HasFile(const char *filename) {
// doesn't add it as a dependency even if the proto file actually does DescriptorPool *intern = GetPool(get_generated_pool());
// depend on it. return upb_symtab_lookupfile(intern->symtab, filename) != NULL;
if (depends_on_descriptor(file)) { }
google_protobuf_FileDescriptorProto_getmsgdef(pool->symtab);
} void DescriptorPool_AddDescriptor(const char *filename, const char *data,
int size) {
upb_arena *arena = upb_arena_new();
const google_protobuf_FileDescriptorProto *file =
google_protobuf_FileDescriptorProto_parse(data, size, arena);
file_def = upb_symtab_addfile(pool->symtab, file, &status); if (!file) {
CheckUpbStatus(&status, "Unable to load descriptor"); zend_error(E_ERROR, "Failed to parse binary descriptor for %s\n", filename);
add_name_mappings(file_def); return;
} }
add_descriptor(GetPool(get_generated_pool()), file);
upb_arena_free(arena);
} }
/* /*
@ -969,7 +996,7 @@ PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
} }
arena = upb_arena_new(); arena = upb_arena_new();
add_descriptor(intern, data, data_len, arena); add_descriptor_set(intern, data, data_len, arena);
upb_arena_free(arena); upb_arena_free(arena);
} }

@ -49,6 +49,12 @@ upb_symtab *DescriptorPool_Steal(zval *zv);
upb_symtab *DescriptorPool_GetSymbolTable(); upb_symtab *DescriptorPool_GetSymbolTable();
// Returns true if the global descriptor pool already has the given filename.
bool DescriptorPool_HasFile(const char *filename);
// Adds the given descriptor with the given filename to the global pool.
void DescriptorPool_AddDescriptor(const char *filename, const char *data, int size);
typedef struct Descriptor { typedef struct Descriptor {
zend_object std; zend_object std;
const upb_msgdef *msgdef; const upb_msgdef *msgdef;

@ -1,62 +0,0 @@
<?php
$cwd = dirname($argv[0]) . "/../../../src";
chdir($cwd);
$cmd = "grep -r -l 'Generated by the protocol buffer' * | grep 'php$' | grep -v Internal";
$handle = popen($cmd, 'r');
$filenames = explode("\n", stream_get_contents($handle));
array_pop($filenames); // empty string after last '\n'
$filenames[] = "Google/Protobuf/DescriptorPool.php";
$output = "../ext/google/protobuf/bundled_php.c";
function stripSuffix($str, $suffix) {
return substr($str, 0, strlen($str) - strlen($suffix));
}
function toClassName($filename) {
# Google/Protobuf/BoolValue.php -> Google\\Protobuf\\BoolValue
$ret = stripSuffix($filename, ".php");
return str_replace("/", "\\\\", $ret);
}
function toCSymbolName($filename) {
# Google/Protobuf/BoolValue.php -> Google__Protobuf__BoolValue
$ret = stripSuffix($filename, ".php");
return str_replace("/", "__", $ret);
}
$f = fopen($output, "w");
fwrite($f, "#include \"bundled_php.h\"\n");
fwrite($f, "#include \"stdlib.h\"\n");
foreach ($filenames as $filename) {
print("Reading $filename...\n");
$contents = file_get_contents($filename);
$contents = substr($contents, 5); // Strip <?php
$c_symbol_name = toCSymbolName($filename);
fwrite($f, "static const char {$c_symbol_name}[] = {");
for ($i = 0; $i < strlen($contents); $i++) {
if ($i % 10 == 0) {
fwrite($f, "\n");
}
fprintf($f, " 0x%02x,", ord($contents[$i]));
}
fwrite($f, "0};\n");
}
fwrite($f, "static BundledPhp_File php[] = {\n");
foreach ($filenames as $filename) {
$class_name = toClassName($filename);
$c_symbol_name = toCSymbolName($filename);
fwrite($f, " {\"$class_name\", $c_symbol_name},\n");
}
fwrite($f, " {NULL, NULL}\n");
fwrite($f, "};\n");
fwrite($f, "BundledPhp_File *bundled_files = &php[0];\n");
fclose($f);
print("Wrote $output\n");
?>

@ -36,6 +36,7 @@
// This is not self-contained: it must be after other Zend includes. // This is not self-contained: it must be after other Zend includes.
#include <Zend/zend_exceptions.h> #include <Zend/zend_exceptions.h>
#include <Zend/zend_inheritance.h>
#include "arena.h" #include "arena.h"
#include "array.h" #include "array.h"
@ -108,6 +109,43 @@ static const upb_fielddef *get_field(Message *msg, PROTO_STR *member) {
return f; return f;
} }
static void Message_get(Message *intern, const upb_fielddef *f, zval *rv) {
upb_arena *arena = Arena_Get(&intern->arena);
if (upb_fielddef_ismap(f)) {
upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena);
} else if (upb_fielddef_isseq(f)) {
upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena);
} else {
upb_msgval msgval = upb_msg_get(intern->msg, f);
const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena);
}
}
static bool Message_set(Message *intern, const upb_fielddef *f, zval *val) {
upb_arena *arena = Arena_Get(&intern->arena);
upb_msgval msgval;
if (upb_fielddef_ismap(f)) {
msgval.map_val = MapField_GetUpbMap(val, f, arena);
if (!msgval.map_val) return false;
} else if (upb_fielddef_isseq(f)) {
msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
if (!msgval.array_val) return false;
} else {
upb_fieldtype_t type = upb_fielddef_type(f);
const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena);
if (!ok) return false;
}
upb_msg_set(intern->msg, f, msgval, arena);
return true;
}
static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m); static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m);
/** /**
@ -271,6 +309,7 @@ static void Message_unset_property(PROTO_VAL *obj, PROTO_STR *member,
upb_msg_clearfield(intern->msg, f); upb_msg_clearfield(intern->msg, f);
} }
/** /**
* Message_read_property() * Message_read_property()
* *
@ -293,22 +332,9 @@ static zval *Message_read_property(PROTO_VAL *obj, PROTO_STR *member,
int type, void **cache_slot, zval *rv) { int type, void **cache_slot, zval *rv) {
Message* intern = PROTO_MSG_P(obj); Message* intern = PROTO_MSG_P(obj);
const upb_fielddef *f = get_field(intern, member); const upb_fielddef *f = get_field(intern, member);
upb_arena *arena = Arena_Get(&intern->arena);
if (!f) return NULL; if (!f) return NULL;
Message_get(intern, f, rv);
if (upb_fielddef_ismap(f)) {
upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena);
} else if (upb_fielddef_isseq(f)) {
upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena);
} else {
upb_msgval msgval = upb_msg_get(intern->msg, f);
const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena);
}
return rv; return rv;
} }
@ -337,37 +363,20 @@ static PROTO_RETURN_VAL Message_write_property(
PROTO_VAL *obj, PROTO_STR *member, zval *val, void **cache_slot) { PROTO_VAL *obj, PROTO_STR *member, zval *val, void **cache_slot) {
Message* intern = PROTO_MSG_P(obj); Message* intern = PROTO_MSG_P(obj);
const upb_fielddef *f = get_field(intern, member); const upb_fielddef *f = get_field(intern, member);
upb_arena *arena = Arena_Get(&intern->arena);
upb_msgval msgval;
if (!f) goto error; if (f && Message_set(intern, f, val)) {
if (upb_fielddef_ismap(f)) {
msgval.map_val = MapField_GetUpbMap(val, f, arena);
if (!msgval.map_val) goto error;
} else if (upb_fielddef_isseq(f)) {
msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
if (!msgval.array_val) goto error;
} else {
upb_fieldtype_t type = upb_fielddef_type(f);
const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena);
if (!ok) goto error;
}
upb_msg_set(intern->msg, f, msgval, arena);
#if PHP_VERSION_ID < 704000 #if PHP_VERSION_ID < 704000
return; return;
#else #else
return val; return val;
#endif #endif
} else {
error:
#if PHP_VERSION_ID < 704000 #if PHP_VERSION_ID < 704000
return; return;
#else #else
return &EG(error_zval); return &EG(error_zval);
#endif #endif
}
} }
/** /**
@ -1009,6 +1018,151 @@ static zend_function_entry Message_methods[] = {
ZEND_FE_END ZEND_FE_END
}; };
// Well-known types ////////////////////////////////////////////////////////////
static const char TYPE_URL_PREFIX[] = "type.googleapis.com/";
static upb_msgval Message_getval(Message *intern, const char *field_name) {
const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef, field_name);
return upb_msg_get(intern->msg, f);
}
PHP_METHOD(google_protobuf_Any, unpack) {
Message* intern = (Message*)Z_OBJ_P(getThis());
upb_strview type_url = Message_getval(intern, "type_url").str_val;
upb_strview value = Message_getval(intern, "value").str_val;
size_t prefix_len = strlen(TYPE_URL_PREFIX);
upb_symtab *symtab = DescriptorPool_GetSymbolTable();
const upb_msgdef *m;
Descriptor *desc;
zend_class_entry *klass;
zval ret;
// Ensure that type_url has TYPE_URL_PREFIX as a prefix.
if (type_url.size < prefix_len ||
strncmp(TYPE_URL_PREFIX, type_url.data, prefix_len) != 0) {
zend_throw_exception(
NULL, "Type url needs to be type.googleapis.com/fully-qualified",
0 TSRMLS_CC);
return;
}
type_url.size -= prefix_len;
type_url.data += prefix_len;
m = upb_symtab_lookupmsg2(symtab, type_url.data, type_url.size);
if (m == NULL) {
zend_throw_exception(
NULL, "Specified message in any hasn't been added to descriptor pool",
0 TSRMLS_CC);
return;
}
desc = Descriptor_GetFromMessageDef(m);
klass = desc->class_entry;
ZVAL_OBJ(&ret, klass->create_object(klass));
Message *msg = (Message*)Z_OBJ_P(&ret);
// Get value.
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");
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);
}
/*
PHP_METHOD(Any, pack) {
zval* val;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &val) ==
FAILURE) {
return;
}
if (!instanceof_function(Z_OBJCE_P(val), message_ce)) {
zend_error(E_USER_ERROR, "Given value is not an instance of Message.");
return;
}
// Set value by serialized data.
zval data;
serialize_to_string(val, &data TSRMLS_CC);
zval member;
PHP_PROTO_ZVAL_STRING(&member, "value", 1);
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
message_handlers->write_property(getThis(), &member, &data,
NULL PHP_PROTO_TSRMLS_CC);
zval_dtor(&data);
zval_dtor(&member);
PHP_PROTO_FAKE_SCOPE_END;
// Set type url.
DescriptorInternal* desc = get_ce_desc(Z_OBJCE_P(val));
const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef);
size_t type_url_len =
strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1;
char* type_url = ALLOC_N(char, type_url_len);
sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name);
zval type_url_php;
PHP_PROTO_ZVAL_STRING(&type_url_php, type_url, 1);
PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
PHP_PROTO_FAKE_SCOPE_RESTART(any_type);
message_handlers->write_property(getThis(), &member, &type_url_php,
NULL PHP_PROTO_TSRMLS_CC);
zval_dtor(&type_url_php);
zval_dtor(&member);
PHP_PROTO_FAKE_SCOPE_END;
FREE(type_url);
}
PHP_METHOD(Any, is) {
zend_class_entry *klass = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &klass) ==
FAILURE) {
return;
}
DescriptorInternal* desc = get_ce_desc(klass);
if (desc == NULL) {
RETURN_BOOL(false);
}
// Create corresponded type url.
const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef);
size_t type_url_len =
strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1;
char* type_url = ALLOC_N(char, type_url_len);
sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name);
// Fetch stored type url.
zval member;
PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
zval* value =
php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC);
zval_dtor(&member);
PHP_PROTO_FAKE_SCOPE_END;
// Compare two type url.
bool is = strcmp(type_url, Z_STRVAL_P(value)) == 0;
FREE(type_url);
RETURN_BOOL(is);
}
*/
#include "wkt.inc"
/** /**
* Message_ModuleInit() * Message_ModuleInit()
* *
@ -1033,4 +1187,6 @@ void Message_ModuleInit() {
h->unset_property = Message_unset_property; h->unset_property = Message_unset_property;
h->get_properties = Message_get_properties; h->get_properties = Message_get_properties;
h->get_property_ptr_ptr = Message_get_property_ptr_ptr; h->get_property_ptr_ptr = Message_get_property_ptr_ptr;
WellKnownTypes_ModuleInit(); /* From wkt.inc. */
} }

@ -81,6 +81,10 @@
#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
#define UPB_NOINLINE __attribute__((noinline)) #define UPB_NOINLINE __attribute__((noinline))
#define UPB_NORETURN __attribute__((__noreturn__)) #define UPB_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER)
#define UPB_NOINLINE
#define UPB_FORCEINLINE
#define UPB_NORETURN __declspec(noreturn)
#else /* !defined(__GNUC__) */ #else /* !defined(__GNUC__) */
#define UPB_FORCEINLINE #define UPB_FORCEINLINE
#define UPB_NOINLINE #define UPB_NOINLINE
@ -143,7 +147,7 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
#elif defined _MSC_VER #elif defined _MSC_VER
#define UPB_ASSUME(expr) if (!(expr)) __assume(0) #define UPB_ASSUME(expr) if (!(expr)) __assume(0)
#else #else
#define UPB_ASSUME(expr) do {} if (false && (expr)) #define UPB_ASSUME(expr) do {} while (false && (expr))
#endif #endif
#else #else
#define UPB_ASSUME(expr) assert(expr) #define UPB_ASSUME(expr) assert(expr)
@ -323,8 +327,6 @@ typedef struct {
typedef union { typedef union {
bool bool_val; bool bool_val;
int32_t int32_val;
int64_t int64_val;
uint32_t uint32_val; uint32_t uint32_val;
uint64_t uint64_val; uint64_t uint64_val;
upb_strview str_val; upb_strview str_val;
@ -424,14 +426,21 @@ static void decode_munge(int type, wireval *val) {
break; break;
case UPB_DESCRIPTOR_TYPE_SINT32: { case UPB_DESCRIPTOR_TYPE_SINT32: {
uint32_t n = val->uint32_val; uint32_t n = val->uint32_val;
val->int32_val = (n >> 1) ^ -(int32_t)(n & 1); val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1);
break; break;
} }
case UPB_DESCRIPTOR_TYPE_SINT64: { case UPB_DESCRIPTOR_TYPE_SINT64: {
uint64_t n = val->uint64_val; uint64_t n = val->uint64_val;
val->int64_val = (n >> 1) ^ -(int64_t)(n & 1); val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1);
break; break;
} }
case UPB_DESCRIPTOR_TYPE_INT32:
case UPB_DESCRIPTOR_TYPE_UINT32:
if (!_upb_isle()) {
/* The next stage will memcpy(dst, &val, 4) */
val->uint32_val = val->uint64_val;
}
break;
} }
} }
@ -607,7 +616,7 @@ static void decode_tomap(upb_decstate *d, upb_msg *msg,
if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE ||
entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) { entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) {
/* Create proactively to handle the case where it doesn't appear. */ /* Create proactively to handle the case where it doesn't appear. */
ent.v.val.val = (uint64_t)_upb_msg_new(entry->submsgs[0], d->arena); ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], d->arena));
} }
decode_tosubmsg(d, &ent.k, layout, field, val.str_val); decode_tosubmsg(d, &ent.k, layout, field, val.str_val);
@ -698,14 +707,16 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
break; break;
case UPB_WIRE_TYPE_32BIT: case UPB_WIRE_TYPE_32BIT:
if (d->limit - ptr < 4) decode_err(d); if (d->limit - ptr < 4) decode_err(d);
memcpy(&val, ptr, 4); memcpy(&val.uint32_val, ptr, 4);
val.uint32_val = _upb_be_swap32(val.uint32_val);
ptr += 4; ptr += 4;
op = OP_SCALAR_LG2(2); op = OP_SCALAR_LG2(2);
if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown; if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown;
break; break;
case UPB_WIRE_TYPE_64BIT: case UPB_WIRE_TYPE_64BIT:
if (d->limit - ptr < 8) decode_err(d); if (d->limit - ptr < 8) decode_err(d);
memcpy(&val, ptr, 8); memcpy(&val.uint64_val, ptr, 8);
val.uint64_val = _upb_be_swap64(val.uint64_val);
ptr += 8; ptr += 8;
op = OP_SCALAR_LG2(3); op = OP_SCALAR_LG2(3);
if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown; if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown;
@ -725,7 +736,7 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
break; break;
} }
case UPB_WIRE_TYPE_START_GROUP: case UPB_WIRE_TYPE_START_GROUP:
val.int32_val = field_number; val.uint32_val = field_number;
op = OP_SUBMSG; op = OP_SUBMSG;
if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown; if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown;
break; break;
@ -794,30 +805,30 @@ bool upb_decode(const char *buf, size_t size, void *msg, const upb_msglayout *l,
/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ /* We encode backwards, to avoid pre-computing lengths (one-pass encode). */
#include <setjmp.h>
#include <string.h> #include <string.h>
#define UPB_PB_VARINT_MAX_LEN 10 #define UPB_PB_VARINT_MAX_LEN 10
#define CHK(x) do { if (!(x)) { return false; } } while(0)
static size_t upb_encode_varint(uint64_t val, char *buf) { UPB_NOINLINE
size_t i; static size_t encode_varint64(uint64_t val, char *buf) {
if (val < 128) { buf[0] = val; return 1; } size_t i = 0;
i = 0; do {
while (val) {
uint8_t byte = val & 0x7fU; uint8_t byte = val & 0x7fU;
val >>= 7; val >>= 7;
if (val) byte |= 0x80U; if (val) byte |= 0x80U;
buf[i++] = byte; buf[i++] = byte;
} } while (val);
return i; return i;
} }
static uint32_t upb_zzencode_32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); } static uint32_t encode_zz32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); }
static uint64_t upb_zzencode_64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); } static uint64_t encode_zz64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); }
typedef struct { typedef struct {
jmp_buf err;
upb_alloc *alloc; upb_alloc *alloc;
char *buf, *ptr, *limit; char *buf, *ptr, *limit;
} upb_encstate; } upb_encstate;
@ -830,11 +841,15 @@ static size_t upb_roundup_pow2(size_t bytes) {
return ret; return ret;
} }
static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) { UPB_NORETURN static void encode_err(upb_encstate *e) { longjmp(e->err, 1); }
UPB_NOINLINE
static void encode_growbuffer(upb_encstate *e, size_t bytes) {
size_t old_size = e->limit - e->buf; size_t old_size = e->limit - e->buf;
size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size);
CHK(new_buf);
if (!new_buf) encode_err(e);
/* We want previous data at the end, realloc() put it at the beginning. */ /* We want previous data at the end, realloc() put it at the beginning. */
if (old_size > 0) { if (old_size > 0) {
@ -844,99 +859,115 @@ static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) {
e->ptr = new_buf + new_size - (e->limit - e->ptr); e->ptr = new_buf + new_size - (e->limit - e->ptr);
e->limit = new_buf + new_size; e->limit = new_buf + new_size;
e->buf = new_buf; e->buf = new_buf;
return true;
e->ptr -= bytes;
} }
/* Call to ensure that at least "bytes" bytes are available for writing at /* Call to ensure that at least "bytes" bytes are available for writing at
* e->ptr. Returns false if the bytes could not be allocated. */ * e->ptr. Returns false if the bytes could not be allocated. */
static bool upb_encode_reserve(upb_encstate *e, size_t bytes) { UPB_FORCEINLINE
CHK(UPB_LIKELY((size_t)(e->ptr - e->buf) >= bytes) || static void encode_reserve(upb_encstate *e, size_t bytes) {
upb_encode_growbuffer(e, bytes)); if ((size_t)(e->ptr - e->buf) < bytes) {
encode_growbuffer(e, bytes);
return;
}
e->ptr -= bytes; e->ptr -= bytes;
return true;
} }
/* Writes the given bytes to the buffer, handling reserve/advance. */ /* Writes the given bytes to the buffer, handling reserve/advance. */
static bool upb_put_bytes(upb_encstate *e, const void *data, size_t len) { static void encode_bytes(upb_encstate *e, const void *data, size_t len) {
if (len == 0) return true; if (len == 0) return; /* memcpy() with zero size is UB */
CHK(upb_encode_reserve(e, len)); encode_reserve(e, len);
memcpy(e->ptr, data, len); memcpy(e->ptr, data, len);
return true;
} }
static bool upb_put_fixed64(upb_encstate *e, uint64_t val) { static void encode_fixed64(upb_encstate *e, uint64_t val) {
/* TODO(haberman): byte-swap for big endian. */ val = _upb_be_swap64(val);
return upb_put_bytes(e, &val, sizeof(uint64_t)); encode_bytes(e, &val, sizeof(uint64_t));
} }
static bool upb_put_fixed32(upb_encstate *e, uint32_t val) { static void encode_fixed32(upb_encstate *e, uint32_t val) {
/* TODO(haberman): byte-swap for big endian. */ val = _upb_be_swap32(val);
return upb_put_bytes(e, &val, sizeof(uint32_t)); encode_bytes(e, &val, sizeof(uint32_t));
} }
static bool upb_put_varint(upb_encstate *e, uint64_t val) { UPB_NOINLINE
static void encode_longvarint(upb_encstate *e, uint64_t val) {
size_t len; size_t len;
char *start; char *start;
CHK(upb_encode_reserve(e, UPB_PB_VARINT_MAX_LEN));
len = upb_encode_varint(val, e->ptr); encode_reserve(e, UPB_PB_VARINT_MAX_LEN);
len = encode_varint64(val, e->ptr);
start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; start = e->ptr + UPB_PB_VARINT_MAX_LEN - len;
memmove(start, e->ptr, len); memmove(start, e->ptr, len);
e->ptr = start; e->ptr = start;
return true;
} }
static bool upb_put_double(upb_encstate *e, double d) { UPB_FORCEINLINE
static void encode_varint(upb_encstate *e, uint64_t val) {
if (val < 128 && e->ptr != e->buf) {
--e->ptr;
*e->ptr = val;
} else {
encode_longvarint(e, val);
}
}
static void encode_double(upb_encstate *e, double d) {
uint64_t u64; uint64_t u64;
UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); UPB_ASSERT(sizeof(double) == sizeof(uint64_t));
memcpy(&u64, &d, sizeof(uint64_t)); memcpy(&u64, &d, sizeof(uint64_t));
return upb_put_fixed64(e, u64); encode_fixed64(e, u64);
} }
static bool upb_put_float(upb_encstate *e, float d) { static void encode_float(upb_encstate *e, float d) {
uint32_t u32; uint32_t u32;
UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); UPB_ASSERT(sizeof(float) == sizeof(uint32_t));
memcpy(&u32, &d, sizeof(uint32_t)); memcpy(&u32, &d, sizeof(uint32_t));
return upb_put_fixed32(e, u32); encode_fixed32(e, u32);
} }
static bool upb_put_tag(upb_encstate *e, int field_number, int wire_type) { static void encode_tag(upb_encstate *e, int field_number, int wire_type) {
return upb_put_varint(e, (field_number << 3) | wire_type); encode_varint(e, (field_number << 3) | wire_type);
} }
static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr, static void encode_fixedarray(upb_encstate *e, const upb_array *arr,
size_t elem_size, uint32_t tag) { size_t elem_size, uint32_t tag) {
size_t bytes = arr->len * elem_size; size_t bytes = arr->len * elem_size;
const char* data = _upb_array_constptr(arr); const char* data = _upb_array_constptr(arr);
const char* ptr = data + bytes - elem_size; const char* ptr = data + bytes - elem_size;
if (tag) { if (tag) {
while (true) { while (true) {
CHK(upb_put_bytes(e, ptr, elem_size) && upb_put_varint(e, tag)); encode_bytes(e, ptr, elem_size);
encode_varint(e, tag);
if (ptr == data) break; if (ptr == data) break;
ptr -= elem_size; ptr -= elem_size;
} }
return true;
} else { } else {
return upb_put_bytes(e, data, bytes) && upb_put_varint(e, bytes); encode_bytes(e, data, bytes);
} }
} }
bool upb_encode_message(upb_encstate *e, const char *msg, static void encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size); const upb_msglayout *m, size_t *size);
static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem, static void encode_scalar(upb_encstate *e, const void *_field_mem,
const upb_msglayout *m, const upb_msglayout *m, const upb_msglayout_field *f,
const upb_msglayout_field *f, bool skip_zero_value) {
bool skip_zero_value) {
const char *field_mem = _field_mem; const char *field_mem = _field_mem;
#define CASE(ctype, type, wire_type, encodeval) do { \ int wire_type;
ctype val = *(ctype*)field_mem; \
if (skip_zero_value && val == 0) { \ #define CASE(ctype, type, wtype, encodeval) \
return true; \ { \
} \ ctype val = *(ctype *)field_mem; \
return upb_put_ ## type(e, encodeval) && \ if (skip_zero_value && val == 0) { \
upb_put_tag(e, f->number, wire_type); \ return; \
} while(0) } \
encode_##type(e, encodeval); \
wire_type = wtype; \
break; \
}
switch (f->descriptortype) { switch (f->descriptortype) {
case UPB_DESCRIPTOR_TYPE_DOUBLE: case UPB_DESCRIPTOR_TYPE_DOUBLE:
@ -960,90 +991,91 @@ static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem,
case UPB_DESCRIPTOR_TYPE_BOOL: case UPB_DESCRIPTOR_TYPE_BOOL:
CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val); CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_SINT32: case UPB_DESCRIPTOR_TYPE_SINT32:
CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val)); CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz32(val));
case UPB_DESCRIPTOR_TYPE_SINT64: case UPB_DESCRIPTOR_TYPE_SINT64:
CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val)); CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz64(val));
case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_DESCRIPTOR_TYPE_BYTES: { case UPB_DESCRIPTOR_TYPE_BYTES: {
upb_strview view = *(upb_strview*)field_mem; upb_strview view = *(upb_strview*)field_mem;
if (skip_zero_value && view.size == 0) { if (skip_zero_value && view.size == 0) {
return true; return;
} }
return upb_put_bytes(e, view.data, view.size) && encode_bytes(e, view.data, view.size);
upb_put_varint(e, view.size) && encode_varint(e, view.size);
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); wire_type = UPB_WIRE_TYPE_DELIMITED;
break;
} }
case UPB_DESCRIPTOR_TYPE_GROUP: { case UPB_DESCRIPTOR_TYPE_GROUP: {
size_t size; size_t size;
void *submsg = *(void **)field_mem; void *submsg = *(void **)field_mem;
const upb_msglayout *subm = m->submsgs[f->submsg_index]; const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (submsg == NULL) { if (submsg == NULL) {
return true; return;
} }
return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
upb_encode_message(e, submsg, subm, &size) && encode_message(e, submsg, subm, &size);
upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP); wire_type = UPB_WIRE_TYPE_START_GROUP;
break;
} }
case UPB_DESCRIPTOR_TYPE_MESSAGE: { case UPB_DESCRIPTOR_TYPE_MESSAGE: {
size_t size; size_t size;
void *submsg = *(void **)field_mem; void *submsg = *(void **)field_mem;
const upb_msglayout *subm = m->submsgs[f->submsg_index]; const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (submsg == NULL) { if (submsg == NULL) {
return true; return;
} }
return upb_encode_message(e, submsg, subm, &size) && encode_message(e, submsg, subm, &size);
upb_put_varint(e, size) && encode_varint(e, size);
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); wire_type = UPB_WIRE_TYPE_DELIMITED;
break;
} }
default:
UPB_UNREACHABLE();
} }
#undef CASE #undef CASE
UPB_UNREACHABLE();
encode_tag(e, f->number, wire_type);
} }
static bool upb_encode_array(upb_encstate *e, const char *field_mem, static void encode_array(upb_encstate *e, const char *field_mem,
const upb_msglayout *m, const upb_msglayout *m, const upb_msglayout_field *f) {
const upb_msglayout_field *f) {
const upb_array *arr = *(const upb_array**)field_mem; const upb_array *arr = *(const upb_array**)field_mem;
bool packed = f->label == _UPB_LABEL_PACKED; bool packed = f->label == _UPB_LABEL_PACKED;
size_t pre_len = e->limit - e->ptr;
if (arr == NULL || arr->len == 0) { if (arr == NULL || arr->len == 0) {
return true; return;
} }
#define VARINT_CASE(ctype, encode) \ #define VARINT_CASE(ctype, encode) \
{ \ { \
const ctype *start = _upb_array_constptr(arr); \ const ctype *start = _upb_array_constptr(arr); \
const ctype *ptr = start + arr->len; \ const ctype *ptr = start + arr->len; \
size_t pre_len = e->limit - e->ptr; \
uint32_t tag = packed ? 0 : (f->number << 3) | UPB_WIRE_TYPE_VARINT; \ uint32_t tag = packed ? 0 : (f->number << 3) | UPB_WIRE_TYPE_VARINT; \
do { \ do { \
ptr--; \ ptr--; \
CHK(upb_put_varint(e, encode)); \ encode_varint(e, encode); \
if (tag) CHK(upb_put_varint(e, tag)); \ if (tag) encode_varint(e, tag); \
} while (ptr != start); \ } while (ptr != start); \
if (!tag) CHK(upb_put_varint(e, e->limit - e->ptr - pre_len)); \
} \ } \
break; \ break;
do { \
; \
} while (0)
#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) #define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type))
switch (f->descriptortype) { switch (f->descriptortype) {
case UPB_DESCRIPTOR_TYPE_DOUBLE: case UPB_DESCRIPTOR_TYPE_DOUBLE:
CHK(upb_put_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT))); encode_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT));
break; break;
case UPB_DESCRIPTOR_TYPE_FLOAT: case UPB_DESCRIPTOR_TYPE_FLOAT:
CHK(upb_put_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT))); encode_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT));
break; break;
case UPB_DESCRIPTOR_TYPE_SFIXED64: case UPB_DESCRIPTOR_TYPE_SFIXED64:
case UPB_DESCRIPTOR_TYPE_FIXED64: case UPB_DESCRIPTOR_TYPE_FIXED64:
CHK(upb_put_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT))); encode_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT));
break; break;
case UPB_DESCRIPTOR_TYPE_FIXED32: case UPB_DESCRIPTOR_TYPE_FIXED32:
case UPB_DESCRIPTOR_TYPE_SFIXED32: case UPB_DESCRIPTOR_TYPE_SFIXED32:
CHK(upb_put_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT))); encode_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT));
break; break;
case UPB_DESCRIPTOR_TYPE_INT64: case UPB_DESCRIPTOR_TYPE_INT64:
case UPB_DESCRIPTOR_TYPE_UINT64: case UPB_DESCRIPTOR_TYPE_UINT64:
@ -1056,20 +1088,20 @@ static bool upb_encode_array(upb_encstate *e, const char *field_mem,
case UPB_DESCRIPTOR_TYPE_BOOL: case UPB_DESCRIPTOR_TYPE_BOOL:
VARINT_CASE(bool, *ptr); VARINT_CASE(bool, *ptr);
case UPB_DESCRIPTOR_TYPE_SINT32: case UPB_DESCRIPTOR_TYPE_SINT32:
VARINT_CASE(int32_t, upb_zzencode_32(*ptr)); VARINT_CASE(int32_t, encode_zz32(*ptr));
case UPB_DESCRIPTOR_TYPE_SINT64: case UPB_DESCRIPTOR_TYPE_SINT64:
VARINT_CASE(int64_t, upb_zzencode_64(*ptr)); VARINT_CASE(int64_t, encode_zz64(*ptr));
case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_DESCRIPTOR_TYPE_BYTES: { case UPB_DESCRIPTOR_TYPE_BYTES: {
const upb_strview *start = _upb_array_constptr(arr); const upb_strview *start = _upb_array_constptr(arr);
const upb_strview *ptr = start + arr->len; const upb_strview *ptr = start + arr->len;
do { do {
ptr--; ptr--;
CHK(upb_put_bytes(e, ptr->data, ptr->size) && encode_bytes(e, ptr->data, ptr->size);
upb_put_varint(e, ptr->size) && encode_varint(e, ptr->size);
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
} while (ptr != start); } while (ptr != start);
return true; return;
} }
case UPB_DESCRIPTOR_TYPE_GROUP: { case UPB_DESCRIPTOR_TYPE_GROUP: {
const void *const*start = _upb_array_constptr(arr); const void *const*start = _upb_array_constptr(arr);
@ -1078,11 +1110,11 @@ static bool upb_encode_array(upb_encstate *e, const char *field_mem,
do { do {
size_t size; size_t size;
ptr--; ptr--;
CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
upb_encode_message(e, *ptr, subm, &size) && encode_message(e, *ptr, subm, &size);
upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP)); encode_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
} while (ptr != start); } while (ptr != start);
return true; return;
} }
case UPB_DESCRIPTOR_TYPE_MESSAGE: { case UPB_DESCRIPTOR_TYPE_MESSAGE: {
const void *const*start = _upb_array_constptr(arr); const void *const*start = _upb_array_constptr(arr);
@ -1091,31 +1123,30 @@ static bool upb_encode_array(upb_encstate *e, const char *field_mem,
do { do {
size_t size; size_t size;
ptr--; ptr--;
CHK(upb_encode_message(e, *ptr, subm, &size) && encode_message(e, *ptr, subm, &size);
upb_put_varint(e, size) && encode_varint(e, size);
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
} while (ptr != start); } while (ptr != start);
return true; return;
} }
} }
#undef VARINT_CASE #undef VARINT_CASE
if (packed) { if (packed) {
CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); encode_varint(e, e->limit - e->ptr - pre_len);
encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
} }
return true;
} }
static bool upb_encode_map(upb_encstate *e, const char *field_mem, static void encode_map(upb_encstate *e, const char *field_mem,
const upb_msglayout *m, const upb_msglayout *m, const upb_msglayout_field *f) {
const upb_msglayout_field *f) {
const upb_map *map = *(const upb_map**)field_mem; const upb_map *map = *(const upb_map**)field_mem;
const upb_msglayout *entry = m->submsgs[f->submsg_index]; const upb_msglayout *entry = m->submsgs[f->submsg_index];
const upb_msglayout_field *key_field = &entry->fields[0]; const upb_msglayout_field *key_field = &entry->fields[0];
const upb_msglayout_field *val_field = &entry->fields[1]; const upb_msglayout_field *val_field = &entry->fields[1];
upb_strtable_iter i; upb_strtable_iter i;
if (map == NULL) { if (map == NULL) {
return true; return;
} }
upb_strtable_begin(&i, &map->table); upb_strtable_begin(&i, &map->table);
@ -1127,59 +1158,57 @@ static bool upb_encode_map(upb_encstate *e, const char *field_mem,
upb_map_entry ent; upb_map_entry ent;
_upb_map_fromkey(key, &ent.k, map->key_size); _upb_map_fromkey(key, &ent.k, map->key_size);
_upb_map_fromvalue(val, &ent.v, map->val_size); _upb_map_fromvalue(val, &ent.v, map->val_size);
CHK(upb_encode_scalarfield(e, &ent.v, entry, val_field, false)); encode_scalar(e, &ent.v, entry, val_field, false);
CHK(upb_encode_scalarfield(e, &ent.k, entry, key_field, false)); encode_scalar(e, &ent.k, entry, key_field, false);
size = (e->limit - e->ptr) - pre_len; size = (e->limit - e->ptr) - pre_len;
CHK(upb_put_varint(e, size)); encode_varint(e, size);
CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
} }
return true;
} }
static void encode_scalarfield(upb_encstate *e, const char *msg,
const upb_msglayout *m,
const upb_msglayout_field *f) {
bool skip_empty = false;
if (f->presence == 0) {
/* Proto3 presence. */
skip_empty = true;
} else if (f->presence > 0) {
/* Proto2 presence: hasbit. */
if (!_upb_hasbit_field(msg, f)) return;
} else {
/* Field is in a oneof. */
if (_upb_getoneofcase_field(msg, f) != f->number) return;
}
encode_scalar(e, msg + f->offset, m, f, skip_empty);
}
bool upb_encode_message(upb_encstate *e, const char *msg, static void encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size) { const upb_msglayout *m, size_t *size) {
int i;
size_t pre_len = e->limit - e->ptr; size_t pre_len = e->limit - e->ptr;
const char *unknown; const char *unknown;
size_t unknown_size; size_t unknown_size;
const upb_msglayout_field *f = &m->fields[m->field_count];
const upb_msglayout_field *first = &m->fields[0];
unknown = upb_msg_getunknown(msg, &unknown_size); unknown = upb_msg_getunknown(msg, &unknown_size);
if (unknown) { if (unknown) {
upb_put_bytes(e, unknown, unknown_size); encode_bytes(e, unknown, unknown_size);
} }
for (i = m->field_count - 1; i >= 0; i--) { while (f != first) {
const upb_msglayout_field *f = &m->fields[i]; f--;
if (_upb_isrepeated(f)) { if (_upb_isrepeated(f)) {
CHK(upb_encode_array(e, msg + f->offset, m, f)); encode_array(e, msg + f->offset, m, f);
} else if (f->label == _UPB_LABEL_MAP) { } else if (f->label == _UPB_LABEL_MAP) {
CHK(upb_encode_map(e, msg + f->offset, m, f)); encode_map(e, msg + f->offset, m, f);
} else { } else {
bool skip_empty = false; encode_scalarfield(e, msg, m, f);
if (f->presence == 0) {
/* Proto3 presence. */
skip_empty = true;
} else if (f->presence > 0) {
/* Proto2 presence: hasbit. */
if (!_upb_hasbit_field(msg, f)) {
continue;
}
} else {
/* Field is in a oneof. */
if (_upb_getoneofcase_field(msg, f) != f->number) {
continue;
}
}
CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, skip_empty));
} }
} }
*size = (e->limit - e->ptr) - pre_len; *size = (e->limit - e->ptr) - pre_len;
return true;
} }
char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena, char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena,
@ -1190,11 +1219,13 @@ char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena,
e.limit = NULL; e.limit = NULL;
e.ptr = NULL; e.ptr = NULL;
if (!upb_encode_message(&e, msg, m, size)) { if (setjmp(e.err)) {
*size = 0; *size = 0;
return NULL; return NULL;
} }
encode_message(&e, msg, m, size);
*size = e.limit - e.ptr; *size = e.limit - e.ptr;
if (*size == 0) { if (*size == 0) {
@ -1206,8 +1237,6 @@ char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena,
} }
} }
#undef CHK
@ -3063,7 +3092,7 @@ extern const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit;
extern const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit; extern const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit;
extern const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit; extern const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit;
static const upb_msglayout *layouts[27] = { static const upb_msglayout *google_protobuf_descriptor_proto_layouts[27] = {
&google_protobuf_FileDescriptorSet_msginit, &google_protobuf_FileDescriptorSet_msginit,
&google_protobuf_FileDescriptorProto_msginit, &google_protobuf_FileDescriptorProto_msginit,
&google_protobuf_DescriptorProto_msginit, &google_protobuf_DescriptorProto_msginit,
@ -3093,7 +3122,8 @@ static const upb_msglayout *layouts[27] = {
&google_protobuf_GeneratedCodeInfo_Annotation_msginit, &google_protobuf_GeneratedCodeInfo_Annotation_msginit,
}; };
static const char descriptor[7619] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', static const char google_protobuf_descriptor_proto_descriptor[7619] = {
'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p',
't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\017', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\017', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u',
'f', '\"', 'M', '\n', '\021', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'S', 'e', 't', '\022', '8', '\n', 'f', '\"', 'M', '\n', '\021', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'S', 'e', 't', '\022', '8', '\n',
'\004', 'f', 'i', 'l', 'e', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', '\004', 'f', 'i', 'l', 'e', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't',
@ -3400,15 +3430,15 @@ static const char descriptor[7619] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '
'P', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n',
}; };
static upb_def_init *deps[1] = { static upb_def_init *google_protobuf_descriptor_proto_deps[1] = {
NULL NULL
}; };
upb_def_init google_protobuf_descriptor_proto_upbdefinit = { upb_def_init google_protobuf_descriptor_proto_definit = {
deps, google_protobuf_descriptor_proto_deps,
layouts, google_protobuf_descriptor_proto_layouts,
"google/protobuf/descriptor.proto", "google/protobuf/descriptor.proto",
UPB_STRVIEW_INIT(descriptor, 7619) UPB_STRVIEW_INIT(google_protobuf_descriptor_proto_descriptor, 7619)
}; };
@ -5666,11 +5696,7 @@ const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg,
if (upb_oneof_done(&i)) return false; if (upb_oneof_done(&i)) return false;
f = upb_oneof_iter_field(&i); f = upb_oneof_iter_field(&i);
field = upb_fielddef_layout(f); field = upb_fielddef_layout(f);
if (in_oneof(field)) { oneof_case = _upb_getoneofcase_field(msg, field);
oneof_case = _upb_getoneofcase_field(msg, field);
} else {
return _upb_hasbit_field(msg, field) ? f : NULL;
}
return oneof_case ? upb_msgdef_itof(m, oneof_case) : NULL; return oneof_case ? upb_msgdef_itof(m, oneof_case) : NULL;
} }

@ -80,6 +80,10 @@
#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
#define UPB_NOINLINE __attribute__((noinline)) #define UPB_NOINLINE __attribute__((noinline))
#define UPB_NORETURN __attribute__((__noreturn__)) #define UPB_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER)
#define UPB_NOINLINE
#define UPB_FORCEINLINE
#define UPB_NORETURN __declspec(noreturn)
#else /* !defined(__GNUC__) */ #else /* !defined(__GNUC__) */
#define UPB_FORCEINLINE #define UPB_FORCEINLINE
#define UPB_NOINLINE #define UPB_NOINLINE
@ -142,7 +146,7 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
#elif defined _MSC_VER #elif defined _MSC_VER
#define UPB_ASSUME(expr) if (!(expr)) __assume(0) #define UPB_ASSUME(expr) if (!(expr)) __assume(0)
#else #else
#define UPB_ASSUME(expr) do {} if (false && (expr)) #define UPB_ASSUME(expr) do {} while (false && (expr))
#endif #endif
#else #else
#define UPB_ASSUME(expr) assert(expr) #define UPB_ASSUME(expr) assert(expr)
@ -213,7 +217,7 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
** store pointers or integers of at least 32 bits (upb isn't really useful on ** store pointers or integers of at least 32 bits (upb isn't really useful on
** systems where sizeof(void*) < 4). ** systems where sizeof(void*) < 4).
** **
** The table must be homogeneous (all values of the same type). In debug ** The table must be homogenous (all values of the same type). In debug
** mode, we check this on insert and lookup. ** mode, we check this on insert and lookup.
*/ */
@ -496,6 +500,32 @@ typedef enum {
#define UPB_MAP_BEGIN ((size_t)-1) #define UPB_MAP_BEGIN ((size_t)-1)
UPB_INLINE bool _upb_isle(void) {
int x = 1;
return *(char*)&x == 1;
}
UPB_INLINE uint32_t _upb_be_swap32(uint32_t val) {
if (_upb_isle()) {
return val;
} else {
return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
((val & 0xff0000ULL) >> 8) | ((val & 0xff000000ULL) >> 24);
}
}
UPB_INLINE uint64_t _upb_be_swap64(uint64_t val) {
if (_upb_isle()) {
return val;
} else {
return ((val & 0xff) << 56) | ((val & 0xff00) << 40) |
((val & 0xff0000) << 24) | ((val & 0xff000000) << 8) |
((val & 0xff00000000ULL) >> 8) | ((val & 0xff0000000000ULL) >> 24) |
((val & 0xff000000000000ULL) >> 40) |
((val & 0xff00000000000000ULL) >> 56);
}
}
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
@ -1251,7 +1281,7 @@ UPB_INLINE upb_value _upb_map_tovalue(const void *val, size_t size,
if (size == UPB_MAPTYPE_STRING) { if (size == UPB_MAPTYPE_STRING) {
upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp)); upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp));
*strp = *(upb_strview*)val; *strp = *(upb_strview*)val;
memcpy(&ret, &strp, sizeof(strp)); ret = upb_value_ptr(strp);
} else { } else {
memcpy(&ret, val, size); memcpy(&ret, val, size);
} }
@ -1382,7 +1412,7 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size)
/* This is like _upb_map_tovalue() except the entry already exists so we can /* This is like _upb_map_tovalue() except the entry already exists so we can
* reuse the allocated upb_strview for string fields. */ * reuse the allocated upb_strview for string fields. */
if (size == UPB_MAPTYPE_STRING) { if (size == UPB_MAPTYPE_STRING) {
upb_strview *strp = (upb_strview*)ent->val.val; upb_strview *strp = (upb_strview*)(uintptr_t)ent->val.val;
memcpy(strp, val, sizeof(*strp)); memcpy(strp, val, sizeof(*strp));
} else { } else {
memcpy(&ent->val.val, val, size); memcpy(&ent->val.val, val, size);
@ -3489,140 +3519,140 @@ extern "C" {
extern upb_def_init google_protobuf_descriptor_proto_upbdefinit; extern upb_def_init google_protobuf_descriptor_proto_definit;
UPB_INLINE const upb_msgdef *google_protobuf_FileDescriptorSet_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_FileDescriptorSet_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorSet"); return upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorSet");
} }
UPB_INLINE const upb_msgdef *google_protobuf_FileDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_FileDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_DescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_DescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_DescriptorProto_ExtensionRange_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_DescriptorProto_ExtensionRange_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ExtensionRange"); return upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ExtensionRange");
} }
UPB_INLINE const upb_msgdef *google_protobuf_DescriptorProto_ReservedRange_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_DescriptorProto_ReservedRange_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ReservedRange"); return upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ReservedRange");
} }
UPB_INLINE const upb_msgdef *google_protobuf_ExtensionRangeOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_ExtensionRangeOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.ExtensionRangeOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.ExtensionRangeOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_FieldDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_FieldDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.FieldDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.FieldDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_OneofDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_OneofDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.OneofDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.OneofDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_EnumDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_EnumDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_EnumDescriptorProto_EnumReservedRange_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_EnumDescriptorProto_EnumReservedRange_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto.EnumReservedRange"); return upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto.EnumReservedRange");
} }
UPB_INLINE const upb_msgdef *google_protobuf_EnumValueDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_EnumValueDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.EnumValueDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.EnumValueDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_ServiceDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_ServiceDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.ServiceDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.ServiceDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_MethodDescriptorProto_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_MethodDescriptorProto_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.MethodDescriptorProto"); return upb_symtab_lookupmsg(s, "google.protobuf.MethodDescriptorProto");
} }
UPB_INLINE const upb_msgdef *google_protobuf_FileOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_FileOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.FileOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.FileOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_MessageOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_MessageOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.MessageOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.MessageOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_FieldOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_FieldOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.FieldOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.FieldOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_OneofOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_OneofOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.OneofOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.OneofOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_EnumOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_EnumOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.EnumOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.EnumOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_EnumValueOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_EnumValueOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.EnumValueOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.EnumValueOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_ServiceOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_ServiceOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.ServiceOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.ServiceOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_MethodOptions_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_MethodOptions_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.MethodOptions"); return upb_symtab_lookupmsg(s, "google.protobuf.MethodOptions");
} }
UPB_INLINE const upb_msgdef *google_protobuf_UninterpretedOption_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_UninterpretedOption_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption"); return upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption");
} }
UPB_INLINE const upb_msgdef *google_protobuf_UninterpretedOption_NamePart_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_UninterpretedOption_NamePart_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption.NamePart"); return upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption.NamePart");
} }
UPB_INLINE const upb_msgdef *google_protobuf_SourceCodeInfo_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_SourceCodeInfo_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo"); return upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo");
} }
UPB_INLINE const upb_msgdef *google_protobuf_SourceCodeInfo_Location_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_SourceCodeInfo_Location_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo.Location"); return upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo.Location");
} }
UPB_INLINE const upb_msgdef *google_protobuf_GeneratedCodeInfo_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_GeneratedCodeInfo_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.GeneratedCodeInfo"); return upb_symtab_lookupmsg(s, "google.protobuf.GeneratedCodeInfo");
} }
UPB_INLINE const upb_msgdef *google_protobuf_GeneratedCodeInfo_Annotation_getmsgdef(upb_symtab *s) { UPB_INLINE const upb_msgdef *google_protobuf_GeneratedCodeInfo_Annotation_getmsgdef(upb_symtab *s) {
_upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_upbdefinit); _upb_symtab_loaddefinit(s, &google_protobuf_descriptor_proto_definit);
return upb_symtab_lookupmsg(s, "google.protobuf.GeneratedCodeInfo.Annotation"); return upb_symtab_lookupmsg(s, "google.protobuf.GeneratedCodeInfo.Annotation");
} }
@ -3827,7 +3857,7 @@ extern "C" {
#endif #endif
enum { enum {
/* When set, emits 0/default values. TODO(haberman): proto3 only? */ /* When set, emits 0/default values. TOOD(haberman): proto3 only? */
UPB_JSONENC_EMITDEFAULTS = 1, UPB_JSONENC_EMITDEFAULTS = 1,
/* When set, use normal (snake_caes) field names instead of JSON (camelCase) /* When set, use normal (snake_caes) field names instead of JSON (camelCase)

@ -35,7 +35,6 @@
#include "arena.h" #include "arena.h"
#include "array.h" #include "array.h"
#include "bundled_php.h"
#include "convert.h" #include "convert.h"
#include "def.h" #include "def.h"
#include "map.h" #include "map.h"
@ -162,10 +161,6 @@ static PHP_RINIT_FUNCTION(protobuf) {
upb_symtab *symtab = PROTOBUF_G(saved_symtab); upb_symtab *symtab = PROTOBUF_G(saved_symtab);
DescriptorPool_CreateWithSymbolTable(&PROTOBUF_G(generated_pool), symtab); DescriptorPool_CreateWithSymbolTable(&PROTOBUF_G(generated_pool), symtab);
// Set up autoloader for bundled sources.
zend_eval_string("spl_autoload_register('protobuf_internal_loadbundled');",
NULL, "autoload_register.php");
zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0); 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_msg_cache), 64, NULL, NULL, 0);
zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0); zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0);
@ -193,34 +188,6 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) {
return SUCCESS; return SUCCESS;
} }
// -----------------------------------------------------------------------------
// Bundled PHP sources
// -----------------------------------------------------------------------------
// We bundle PHP sources for well-known types into the C extension. There is no
// need to implement these in C.
static PHP_FUNCTION(protobuf_internal_loadbundled) {
char *name = NULL;
zend_long size;
BundledPhp_File *file;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &size) != SUCCESS) {
return;
}
for (file = bundled_files; file->filename; file++) {
if (strcmp(file->filename, name) == 0) {
zend_eval_string((char*)file->contents, NULL, (char*)file->filename);
return;
}
}
}
ZEND_BEGIN_ARG_INFO_EX(arginfo_load_bundled_source, 0, 0, 1)
ZEND_ARG_INFO(0, class_name)
ZEND_END_ARG_INFO()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Object Cache. // Object Cache.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -303,7 +270,6 @@ const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
zend_function_entry protobuf_functions[] = { zend_function_entry protobuf_functions[] = {
PHP_FE(protobuf_internal_loadbundled, arginfo_load_bundled_source)
ZEND_FE_END ZEND_FE_END
}; };

File diff suppressed because it is too large Load Diff

@ -7,7 +7,6 @@ cd $(dirname $0)
pushd ../ext/google/protobuf pushd ../ext/google/protobuf
phpize --clean phpize --clean
rm -f configure.in configure.ac rm -f configure.in configure.ac
php make-preload.php
phpize phpize
if [ "$1" = "--release" ]; then if [ "$1" = "--release" ]; then
./configure --with-php-config=$(which php-config) ./configure --with-php-config=$(which php-config)

@ -81,6 +81,7 @@ namespace php {
struct Options { struct Options {
bool is_descriptor = false; bool is_descriptor = false;
bool aggregate_metadata = false; bool aggregate_metadata = false;
bool gen_c_wkt = false;
std::set<string> aggregate_metadata_prefixes; std::set<string> aggregate_metadata_prefixes;
}; };
@ -1791,7 +1792,7 @@ void GenerateEnumValueDocComment(io::Printer* printer,
} }
void GenerateServiceMethodDocComment(io::Printer* printer, void GenerateServiceMethodDocComment(io::Printer* printer,
const MethodDescriptor* method) { const MethodDescriptor* method) {
printer->Print("/**\n"); printer->Print("/**\n");
GenerateDocCommentBody(printer, method); GenerateDocCommentBody(printer, method);
printer->Print( printer->Print(
@ -1807,6 +1808,231 @@ void GenerateServiceMethodDocComment(io::Printer* printer,
"return_type", EscapePhpdoc(FullClassName(method->output_type(), false))); "return_type", EscapePhpdoc(FullClassName(method->output_type(), false)));
} }
std::string FilenameCName(const FileDescriptor* file) {
std::string c_name = file->name();
c_name = StringReplace(c_name, ".", "_", true);
c_name = StringReplace(c_name, "/", "_", true);
return c_name;
}
void GenerateCMessage(const Descriptor* message, io::Printer* printer) {
std::string c_name = message->full_name();
c_name = StringReplace(c_name, ".", "_", true);
std::string php_name = FullClassName(message, Options());
php_name = StringReplace(php_name, "\\", "\\\\", true);
printer->Print(
"/* $c_name$ */\n"
"\n"
"zend_class_entry* $c_name$_ce;\n"
"\n"
"static PHP_METHOD($c_name$, __construct) {\n"
" $file_c_name$_AddDescriptor();\n"
" zim_Message___construct(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n"
"}\n"
"\n",
"file_c_name", FilenameCName(message->file()),
"c_name", c_name);
for (int i = 0; i < message->field_count(); i++) {
auto field = message->field(i);
printer->Print(
"static PHP_METHOD($c_name$, get$camel_name$) {\n"
" Message* intern = (Message*)Z_OBJ_P(getThis());\n"
" const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef,\n"
" \"$name$\");\n"
" zval ret;\n"
" Message_get(intern, f, &ret);\n"
" RETURN_ZVAL(&ret, 1, 0);\n"
"}\n"
"\n"
"static PHP_METHOD($c_name$, set$camel_name$) {\n"
" Message* intern = (Message*)Z_OBJ_P(getThis());\n"
" const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef,\n"
" \"$name$\");\n"
" zval *val;\n"
" if (zend_parse_parameters(ZEND_NUM_ARGS(), \"z\", &val)\n"
" == FAILURE) {\n"
" return;\n"
" }\n"
" Message_set(intern, f, val);\n"
" RETURN_ZVAL(getThis(), 1, 0);\n"
"}\n"
"\n",
"c_name", c_name,
"name", field->name(),
"camel_name", UnderscoresToCamelCase(field->name(), true));
}
printer->Print(
"static zend_function_entry $c_name$_phpmethods[] = {\n"
" PHP_ME($c_name$, __construct, NULL, ZEND_ACC_PUBLIC)\n",
"c_name", c_name);
for (int i = 0; i < message->field_count(); i++) {
auto field = message->field(i);
printer->Print(
" PHP_ME($c_name$, get$camel_name$, NULL, ZEND_ACC_PUBLIC)\n"
" PHP_ME($c_name$, set$camel_name$, NULL, ZEND_ACC_PUBLIC)\n",
"c_name", c_name,
"camel_name", UnderscoresToCamelCase(field->name(), true));
}
if (message->well_known_type() == Descriptor::WELLKNOWNTYPE_ANY) {
printer->Print(
" PHP_ME($c_name$, unpack, NULL, ZEND_ACC_PUBLIC)\n",
"c_name", c_name);
}
printer->Print(
" ZEND_FE_END\n"
"};\n"
"\n"
"static void $c_name$_ModuleInit() {\n"
" zend_class_entry tmp_ce;\n"
"\n"
" INIT_CLASS_ENTRY(tmp_ce, \"$php_name$\",\n"
" $c_name$_phpmethods);\n"
"\n"
" $c_name$_ce = zend_register_internal_class(&tmp_ce);\n"
" $c_name$_ce->ce_flags |= ZEND_ACC_FINAL;\n"
" $c_name$_ce->create_object = Message_create;\n"
" zend_do_inheritance($c_name$_ce, message_ce);\n"
"}\n"
"\n",
"c_name", c_name,
"php_name", php_name);
for (int i = 0; i < message->nested_type_count(); i++) {
GenerateCMessage(message->nested_type(i), printer);
}
}
void GenerateCInit(const Descriptor* message, io::Printer* printer) {
std::string c_name = message->full_name();
c_name = StringReplace(c_name, ".", "_", true);
printer->Print(
" $c_name$_ModuleInit();\n",
"c_name", c_name);
for (int i = 0; i < message->nested_type_count(); i++) {
GenerateCInit(message->nested_type(i), printer);
}
}
void GenerateCWellKnownTypes(const std::vector<const FileDescriptor*>& files,
GeneratorContext* context) {
std::unique_ptr<io::ZeroCopyOutputStream> output(
context->Open("../ext/google/protobuf/wkt.inc"));
io::Printer printer(output.get(), '$');
printer.Print(
"// This file is generated from the .proto files for the well-known\n"
"// types. Do not edit!\n");
for (auto file : files) {
printer.Print(
"static void $c_name$_AddDescriptor();\n",
"c_name", FilenameCName(file));
}
for (auto file : files) {
std::string c_name = FilenameCName(file);
std::string metadata_filename = GeneratedMetadataFileName(file, Options());
std::string metadata_classname = FilenameToClassname(metadata_filename);
std::string metadata_c_name =
StringReplace(metadata_classname, "\\", "_", true);
metadata_classname = StringReplace(metadata_classname, "\\", "\\\\", true);
FileDescriptorProto file_proto;
file->CopyTo(&file_proto);
std::string serialized;
file_proto.SerializeToString(&serialized);
printer.Print(
"/* $filename$ */\n"
"\n"
"zend_class_entry* $metadata_c_name$_ce;\n"
"\n"
"const char $c_name$_descriptor [$size$] = {\n",
"filename", file->name(),
"c_name", c_name,
"metadata_c_name", metadata_c_name,
"size", std::to_string(serialized.size()));
for (size_t i = 0; i < serialized.size();) {
for (size_t j = 0; j < 25 && i < serialized.size(); ++i, ++j) {
printer.Print("'$ch$', ", "ch", CEscape(serialized.substr(i, 1)));
}
printer.Print("\n");
}
printer.Print(
"};\n"
"\n"
"static void $c_name$_AddDescriptor() {\n"
" if (DescriptorPool_HasFile(\"$filename$\")) return;\n",
"filename", file->name(),
"c_name", c_name,
"metadata_c_name", metadata_c_name);
for (int i = 0; i < file->dependency_count(); i++) {
std::string dep_c_name = FilenameCName(file->dependency(i));
printer.Print(
" $dep_c_name$_AddDescriptor();\n",
"dep_c_name", dep_c_name);
}
printer.Print(
" DescriptorPool_AddDescriptor(\"$filename$\", $c_name$_descriptor,\n"
" sizeof($c_name$_descriptor));\n"
"}\n"
"\n"
"static PHP_METHOD($metadata_c_name$, initOnce) {\n"
" $c_name$_AddDescriptor();\n"
"}\n"
"\n"
"static zend_function_entry $metadata_c_name$_methods[] = {\n"
" PHP_ME($metadata_c_name$, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n"
" ZEND_FE_END\n"
"};\n"
"\n"
"static void $metadata_c_name$_ModuleInit() {\n"
" zend_class_entry tmp_ce;\n"
"\n"
" INIT_CLASS_ENTRY(tmp_ce, \"$metadata_classname$\",\n"
" $metadata_c_name$_methods);\n"
"\n"
" $metadata_c_name$_ce = zend_register_internal_class(&tmp_ce);\n"
"}\n"
"\n",
"filename", file->name(),
"c_name", c_name,
"metadata_c_name", metadata_c_name,
"metadata_classname", metadata_classname);
for (int i = 0; i < file->message_type_count(); i++) {
GenerateCMessage(file->message_type(i), &printer);
}
}
printer.Print(
"static void WellKnownTypes_ModuleInit() {\n");
for (auto file : files) {
std::string metadata_filename = GeneratedMetadataFileName(file, Options());
std::string metadata_classname = FilenameToClassname(metadata_filename);
std::string metadata_c_name =
StringReplace(metadata_classname, "\\", "_", true);
printer.Print(
" $metadata_c_name$_ModuleInit();\n",
"metadata_c_name", metadata_c_name);
for (int i = 0; i < file->message_type_count(); i++) {
GenerateCInit(file->message_type(i), &printer);
}
}
printer.Print(
"}\n");
}
} // namespace } // namespace
bool Generator::Generate(const FileDescriptor* file, const string& parameter, bool Generator::Generate(const FileDescriptor* file, const string& parameter,
@ -1850,9 +2076,12 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
options.aggregate_metadata_prefixes.insert(prefix); options.aggregate_metadata_prefixes.insert(prefix);
GOOGLE_LOG(INFO) << prefix; GOOGLE_LOG(INFO) << prefix;
} }
} } else if (option_pair[0] == "internal") {
if (option_pair[0] == "internal") {
options.is_descriptor = true; options.is_descriptor = true;
} else if (option_pair[0] == "internal_generate_c_wkt") {
GenerateCWellKnownTypes(files, generator_context);
} else {
GOOGLE_LOG(FATAL) << "Unknown codegen option: " << option_pair[0];
} }
} }
@ -1861,6 +2090,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
return false; return false;
} }
} }
return true; return true;
} }

Loading…
Cancel
Save