From 0c64c4b594b5ee0a2ab87d955bfd0fe0d746da9d Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 28 Mar 2019 13:51:23 -0700 Subject: [PATCH 01/35] WIP. --- upb/legacy_msg_reflection.c | 9 --------- upb/legacy_msg_reflection.h | 3 --- upb/msg.h | 15 +++++++++++++++ upbc/generator.cc | 15 +++++++++++++-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/upb/legacy_msg_reflection.c b/upb/legacy_msg_reflection.c index 0683dde545..af788dd132 100644 --- a/upb/legacy_msg_reflection.c +++ b/upb/legacy_msg_reflection.c @@ -211,15 +211,6 @@ bool upb_array_set(upb_array *arr, size_t i, upb_msgval val) { /** upb_map *******************************************************************/ -struct upb_map { - upb_fieldtype_t key_type; - upb_fieldtype_t val_type; - /* We may want to optimize this to use inttable where possible, for greater - * efficiency and lower memory footprint. */ - upb_strtable strtab; - upb_arena *arena; -}; - static void upb_map_tokey(upb_fieldtype_t type, upb_msgval *key, const char **out_key, size_t *out_len) { switch (type) { diff --git a/upb/legacy_msg_reflection.h b/upb/legacy_msg_reflection.h index 32a621b4b7..7c7c2cc687 100644 --- a/upb/legacy_msg_reflection.h +++ b/upb/legacy_msg_reflection.h @@ -7,9 +7,6 @@ #include "upb/port_def.inc" -struct upb_map; -typedef struct upb_map upb_map; - struct upb_mapiter; typedef struct upb_mapiter upb_mapiter; diff --git a/upb/msg.h b/upb/msg.h index e46733f4f6..8394d6f0fd 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -11,6 +11,8 @@ #include #include + +#include "upb/table.int.h" #include "upb/upb.h" #ifdef __cplusplus @@ -55,6 +57,19 @@ typedef struct { upb_arena *arena; } upb_array; +/* Our internal representation for maps. */ +typedef struct { + /* First element must be upb_array so code like parser/serializer can treat + * map fields as array. */ + upb_array array; + + /* A side index whose values are indexes into the array. May be NULL. */ + union { + upb_strtable *strtab; + upb_inttable *inttab; + } table; +} upb_map; + upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); diff --git a/upbc/generator.cc b/upbc/generator.cc index 27600693da..6e8de0a7ec 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -368,8 +368,10 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output GetSizeInit(layout.GetOneofCaseOffset(oneof))); } - for (auto field : FieldNumberOrder(message)) { + // Generate const methods. + for (auto field : FieldNumberOrder(message)) { + // Generate hazzer (if any). if (layout.HasHasbit(field)) { output( "UPB_INLINE bool $0_has_$1(const $0 *msg) { " @@ -384,6 +386,7 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output field->number()); } + // Generate getter. if (field->is_repeated()) { output( "UPB_INLINE $0 const* $1_$2(const $1 *msg, size_t *len) { " @@ -409,8 +412,15 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output output("\n"); + // Generate mutable methods. + for (auto field : FieldNumberOrder(message)) { - if (field->is_repeated()) { + if (message->options().map_entry() && field->name() == "key") { + // Emit nothing, map keys cannot be changed directly. Users must use + // the mutators of the map itself. + } else if (field->is_map()) { + // TODO(haberman): add map-based mutators. + } else if (field->is_repeated()) { output( "UPB_INLINE $0* $1_mutable_$2($1 *msg, size_t *len) {\n" " return ($0*)_upb_array_mutable_accessor(msg, $3, len);\n" @@ -453,6 +463,7 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output UpbType(field)); } } else { + // Non-repeated field. output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) {\n", msgname, field->name(), CType(field)); if (field->containing_oneof()) { From 283857f30807f77311f940eb269b57493526497b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 5 Jun 2019 15:36:25 -0700 Subject: [PATCH 02/35] WIP. --- upb/legacy_msg_reflection.c | 99 ++++++++++--------------------------- upb/legacy_msg_reflection.h | 27 +++++----- upb/msg.c | 29 ++++++++--- upb/msg.h | 23 ++++----- 4 files changed, 75 insertions(+), 103 deletions(-) diff --git a/upb/legacy_msg_reflection.c b/upb/legacy_msg_reflection.c index 0b71963abf..aa043d1cb7 100644 --- a/upb/legacy_msg_reflection.c +++ b/upb/legacy_msg_reflection.c @@ -85,24 +85,6 @@ static upb_msgval upb_msgval_fromval(upb_value val) { return ret; } -static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_FLOAT: return UPB_CTYPE_FLOAT; - case UPB_TYPE_DOUBLE: return UPB_CTYPE_DOUBLE; - case UPB_TYPE_BOOL: return UPB_CTYPE_BOOL; - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - case UPB_TYPE_STRING: return UPB_CTYPE_CONSTPTR; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: return UPB_CTYPE_INT32; - case UPB_TYPE_UINT32: return UPB_CTYPE_UINT32; - case UPB_TYPE_INT64: return UPB_CTYPE_INT64; - case UPB_TYPE_UINT64: return UPB_CTYPE_UINT64; - default: UPB_ASSERT(false); return 0; - } -} - - /** upb_msg *******************************************************************/ /* If we always read/write as a consistent type to each address, this shouldn't @@ -255,48 +237,16 @@ static upb_msgval upb_map_fromkey(upb_fieldtype_t type, const char *key, UPB_UNREACHABLE(); } -upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, - upb_arena *a) { - upb_ctype_t vtabtype = upb_fieldtotabtype(vtype); - upb_alloc *alloc = upb_arena_alloc(a); - upb_map *map = upb_malloc(alloc, sizeof(upb_map)); - - if (!map) { - return NULL; - } - - UPB_ASSERT(upb_fieldtype_mapkeyok(ktype)); - map->key_type = ktype; - map->val_type = vtype; - map->arena = a; - - if (!upb_strtable_init2(&map->strtab, vtabtype, alloc)) { - return NULL; - } - - return map; -} - -size_t upb_map_size(const upb_map *map) { - return upb_strtable_count(&map->strtab); -} - -upb_fieldtype_t upb_map_keytype(const upb_map *map) { - return map->key_type; -} - -upb_fieldtype_t upb_map_valuetype(const upb_map *map) { - return map->val_type; -} - -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { +bool upb_map_get(const upb_map *map, upb_fieldtype_t key_type, upb_msgval key, + upb_msgval *val) { + const upb_strmap *map2 = (const upb_strmap*)map; upb_value tabval; const char *key_str; size_t key_len; bool ret; - upb_map_tokey(map->key_type, &key, &key_str, &key_len); - ret = upb_strtable_lookup2(&map->strtab, key_str, key_len, &tabval); + upb_map_tokey(key_type, &key, &key_str, &key_len); + ret = upb_strtable_lookup2(&map2->table, key_str, key_len, &tabval); if (ret) { memcpy(val, &tabval, sizeof(tabval)); } @@ -304,35 +254,37 @@ bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { return ret; } -bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, - upb_msgval *removed) { +bool upb_map_set(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, + upb_msgval val, upb_msgval *removed, upb_arena *arena) { + upb_strmap *map2 = (upb_strmap*)map; const char *key_str; size_t key_len; upb_value tabval = upb_toval(val); upb_value removedtabval; - upb_alloc *a = upb_arena_alloc(map->arena); + upb_alloc *a = upb_arena_alloc(arena); - upb_map_tokey(map->key_type, &key, &key_str, &key_len); + upb_map_tokey(key_type, &key, &key_str, &key_len); /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - if (upb_strtable_lookup2(&map->strtab, key_str, key_len, NULL)) { - upb_strtable_remove3(&map->strtab, key_str, key_len, &removedtabval, a); + if (upb_strtable_lookup2(&map2->table, key_str, key_len, NULL)) { + upb_strtable_remove3(&map2->table, key_str, key_len, &removedtabval, a); memcpy(&removed, &removedtabval, sizeof(removed)); } - return upb_strtable_insert3(&map->strtab, key_str, key_len, tabval, a); + return upb_strtable_insert3(&map2->table, key_str, key_len, tabval, a); } -bool upb_map_del(upb_map *map, upb_msgval key) { +bool upb_map_del(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, + upb_arena *arena) { + upb_strmap *map2 = (upb_strmap*)map; const char *key_str; size_t key_len; - upb_alloc *a = upb_arena_alloc(map->arena); + upb_alloc *a = upb_arena_alloc(arena); - upb_map_tokey(map->key_type, &key, &key_str, &key_len); - return upb_strtable_remove3(&map->strtab, key_str, key_len, NULL, a); + upb_map_tokey(key_type, &key, &key_str, &key_len); + return upb_strtable_remove3(&map2->table, key_str, key_len, NULL, a); } - /** upb_mapiter ***************************************************************/ struct upb_mapiter { @@ -344,19 +296,22 @@ size_t upb_mapiter_sizeof() { return sizeof(upb_mapiter); } -void upb_mapiter_begin(upb_mapiter *i, const upb_map *map) { - upb_strtable_begin(&i->iter, &map->strtab); - i->key_type = map->key_type; +void upb_mapiter_begin(upb_mapiter *i, upb_fieldtype_t key_type, + const upb_map *map) { + const upb_strmap *map2 = (const upb_strmap*)map; + upb_strtable_begin(&i->iter, &map2->table); + i->key_type = key_type; } -upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a) { +upb_mapiter *upb_mapiter_new(const upb_map *map, upb_fieldtype_t key_type, + upb_alloc *a) { upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof()); if (!ret) { return NULL; } - upb_mapiter_begin(ret, t); + upb_mapiter_begin(ret, key_type, map); return ret; } diff --git a/upb/legacy_msg_reflection.h b/upb/legacy_msg_reflection.h index c3bc94e24d..b2dbb2f0da 100644 --- a/upb/legacy_msg_reflection.h +++ b/upb/legacy_msg_reflection.h @@ -10,6 +10,11 @@ struct upb_mapiter; typedef struct upb_mapiter upb_mapiter; +/* A distinct pointer type to represent all maps for reflection. */ +typedef struct { + int x; +} upb_map; + /** upb_msgval ****************************************************************/ /* A union representing all possible protobuf values. Used for generic get/set @@ -139,15 +144,11 @@ bool upb_array_set(upb_array *arr, upb_fieldtype_t type, size_t i, * So you must ensure that any string or message values outlive the map, and you * must delete them manually when they are no longer required. */ -upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, - upb_arena *a); - /* Read-only interface. Safe for anyone to call. */ size_t upb_map_size(const upb_map *map); -upb_fieldtype_t upb_map_keytype(const upb_map *map); -upb_fieldtype_t upb_map_valuetype(const upb_map *map); -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); +bool upb_map_get(const upb_map *map, upb_fieldtype_t key_type, upb_msgval key, + upb_msgval *val); /* Write interface. May only be called by the message's owner who can enforce * its memory management invariants. */ @@ -155,12 +156,12 @@ bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); /* Sets or overwrites an entry in the map. Return value indicates whether * the operation succeeded or failed with OOM, and also whether an existing * key was replaced or not. */ -bool upb_map_set(upb_map *map, - upb_msgval key, upb_msgval val, - upb_msgval *valremoved); +bool upb_map_set(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, + upb_msgval val, upb_msgval *valremoved, upb_arena *arena); /* Deletes an entry in the map. Returns true if the key was present. */ -bool upb_map_del(upb_map *map, upb_msgval key); +bool upb_map_del(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, + upb_arena *arena); /** upb_mapiter ***************************************************************/ @@ -172,8 +173,10 @@ bool upb_map_del(upb_map *map, upb_msgval key); size_t upb_mapiter_sizeof(); -void upb_mapiter_begin(upb_mapiter *i, const upb_map *t); -upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a); +void upb_mapiter_begin(upb_mapiter *i, upb_fieldtype_t key_type, + const upb_map *t); +upb_mapiter *upb_mapiter_new(const upb_map *t, upb_fieldtype_t key_type, + upb_alloc *a); void upb_mapiter_free(upb_mapiter *i, upb_alloc *a); void upb_mapiter_next(upb_mapiter *i); bool upb_mapiter_done(const upb_mapiter *i); diff --git a/upb/msg.c b/upb/msg.c index 93d89a5afa..74bb62139f 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -74,18 +74,35 @@ upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { return msg; } +static void upb_array_init(upb_array *arr) { + arr->data = NULL; + arr->len = 0; + arr->size = 0; +} + upb_array *upb_array_new(upb_arena *a) { - upb_array *ret = upb_arena_malloc(a, sizeof(upb_array)); + upb_array *arr = upb_arena_malloc(a, sizeof(upb_array)); + + if (!arr) { + return NULL; + } + + upb_array_init(arr); + + return arr; +} + +upb_strmap *upb_strmap_new(upb_arena *a) { + upb_strmap *map = upb_arena_malloc(a, sizeof(upb_strmap)); - if (!ret) { + if (!map) { return NULL; } - ret->data = NULL; - ret->len = 0; - ret->size = 0; + upb_array_init(&map->array); + upb_strtable_init(&map->table, UPB_CTYPE_INT32); - return ret; + return map; } void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, diff --git a/upb/msg.h b/upb/msg.h index 9bbd1534fc..c240213007 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -55,28 +55,25 @@ typedef struct { size_t size; /* Measured in elements. */ } upb_array; -/* Our internal representation for maps. */ +/* Our internal representation for maps. They are arrays but also have a side + * index. These start with array so the parser can begin with a simple array + * path and do the table insert as a separate step. + * + * Right now we use strmaps for everything. We'll likely want to use + * integer-specific maps for integer-keyed maps.*/ typedef struct { - /* First element must be upb_array so code like parser/serializer can treat - * map fields as array. */ upb_array array; + upb_strtable table; /* Values are indices into array. */ +} upb_strmap; - /* A side index whose values are indexes into the array. May be NULL. */ - union { - upb_strtable *strtab; - upb_inttable *inttab; - } table; -} upb_map; - -upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); +upb_array *upb_array_new(upb_arena *a); +upb_strmap *upb_map_new(upb_arena *a); void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, upb_arena *arena); const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); -upb_array *upb_array_new(upb_arena *a); - #ifdef __cplusplus } /* extern "C" */ #endif From 1461da50560030737a0ee38737be66ce284d5572 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 26 Aug 2019 07:55:52 -0700 Subject: [PATCH 03/35] WIP. --- upb/bindings/lua/msg.c | 19 ++-- upb/bindings/lua/upb.h | 1 - upb/legacy_msg_reflection.c | 178 +++++++++++++++++++++--------------- upb/legacy_msg_reflection.h | 21 ++--- upb/msg.c | 5 +- upb/msg.h | 16 ++-- upb/msgfactory.h | 5 + 7 files changed, 131 insertions(+), 114 deletions(-) diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 5e769b2f0d..be3ae7df16 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -276,7 +276,6 @@ static const struct luaL_Reg lupb_msgfactory_mm[] = { struct lupb_msgclass { const upb_msglayout *layout; const upb_msgdef *msgdef; - const lupb_msgfactory *lfactory; }; /* Type-checks for assigning to a message field. */ @@ -301,10 +300,6 @@ const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass) { return lmsgclass->msgdef; } -upb_msgfactory *lupb_msgclass_getfactory(const lupb_msgclass *lmsgclass) { - return lmsgclass->lfactory->factory; -} - /** * lupb_msgclass_typecheck() * @@ -355,7 +350,6 @@ static int lupb_msgclass_pushnew(lua_State *L, int factory, lupb_uservalseti(L, -1, LUPB_MSGCLASS_FACTORY, factory); lmc->layout = upb_msgfactory_getlayout(lfactory->factory, md); - lmc->lfactory = lfactory; lmc->msgdef = md; return 1; @@ -493,13 +487,13 @@ static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, const upb_fielddef *f) { lupb_array *larray = lupb_array_check(L, narg); - if (upb_array_type(larray->arr) != upb_fielddef_type(f) || + if (larray->type != upb_fielddef_type(f) || lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) { luaL_error(L, "Array had incorrect type (expected: %d, got: %d)", - (int)upb_fielddef_type(f), (int)upb_array_type(larray->arr)); + (int)upb_fielddef_type(f), (int)larray->type); } - if (upb_array_type(larray->arr) == UPB_TYPE_MESSAGE) { + if (larray->type == UPB_TYPE_MESSAGE) { lupb_msgclass_typecheck(L, lupb_msg_getsubmsgclass(L, msg, f), larray->lmsgclass); } @@ -550,7 +544,7 @@ static int lupb_array_new(lua_State *L) { static int lupb_array_newindex(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); - upb_fieldtype_t type = upb_array_type(larray->arr); + upb_fieldtype_t type = larray->type; uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(larray->arr) + 1); upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->lmsgclass); @@ -567,13 +561,12 @@ static int lupb_array_index(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); upb_array *array = larray->arr; uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(array)); - upb_fieldtype_t type = upb_array_type(array); + upb_fieldtype_t type = larray->type; if (lupb_istypewrapped(type)) { lupb_uservalgeti(L, 1, n); } else { - lupb_pushmsgval(L, upb_array_type(array), - upb_array_get(array, larray->type, n)); + lupb_pushmsgval(L, type, upb_array_get(array, type, n)); } return 1; diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h index 51d8acf9e4..096e3fd9e9 100644 --- a/upb/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h @@ -121,7 +121,6 @@ upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg, const lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg); const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg); const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass); -upb_msgfactory *lupb_msgclass_getfactory(const lupb_msgclass *lmsgclass); void lupb_msg_registertypes(lua_State *L); #endif /* UPB_LUA_UPB_H_ */ diff --git a/upb/legacy_msg_reflection.c b/upb/legacy_msg_reflection.c index aa043d1cb7..30c63e0a55 100644 --- a/upb/legacy_msg_reflection.c +++ b/upb/legacy_msg_reflection.c @@ -37,33 +37,56 @@ static void upb_msgval_write(void *p, size_t ofs, upb_msgval val, memcpy(p, &val, size); } -static size_t upb_msgval_sizeof(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_DOUBLE: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - return 8; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_FLOAT: - return 4; - case UPB_TYPE_BOOL: - return 1; - case UPB_TYPE_MESSAGE: - return sizeof(void*); - case UPB_TYPE_BYTES: - case UPB_TYPE_STRING: - return sizeof(upb_strview); - } - UPB_UNREACHABLE(); +static size_t upb_msgval_sizeof(upb_descriptortype_t type) { + static uint8_t sizes[] = { + 0, /* none */ + 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE = 1 */ + 4, /* UPB_DESCRIPTOR_TYPE_FLOAT = 2 */ + 8, /* UPB_DESCRIPTOR_TYPE_INT64 = 3 */ + 8, /* UPB_DESCRIPTOR_TYPE_UINT64 = 4 */ + 4, /* UPB_DESCRIPTOR_TYPE_INT32 = 5 */ + 8, /* UPB_DESCRIPTOR_TYPE_FIXED64 = 6 */ + 4, /* UPB_DESCRIPTOR_TYPE_FIXED32 = 7 */ + 1, /* UPB_DESCRIPTOR_TYPE_BOOL = 8 */ + sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING = 9 */ + sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP = 11 */ + sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE = 12 */ + sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES = 13 */ + 4, /* UPB_DESCRIPTOR_TYPE_UINT32 = 14 */ + 4, /* UPB_DESCRIPTOR_TYPE_ENUM = 15 */ + 4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 = 16 */ + 8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 = 17 */ + 4, /* UPB_DESCRIPTOR_TYPE_SINT32 = 18 */ + 8, /* UPB_DESCRIPTOR_TYPE_SINT64 = 19 */ + }; + UPB_ASSERT(type < sizeof(sizes)); + return sizes[type]; +} + +static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { + static uint8_t sizes[] = { + 0, /* none */ + 1, /* UPB_TYPE_BOOL = 1, */ + 4, /* UPB_TYPE_FLOAT = 2, */ + 4, /* UPB_TYPE_INT32 = 3, */ + 4, /* UPB_TYPE_UINT32 = 4, */ + 4, /* UPB_TYPE_ENUM = 5, */ + sizeof(upb_strview), /* UPB_TYPE_STRING = 6, */ + sizeof(upb_strview), /* UPB_TYPE_BYTES = 7, */ + sizeof(void*), /* UPB_TYPE_MESSAGE = 8, */ + 8, /* UPB_TYPE_DOUBLE = 9, */ + 8, /* UPB_TYPE_INT64 = 10, */ + 8, /* UPB_TYPE_UINT64 = 11 */ + }; + UPB_ASSERT(type < sizeof(sizes)); + return sizes[type]; } static uint8_t upb_msg_fieldsize(const upb_msglayout_field *field) { if (field->label == UPB_LABEL_REPEATED) { return sizeof(void*); } else { - return upb_msgval_sizeof(upb_desctype_to_fieldtype[field->descriptortype]); + return upb_msgval_sizeof(field->descriptortype); } } @@ -150,14 +173,14 @@ size_t upb_array_size(const upb_array *arr) { } upb_msgval upb_array_get(const upb_array *arr, upb_fieldtype_t type, size_t i) { - size_t element_size = upb_msgval_sizeof(type); + size_t element_size = upb_msgval_sizeof2(type); UPB_ASSERT(i < arr->len); return upb_msgval_read(arr->data, i * element_size, element_size); } bool upb_array_set(upb_array *arr, upb_fieldtype_t type, size_t i, upb_msgval val, upb_arena *arena) { - size_t element_size = upb_msgval_sizeof(type); + size_t element_size = upb_msgval_sizeof2(type); UPB_ASSERT(i <= arr->len); if (i == arr->len) { @@ -189,64 +212,77 @@ bool upb_array_set(upb_array *arr, upb_fieldtype_t type, size_t i, /** upb_map *******************************************************************/ -static void upb_map_tokey(upb_fieldtype_t type, upb_msgval *key, +static void upb_map_tokey(upb_descriptortype_t type, upb_msgval *key, const char **out_key, size_t *out_len) { switch (type) { - case UPB_TYPE_STRING: + case UPB_DESCRIPTOR_TYPE_BYTES: + case UPB_DESCRIPTOR_TYPE_STRING: /* Point to string data of the input key. */ *out_key = key->str.data; *out_len = key->str.size; return; - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: + case UPB_DESCRIPTOR_TYPE_BOOL: + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_SINT32: + case UPB_DESCRIPTOR_TYPE_SFIXED32: + case UPB_DESCRIPTOR_TYPE_FIXED32: + case UPB_DESCRIPTOR_TYPE_UINT32: + case UPB_DESCRIPTOR_TYPE_INT64: + case UPB_DESCRIPTOR_TYPE_SINT64: + case UPB_DESCRIPTOR_TYPE_SFIXED64: + case UPB_DESCRIPTOR_TYPE_FIXED64: + case UPB_DESCRIPTOR_TYPE_UINT64: /* Point to the key itself. XXX: big-endian. */ *out_key = (const char*)key; *out_len = upb_msgval_sizeof(type); return; - case UPB_TYPE_BYTES: - case UPB_TYPE_DOUBLE: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - case UPB_TYPE_MESSAGE: - break; /* Cannot be a map key. */ + case UPB_DESCRIPTOR_TYPE_DOUBLE: + case UPB_DESCRIPTOR_TYPE_ENUM: + case UPB_DESCRIPTOR_TYPE_FLOAT: + case UPB_DESCRIPTOR_TYPE_MESSAGE: + case UPB_DESCRIPTOR_TYPE_GROUP: + UPB_UNREACHABLE(); /* Cannot be a map key. */ } UPB_UNREACHABLE(); } -static upb_msgval upb_map_fromkey(upb_fieldtype_t type, const char *key, +static upb_msgval upb_map_fromkey(upb_descriptortype_t type, const char *key, size_t len) { switch (type) { - case UPB_TYPE_STRING: + case UPB_DESCRIPTOR_TYPE_BYTES: + case UPB_DESCRIPTOR_TYPE_STRING: return upb_msgval_makestr(key, len); - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: + case UPB_DESCRIPTOR_TYPE_BOOL: + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_SINT32: + case UPB_DESCRIPTOR_TYPE_SFIXED32: + case UPB_DESCRIPTOR_TYPE_FIXED32: + case UPB_DESCRIPTOR_TYPE_UINT32: + case UPB_DESCRIPTOR_TYPE_INT64: + case UPB_DESCRIPTOR_TYPE_SINT64: + case UPB_DESCRIPTOR_TYPE_SFIXED64: + case UPB_DESCRIPTOR_TYPE_FIXED64: + case UPB_DESCRIPTOR_TYPE_UINT64: return upb_msgval_read(key, 0, upb_msgval_sizeof(type)); - case UPB_TYPE_BYTES: - case UPB_TYPE_DOUBLE: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - case UPB_TYPE_MESSAGE: - break; /* Cannot be a map key. */ + case UPB_DESCRIPTOR_TYPE_DOUBLE: + case UPB_DESCRIPTOR_TYPE_ENUM: + case UPB_DESCRIPTOR_TYPE_FLOAT: + case UPB_DESCRIPTOR_TYPE_MESSAGE: + case UPB_DESCRIPTOR_TYPE_GROUP: + UPB_UNREACHABLE(); /* Cannot be a map key. */ } UPB_UNREACHABLE(); } -bool upb_map_get(const upb_map *map, upb_fieldtype_t key_type, upb_msgval key, - upb_msgval *val) { - const upb_strmap *map2 = (const upb_strmap*)map; +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val, + const upb_msglayout *layout) { upb_value tabval; const char *key_str; size_t key_len; bool ret; - upb_map_tokey(key_type, &key, &key_str, &key_len); - ret = upb_strtable_lookup2(&map2->table, key_str, key_len, &tabval); + upb_map_tokey(layout->fields[0].descriptortype, &key, &key_str, &key_len); + ret = upb_strtable_lookup2(&map->table, key_str, key_len, &tabval); if (ret) { memcpy(val, &tabval, sizeof(tabval)); } @@ -254,56 +290,52 @@ bool upb_map_get(const upb_map *map, upb_fieldtype_t key_type, upb_msgval key, return ret; } -bool upb_map_set(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, - upb_msgval val, upb_msgval *removed, upb_arena *arena) { - upb_strmap *map2 = (upb_strmap*)map; +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, + const upb_msglayout *layout, upb_arena *arena) { const char *key_str; size_t key_len; upb_value tabval = upb_toval(val); upb_value removedtabval; upb_alloc *a = upb_arena_alloc(arena); - upb_map_tokey(key_type, &key, &key_str, &key_len); + upb_map_tokey(layout->fields[0].descriptortype, &key, &key_str, &key_len); /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - if (upb_strtable_lookup2(&map2->table, key_str, key_len, NULL)) { - upb_strtable_remove3(&map2->table, key_str, key_len, &removedtabval, a); - memcpy(&removed, &removedtabval, sizeof(removed)); + if (upb_strtable_lookup2(&map->table, key_str, key_len, NULL)) { + upb_strtable_remove3(&map->table, key_str, key_len, &removedtabval, a); } - return upb_strtable_insert3(&map2->table, key_str, key_len, tabval, a); + return upb_strtable_insert3(&map->table, key_str, key_len, tabval, a); } -bool upb_map_del(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, +bool upb_map_del(upb_map *map, upb_msgval key, const upb_msglayout *layout, upb_arena *arena) { - upb_strmap *map2 = (upb_strmap*)map; const char *key_str; size_t key_len; upb_alloc *a = upb_arena_alloc(arena); - upb_map_tokey(key_type, &key, &key_str, &key_len); - return upb_strtable_remove3(&map2->table, key_str, key_len, NULL, a); + upb_map_tokey(layout->fields[0].descriptortype, &key, &key_str, &key_len); + return upb_strtable_remove3(&map->table, key_str, key_len, NULL, a); } /** upb_mapiter ***************************************************************/ struct upb_mapiter { upb_strtable_iter iter; - upb_fieldtype_t key_type; + upb_descriptortype_t key_type; }; size_t upb_mapiter_sizeof() { return sizeof(upb_mapiter); } -void upb_mapiter_begin(upb_mapiter *i, upb_fieldtype_t key_type, +void upb_mapiter_begin(upb_mapiter *i, const upb_msglayout *layout, const upb_map *map) { - const upb_strmap *map2 = (const upb_strmap*)map; - upb_strtable_begin(&i->iter, &map2->table); - i->key_type = key_type; + upb_strtable_begin(&i->iter, &map->table); + i->key_type = layout->fields[0].descriptortype; } -upb_mapiter *upb_mapiter_new(const upb_map *map, upb_fieldtype_t key_type, +upb_mapiter *upb_mapiter_new(const upb_map *map, const upb_msglayout *layout, upb_alloc *a) { upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof()); @@ -311,7 +343,7 @@ upb_mapiter *upb_mapiter_new(const upb_map *map, upb_fieldtype_t key_type, return NULL; } - upb_mapiter_begin(ret, key_type, map); + upb_mapiter_begin(ret, layout, map); return ret; } diff --git a/upb/legacy_msg_reflection.h b/upb/legacy_msg_reflection.h index b2dbb2f0da..63f3e841e3 100644 --- a/upb/legacy_msg_reflection.h +++ b/upb/legacy_msg_reflection.h @@ -10,11 +10,6 @@ struct upb_mapiter; typedef struct upb_mapiter upb_mapiter; -/* A distinct pointer type to represent all maps for reflection. */ -typedef struct { - int x; -} upb_map; - /** upb_msgval ****************************************************************/ /* A union representing all possible protobuf values. Used for generic get/set @@ -123,8 +118,6 @@ bool upb_msg_clearfield(upb_msg *msg, * semantics are the same as upb_msg. A upb_array allocates dynamic * memory internally for the array elements. */ -upb_fieldtype_t upb_array_type(const upb_array *arr); - /* Read-only interface. Safe for anyone to call. */ size_t upb_array_size(const upb_array *arr); @@ -147,8 +140,8 @@ bool upb_array_set(upb_array *arr, upb_fieldtype_t type, size_t i, /* Read-only interface. Safe for anyone to call. */ size_t upb_map_size(const upb_map *map); -bool upb_map_get(const upb_map *map, upb_fieldtype_t key_type, upb_msgval key, - upb_msgval *val); +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val, + const upb_msglayout *l); /* Write interface. May only be called by the message's owner who can enforce * its memory management invariants. */ @@ -156,11 +149,11 @@ bool upb_map_get(const upb_map *map, upb_fieldtype_t key_type, upb_msgval key, /* Sets or overwrites an entry in the map. Return value indicates whether * the operation succeeded or failed with OOM, and also whether an existing * key was replaced or not. */ -bool upb_map_set(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, - upb_msgval val, upb_msgval *valremoved, upb_arena *arena); +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, + const upb_msglayout *l, upb_arena *arena); /* Deletes an entry in the map. Returns true if the key was present. */ -bool upb_map_del(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, +bool upb_map_del(upb_map *map, upb_msgval key, const upb_msglayout *l, upb_arena *arena); /** upb_mapiter ***************************************************************/ @@ -173,9 +166,9 @@ bool upb_map_del(upb_map *map, upb_fieldtype_t key_type, upb_msgval key, size_t upb_mapiter_sizeof(); -void upb_mapiter_begin(upb_mapiter *i, upb_fieldtype_t key_type, +void upb_mapiter_begin(upb_mapiter *i, const upb_msglayout *layout, const upb_map *t); -upb_mapiter *upb_mapiter_new(const upb_map *t, upb_fieldtype_t key_type, +upb_mapiter *upb_mapiter_new(const upb_map *t, const upb_msglayout *layout, upb_alloc *a); void upb_mapiter_free(upb_mapiter *i, upb_alloc *a); void upb_mapiter_next(upb_mapiter *i); diff --git a/upb/msg.c b/upb/msg.c index 74bb62139f..e96fefe2d8 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -92,14 +92,13 @@ upb_array *upb_array_new(upb_arena *a) { return arr; } -upb_strmap *upb_strmap_new(upb_arena *a) { - upb_strmap *map = upb_arena_malloc(a, sizeof(upb_strmap)); +upb_map *upb_map_new(upb_arena *a) { + upb_map *map = upb_arena_malloc(a, sizeof(upb_map)); if (!map) { return NULL; } - upb_array_init(&map->array); upb_strtable_init(&map->table, UPB_CTYPE_INT32); return map; diff --git a/upb/msg.h b/upb/msg.h index c240213007..d8a6defe8f 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -55,20 +55,16 @@ typedef struct { size_t size; /* Measured in elements. */ } upb_array; -/* Our internal representation for maps. They are arrays but also have a side - * index. These start with array so the parser can begin with a simple array - * path and do the table insert as a separate step. - * - * Right now we use strmaps for everything. We'll likely want to use - * integer-specific maps for integer-keyed maps.*/ +/* Our internal representation for maps. Right now we use strmaps for + * everything. We'll likely want to use integer-specific maps for + * integer-keyed maps.*/ typedef struct { - upb_array array; - upb_strtable table; /* Values are indices into array. */ -} upb_strmap; + upb_strtable table; +} upb_map; upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); upb_array *upb_array_new(upb_arena *a); -upb_strmap *upb_map_new(upb_arena *a); +upb_map *upb_map_new(upb_arena *a); void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, upb_arena *arena); diff --git a/upb/msgfactory.h b/upb/msgfactory.h index 9b3b599938..3770faf5f2 100644 --- a/upb/msgfactory.h +++ b/upb/msgfactory.h @@ -41,6 +41,11 @@ const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f); const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, const upb_msgdef *m); +const upb_msglayout *upb_msgfactory_getmaplayout(upb_msgfactory *f, + const upb_fieldtype_t keytype, + const upb_fieldtype_t valtype, + const upb_msgdef *valmsg); + #ifdef __cplusplus } /* extern "C" */ #endif From c486da3970cd26d66c6aff8b541446388821cab0 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 11 Nov 2019 16:59:24 -0800 Subject: [PATCH 04/35] WIP. --- BUILD | 1 + upb/bindings/lua/msg.c | 85 ++++++++------ upb/generated_util.h | 41 ++----- upb/legacy_msg_reflection.c | 56 ++++------ upb/legacy_msg_reflection.h | 217 ++++++++++++++---------------------- upb/msg.c | 99 ++++++++++++---- upb/msg.h | 63 ++++++++--- upbc/generator.cc | 19 ++-- 8 files changed, 302 insertions(+), 279 deletions(-) diff --git a/BUILD b/BUILD index ad85b202a9..a9a421fe15 100644 --- a/BUILD +++ b/BUILD @@ -156,6 +156,7 @@ cc_library( deps = [ ":table", ":upb", + ":reflection", ], ) diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index be3ae7df16..8d319bc905 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -385,33 +385,43 @@ static bool lupb_istypewrapped(upb_fieldtype_t type) { static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg, const lupb_msgclass *lmsgclass) { + upb_msgval ret; switch (type) { case UPB_TYPE_INT32: case UPB_TYPE_ENUM: - return upb_msgval_int32(lupb_checkint32(L, narg)); + ret.int32_val = lupb_checkint32(L, narg); + break; case UPB_TYPE_INT64: - return upb_msgval_int64(lupb_checkint64(L, narg)); + ret.int64_val = lupb_checkint64(L, narg); + break; case UPB_TYPE_UINT32: - return upb_msgval_uint32(lupb_checkuint32(L, narg)); + ret.uint32_val = lupb_checkuint32(L, narg); + break; case UPB_TYPE_UINT64: - return upb_msgval_uint64(lupb_checkuint64(L, narg)); + ret.uint64_val = lupb_checkuint64(L, narg); + break; case UPB_TYPE_DOUBLE: - return upb_msgval_double(lupb_checkdouble(L, narg)); + ret.double_val = lupb_checkdouble(L, narg); + break; case UPB_TYPE_FLOAT: - return upb_msgval_float(lupb_checkfloat(L, narg)); + ret.float_val = lupb_checkfloat(L, narg); + break; case UPB_TYPE_BOOL: - return upb_msgval_bool(lupb_checkbool(L, narg)); + ret.bool_val = lupb_checkbool(L, narg); + break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { size_t len; const char *ptr = lupb_checkstring(L, narg, &len); - return upb_msgval_makestr(ptr, len); + ret.str_val = upb_strview_make(ptr, len); + break; } case UPB_TYPE_MESSAGE: UPB_ASSERT(lmsgclass); - return upb_msgval_msg(lupb_msg_checkmsg(L, narg, lmsgclass)); + ret.msg_val = lupb_msg_checkmsg(L, narg, lmsgclass); + break; } - UPB_UNREACHABLE(); + return ret; } static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, @@ -419,25 +429,25 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, switch (type) { case UPB_TYPE_INT32: case UPB_TYPE_ENUM: - lupb_pushint32(L, upb_msgval_getint32(val)); + lupb_pushint32(L, val.int32_val); return; case UPB_TYPE_INT64: - lupb_pushint64(L, upb_msgval_getint64(val)); + lupb_pushint64(L, val.int64_val); return; case UPB_TYPE_UINT32: - lupb_pushuint32(L, upb_msgval_getuint32(val)); + lupb_pushuint32(L, val.uint32_val); return; case UPB_TYPE_UINT64: - lupb_pushuint64(L, upb_msgval_getuint64(val)); + lupb_pushuint64(L, val.uint64_val); return; case UPB_TYPE_DOUBLE: - lupb_pushdouble(L, upb_msgval_getdouble(val)); + lupb_pushdouble(L, val.double_val); return; case UPB_TYPE_FLOAT: - lupb_pushfloat(L, upb_msgval_getfloat(val)); + lupb_pushfloat(L, val.float_val); return; case UPB_TYPE_BOOL: - lua_pushboolean(L, upb_msgval_getbool(val)); + lua_pushboolean(L, val.bool_val); return; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: @@ -486,6 +496,7 @@ static lupb_array *lupb_array_check(lua_State *L, int narg) { static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, const upb_fielddef *f) { lupb_array *larray = lupb_array_check(L, narg); + upb_msgval val; if (larray->type != upb_fielddef_type(f) || lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) { @@ -498,7 +509,8 @@ static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, larray->lmsgclass); } - return upb_msgval_arr(larray->arr); + val.array_val = larray->arr; + return val; } /** @@ -599,6 +611,8 @@ static const struct luaL_Reg lupb_array_mm[] = { typedef struct { const lupb_msgclass *value_lmsgclass; + upb_fieldtype_t key_type; + upb_fieldtype_t value_type; upb_map *map; } lupb_map; @@ -627,16 +641,17 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, UPB_ASSERT(entry && key_field && value_field); - if (upb_map_keytype(map) != upb_fielddef_type(key_field)) { - luaL_error(L, "Map key type invalid"); + if (lmap->key_type != upb_fielddef_type(key_field)) { + luaL_error(L, "Map had incorrect field type (expected: %s, got: %s)", + upb_fielddef_type(key_field), lmap->key_type); } - if (upb_map_valuetype(map) != upb_fielddef_type(value_field)) { + if (lmap->value_type != upb_fielddef_type(value_field)) { luaL_error(L, "Map had incorrect value type (expected: %s, got: %s)", - upb_fielddef_type(value_field), upb_map_valuetype(map)); + upb_fielddef_type(value_field), lmap->value_type); } - if (upb_map_valuetype(map) == UPB_TYPE_MESSAGE) { + if (lmap->value_type == UPB_TYPE_MESSAGE) { lupb_msgclass_typecheck( L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)), lmap->value_lmsgclass); @@ -672,6 +687,8 @@ static int lupb_map_new(lua_State *L) { lupb_uservalseti(L, -1, MAP_MSGCLASS_INDEX, 2); /* GC-root lmsgclass. */ } + lmap->key_type = key_type; + lmap->value_type = value_type; lmap->value_lmsgclass = value_lmsgclass; lmap->map = upb_map_new(key_type, value_type, lupb_arena_get(L)); @@ -687,9 +704,9 @@ static int lupb_map_new(lua_State *L) { static int lupb_map_index(lua_State *L) { lupb_map *lmap = lupb_map_check(L, 1); upb_map *map = lmap->map; - upb_fieldtype_t valtype = upb_map_valuetype(map); + upb_fieldtype_t valtype = lmap->value_type; /* We don't always use "key", but this call checks the key type. */ - upb_msgval key = lupb_tomsgval(L, upb_map_keytype(map), 2, NULL); + upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, NULL); if (lupb_istypewrapped(valtype)) { /* Userval contains the full map, lookup there by key. */ @@ -704,7 +721,7 @@ static int lupb_map_index(lua_State *L) { /* Lookup in upb_map. */ upb_msgval val; if (upb_map_get(map, key, &val)) { - lupb_pushmsgval(L, upb_map_valuetype(map), val); + lupb_pushmsgval(L, lmap->value_type, val); } else { lua_pushnil(L); } @@ -735,13 +752,13 @@ static int lupb_map_len(lua_State *L) { static int lupb_map_newindex(lua_State *L) { lupb_map *lmap = lupb_map_check(L, 1); upb_map *map = lmap->map; - upb_msgval key = lupb_tomsgval(L, upb_map_keytype(map), 2, NULL); + upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, NULL); if (lua_isnil(L, 3)) { /* Delete from map. */ upb_map_del(map, key); - if (lupb_istypewrapped(upb_map_valuetype(map))) { + if (lupb_istypewrapped(lmap->value_type)) { /* Delete in userval. */ lupb_getuservalue(L, 1); lua_pushvalue(L, 2); @@ -752,11 +769,11 @@ static int lupb_map_newindex(lua_State *L) { } else { /* Set in map. */ upb_msgval val = - lupb_tomsgval(L, upb_map_valuetype(map), 3, lmap->value_lmsgclass); + lupb_tomsgval(L, lmap->value_type, 3, lmap->value_lmsgclass); upb_map_set(map, key, val, NULL); - if (lupb_istypewrapped(upb_map_valuetype(map))) { + if (lupb_istypewrapped(lmap->value_type)) { /* Set in userval. */ lupb_getuservalue(L, 1); lua_pushvalue(L, 2); @@ -780,8 +797,8 @@ static int lupb_mapiter_next(lua_State *L) { return 0; } - lupb_pushmsgval(L, upb_map_keytype(map), upb_mapiter_key(i)); - lupb_pushmsgval(L, upb_map_valuetype(map), upb_mapiter_value(i)); + lupb_pushmsgval(L, lmap->key_type, upb_mapiter_key(i)); + lupb_pushmsgval(L, lmap->value_type, upb_mapiter_value(i)); upb_mapiter_next(i); return 2; @@ -790,8 +807,8 @@ static int lupb_mapiter_next(lua_State *L) { static int lupb_map_pairs(lua_State *L) { lupb_map *lmap = lupb_map_check(L, 1); - if (lupb_istypewrapped(upb_map_keytype(lmap->map)) || - lupb_istypewrapped(upb_map_valuetype(lmap->map))) { + if (lupb_istypewrapped(lmap->key_type) || + lupb_istypewrapped(lmap->value_type)) { /* Complex key or value type. * Sync upb_map to userval if necessary, then iterate over userval. */ diff --git a/upb/generated_util.h b/upb/generated_util.h index 234bcdad3c..8151e45583 100644 --- a/upb/generated_util.h +++ b/upb/generated_util.h @@ -37,48 +37,29 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, } } -/* TODO(haberman): this is a mess. It will improve when upb_array no longer - * carries reflective state (type, elem_size). */ UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, size_t elem_size, - upb_fieldtype_t type, upb_arena *arena) { - upb_array *arr = *PTR_AT(msg, ofs, upb_array*); - - if (!arr) { - arr = upb_array_new(arena); - if (!arr) return NULL; - *PTR_AT(msg, ofs, upb_array*) = arr; - } - - if (size > arr->size) { - size_t new_size = UPB_MAX(arr->size, 4); - size_t old_bytes = arr->size * elem_size; - size_t new_bytes; - while (new_size < size) new_size *= 2; - new_bytes = new_size * elem_size; - arr->data = upb_arena_realloc(arena, arr->data, old_bytes, new_bytes); - if (!arr->data) { - return NULL; - } - arr->size = new_size; + upb_array **arr_ptr = 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, arena); } - arr->len = size; return arr->data; } UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, size_t elem_size, - upb_fieldtype_t type, const void *value, upb_arena *arena) { - upb_array *arr = *PTR_AT(msg, ofs, upb_array*); - size_t i = arr ? arr->len : 0; - void *data = - _upb_array_resize_accessor(msg, ofs, i + 1, elem_size, type, arena); - if (!data) return false; - memcpy(PTR_AT(data, i * elem_size, char), value, elem_size); + upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); + upb_array *arr = *arr_ptr; + if (!arr || arr->len == arr->size) { + return _upb_array_append_fallback(arr_ptr, elem_size, value, arena); + } + memcpy(PTR_AT(arr->data, arr->len * elem_size, char), value, elem_size); + arr->len++; return true; } diff --git a/upb/legacy_msg_reflection.c b/upb/legacy_msg_reflection.c index 7abb368a76..ab0ad8e8e0 100644 --- a/upb/legacy_msg_reflection.c +++ b/upb/legacy_msg_reflection.c @@ -20,6 +20,7 @@ bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) { /** upb_msgval ****************************************************************/ +#if 0 /* These functions will generate real memcpy() calls on ARM sadly, because * the compiler assumes they might not be aligned. */ @@ -163,53 +164,38 @@ void upb_msg_set(upb_msg *msg, int field_index, upb_msgval val, upb_msgval_write(msg, field->offset, val, size); } +#endif /** upb_array *****************************************************************/ -#define DEREF_ARR(arr, i, type) ((type*)arr->data)[i] - size_t upb_array_size(const upb_array *arr) { return arr->len; } -upb_msgval upb_array_get(const upb_array *arr, upb_fieldtype_t type, size_t i) { - size_t element_size = upb_msgval_sizeof2(type); - UPB_ASSERT(i < arr->len); - return upb_msgval_read(arr->data, i * element_size, element_size); +const void *upb_array_get(const upb_array *arr, size_t *size) { + if (size) *size = arr->len; + return arr->data; } -bool upb_array_set(upb_array *arr, upb_fieldtype_t type, size_t i, - upb_msgval val, upb_arena *arena) { - size_t element_size = upb_msgval_sizeof2(type); - UPB_ASSERT(i <= arr->len); - - if (i == arr->len) { - /* Extending the array. */ - - if (i == arr->size) { - /* Need to reallocate. */ - size_t new_size = UPB_MAX(arr->size * 2, 8); - size_t new_bytes = new_size * element_size; - size_t old_bytes = arr->size * element_size; - upb_alloc *alloc = upb_arena_alloc(arena); - upb_msgval *new_data = - upb_realloc(alloc, arr->data, old_bytes, new_bytes); - - if (!new_data) { - return false; - } - - arr->data = new_data; - arr->size = new_size; - } +void* upb_array_getmutable(upb_array *arr, size_t *size) { + if (size) *size = arr->len; + return arr->data; +} - arr->len = i + 1; +/* Resizes the array to the given size, reallocating if necessary, and returns a + * pointer to the new array elements. */ +void *upb_array_resize(upb_array *arr, size_t size, upb_fieldtype_t type, + upb_arena *arena) { + int elem_size = _upb_fieldtype_to_size[type]; + if (size > arr->size && !_upb_array_realloc(arr, size, elem_size, arena)) { + return NULL; } - - upb_msgval_write(arr->data, i * element_size, val, element_size); - return true; + arr->len = size; + return arr->data; } +#if 0 + /** upb_map *******************************************************************/ static void upb_map_tokey(upb_descriptortype_t type, upb_msgval *key, @@ -375,3 +361,5 @@ void upb_mapiter_setdone(upb_mapiter *i) { bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) { return upb_strtable_iter_isequal(&i1->iter, &i2->iter); } + +#endif diff --git a/upb/legacy_msg_reflection.h b/upb/legacy_msg_reflection.h index 62b05fa976..cd6db7c1ec 100644 --- a/upb/legacy_msg_reflection.h +++ b/upb/legacy_msg_reflection.h @@ -2,181 +2,132 @@ #ifndef UPB_LEGACY_MSG_REFLECTION_H_ #define UPB_LEGACY_MSG_REFLECTION_H_ -#include "upb/upb.h" +#include "upb/def.h" #include "upb/msg.h" +#include "upb/upb.h" #include "upb/port_def.inc" -struct upb_mapiter; -typedef struct upb_mapiter upb_mapiter; - -/** upb_msgval ****************************************************************/ - -/* A union representing all possible protobuf values. Used for generic get/set - * operations. */ - typedef union { - bool b; - float flt; - double dbl; - int32_t i32; - int64_t i64; - uint32_t u32; - uint64_t u64; - const upb_map* map; - const upb_msg* msg; - const upb_array* arr; - const void* ptr; - upb_strview str; + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_map* map_val; + const upb_msg* msg_val; + const upb_array* array_val; + upb_strview str_val; } upb_msgval; -#define ACCESSORS(name, membername, ctype) \ - UPB_INLINE ctype upb_msgval_get ## name(upb_msgval v) { \ - return v.membername; \ - } \ - UPB_INLINE void upb_msgval_set ## name(upb_msgval *v, ctype cval) { \ - v->membername = cval; \ - } \ - UPB_INLINE upb_msgval upb_msgval_ ## name(ctype v) { \ - upb_msgval ret; \ - ret.membername = v; \ - return ret; \ - } - -ACCESSORS(bool, b, bool) -ACCESSORS(float, flt, float) -ACCESSORS(double, dbl, double) -ACCESSORS(int32, i32, int32_t) -ACCESSORS(int64, i64, int64_t) -ACCESSORS(uint32, u32, uint32_t) -ACCESSORS(uint64, u64, uint64_t) -ACCESSORS(map, map, const upb_map*) -ACCESSORS(msg, msg, const upb_msg*) -ACCESSORS(ptr, ptr, const void*) -ACCESSORS(arr, arr, const upb_array*) -ACCESSORS(str, str, upb_strview) - -#undef ACCESSORS - -UPB_INLINE upb_msgval upb_msgval_makestr(const char *data, size_t size) { - return upb_msgval_str(upb_strview_make(data, size)); -} +typedef union { + upb_map* map; + upb_msg* msg; + upb_array* array; +} upb_mutmsgval; /** upb_msg *******************************************************************/ -/* A upb_msg represents a protobuf message. It always corresponds to a specific - * upb_msglayout, which describes how it is laid out in memory. */ - -/* Read-only message API. Can be safely called by anyone. */ - -/* Returns the value associated with this field: - * - for scalar fields (including strings), the value directly. - * - return upb_msg*, or upb_map* for msg/map. - * If the field is unset for these field types, returns NULL. - * - * TODO(haberman): should we let users store cached array/map/msg - * pointers here for fields that are unset? Could be useful for the - * strongly-owned submessage model (ie. generated C API that doesn't use - * arenas). - */ -upb_msgval upb_msg_get(const upb_msg *msg, - int field_index, +/* Returns the value associated with this field. */ +upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l); +/* Returns a mutable pointer to a map, array, or submessage value, constructing + * a new object if it was not previously present. May not be called for + * primitive fields. */ +upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, + const upb_msglayout *l, upb_arena *a); + /* May only be called for fields where upb_fielddef_haspresence(f) == true. */ -bool upb_msg_has(const upb_msg *msg, - int field_index, +bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l); -/* Mutable message API. May only be called by the owner of the message who - * knows its ownership scheme and how to keep it consistent. */ - -/* Sets the given field to the given value. Does not perform any memory - * management: if you overwrite a pointer to a msg/array/map/string without - * cleaning it up (or using an arena) it will leak. - */ -void upb_msg_set(upb_msg *msg, - int field_index, - upb_msgval val, - const upb_msglayout *l); +/* Sets the given field to the given value. For a msg/array/map/string, the + * value must be in the same arena. */ +void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, + const upb_msglayout *l, upb_arena *a); -/* For a primitive field, set it back to its default. For repeated, string, and - * submessage fields set it back to NULL. This could involve releasing some - * internal memory (for example, from an extension dictionary), but it is not - * recursive in any way and will not recover any memory that may be used by - * arrays/maps/strings/msgs that this field may have pointed to. - */ -bool upb_msg_clearfield(upb_msg *msg, - int field_index, +/* Clears any field presence and sets the value back to its default. */ +void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l); -/* TODO(haberman): copyfrom()/mergefrom()? */ - /** upb_array *****************************************************************/ -/* A upb_array stores data for a repeated field. The memory management - * semantics are the same as upb_msg. A upb_array allocates dynamic - * memory internally for the array elements. */ - -/* Read-only interface. Safe for anyone to call. */ - +/* Returns the size of the array. */ size_t upb_array_size(const upb_array *arr); -upb_msgval upb_array_get(const upb_array *arr, upb_fieldtype_t type, size_t i); -/* Write interface. May only be called by the message's owner who can enforce - * its memory management invariants. */ +/* Returns the given element. */ +upb_msgval upb_array_get(const upb_array *arr, size_t i); -bool upb_array_set(upb_array *arr, upb_fieldtype_t type, size_t i, - upb_msgval val, upb_arena *arena); +/* Sets the given element, which must be within the array's current size. */ +void upb_array_set(upb_array *arr, size_t i, upb_msgval val); -/** upb_map *******************************************************************/ +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_array_append(upb_array *array, upb_msgval val); -/* A upb_map stores data for a map field. The memory management semantics are - * the same as upb_msg, with one notable exception. upb_map will internally - * store a copy of all string keys, but *not* any string values or submessages. - * So you must ensure that any string or message values outlive the map, and you - * must delete them manually when they are no longer required. */ +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_array_resize(upb_array *array, size_t size); -/* Read-only interface. Safe for anyone to call. */ +/** upb_map *******************************************************************/ +/* Returns the number of entries in the map. */ size_t upb_map_size(const upb_map *map); -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val, - const upb_msglayout *l); -/* Write interface. May only be called by the message's owner who can enforce - * its memory management invariants. */ +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); -/* Sets or overwrites an entry in the map. Return value indicates whether - * the operation succeeded or failed with OOM, and also whether an existing - * key was replaced or not. */ -bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, - const upb_msglayout *l, upb_arena *arena); +/* Removes all entries in the map. */ +void upb_map_clear(upb_map *map); -/* Deletes an entry in the map. Returns true if the key was present. */ -bool upb_map_del(upb_map *map, upb_msgval key, const upb_msglayout *l, - upb_arena *arena); +/* Sets the given key to the given value. Returns true if this was a new key in + * the map, or false if an existing key was replaced. */ +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val); + +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_map_delete(upb_map *map, upb_msgval key); /** upb_mapiter ***************************************************************/ /* For iterating over a map. Map iterators are invalidated by mutations to the - * map, but an invalidated iterator will never return junk or crash the process. - * An invalidated iterator may return entries that were already returned though, - * and if you keep invalidating the iterator during iteration, the program may - * enter an infinite loop. */ + * map, but an invalidated iterator will never return junk or crash the process + * (this is an important property when exposing iterators to interpreted + * languages like Ruby, PHP, etc). An invalidated iterator may return entries + * that were already returned though, and if you keep invalidating the iterator + * during iteration, the program may enter an infinite loop. */ +struct upb_mapiter; +typedef struct upb_mapiter upb_mapiter; size_t upb_mapiter_sizeof(void); -void upb_mapiter_begin(upb_mapiter *i, const upb_msglayout *layout, - const upb_map *t); -upb_mapiter *upb_mapiter_new(const upb_map *t, const upb_msglayout *layout, - upb_alloc *a); -void upb_mapiter_free(upb_mapiter *i, upb_alloc *a); +/* Starts iteration. If the map is mutable then we can modify entries while + * iterating. */ +void upb_mapiter_constbegin(upb_mapiter *i, const upb_map *t); +void upb_mapiter_begin(upb_mapiter *i, upb_map *t); + +/* Sets the iterator to "done" state. This will return "true" from + * upb_mapiter_done() and will compare equal to other "done" iterators. */ +void upb_mapiter_setdone(upb_mapiter *i); + +/* Advances to the next entry. The iterator must not be done. */ void upb_mapiter_next(upb_mapiter *i); -bool upb_mapiter_done(const upb_mapiter *i); +/* Returns the key and value for this entry of the map. */ upb_msgval upb_mapiter_key(const upb_mapiter *i); upb_msgval upb_mapiter_value(const upb_mapiter *i); -void upb_mapiter_setdone(upb_mapiter *i); + +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_mapiter_setvalue(const upb_mapiter *i, upb_msgval value); + +/* Returns true if the iterator is done. */ +bool upb_mapiter_done(const upb_mapiter *i); + +/* Compares two iterators for equality. */ bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2); #include "upb/port_undef.inc" diff --git a/upb/msg.c b/upb/msg.c index 41bacd861c..80bd7c1392 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -7,6 +7,8 @@ #define VOIDPTR_AT(msg, ofs) (void*)((char*)msg + (int)ofs) +/** upb_msg *******************************************************************/ + /* Internal members of a upb_msg. We can change this without breaking binary * compatibility. We put these before the user's data. The user's upb_msg* * points after the upb_msg_internal. */ @@ -24,6 +26,21 @@ typedef struct { upb_msg_internal base; } upb_msg_internal_withext; +char _upb_fieldtype_to_size[12] = { + 0, + 1, /* UPB_TYPE_BOOL */ + 4, /* UPB_TYPE_FLOAT */ + 4, /* UPB_TYPE_INT32 */ + 4, /* UPB_TYPE_UINT32 */ + 4, /* UPB_TYPE_ENUM */ + sizeof(void*), /* UPB_TYPE_STRING */ + sizeof(void*), /* UPB_TYPE_BYTES */ + sizeof(void*), /* UPB_TYPE_MESSAGE */ + 8, /* UPB_TYPE_DOUBLE */ + 8, /* UPB_TYPE_INT64 */ + 8, /* UPB_TYPE_UINT64 */ +}; + static int upb_msg_internalsize(const upb_msglayout *l) { return sizeof(upb_msg_internal) - l->extendable * sizeof(void *); } @@ -74,6 +91,28 @@ upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { return msg; } +void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, + upb_arena *arena) { + upb_msg_internal *in = upb_msg_getinternal(msg); + if (len > in->unknown_size - in->unknown_len) { + upb_alloc *alloc = upb_arena_alloc(arena); + size_t need = in->unknown_size + len; + size_t newsize = UPB_MAX(in->unknown_size * 2, need); + in->unknown = upb_realloc(alloc, in->unknown, in->unknown_size, newsize); + in->unknown_size = newsize; + } + memcpy(in->unknown + in->unknown_len, data, len); + in->unknown_len += len; +} + +const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { + const upb_msg_internal* in = upb_msg_getinternal_const(msg); + *len = in->unknown_len; + return in->unknown; +} + +/** upb_array *****************************************************************/ + static void upb_array_init(upb_array *arr) { arr->data = NULL; arr->len = 0; @@ -92,7 +131,44 @@ upb_array *upb_array_new(upb_arena *a) { return arr; } -upb_map *upb_map_new(upb_arena *a) { +bool _upb_array_realloc(upb_array *arr, size_t min_size, int elem_size, + upb_arena *arena) { + size_t new_size = UPB_MAX(arr->size, 4); + size_t old_bytes = arr->size * elem_size; + size_t new_bytes; + while (new_size < min_size) new_size *= 2; + new_bytes = new_size * elem_size; + arr->data = upb_arena_realloc(arena, arr->data, old_bytes, new_bytes); + if (!arr->data) { + arr->len = 0; + arr->size = 0; + return false; + } + arr->size = new_size; + return true; +} + +void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, int elem_size, + upb_arena *arena) { + upb_array *arr = *arr_ptr; + if (!arr) { + arr = upb_array_new(arena); + if (!arr) return NULL; + *arr_ptr = arr; + } + + if (size > arr->size && !_upb_array_realloc(arr, size, elem_size, arena)) { + return NULL; + } + + arr->len = size; + return arr->data; +} + +/** upb_map *******************************************************************/ + +upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, + upb_fieldtype_t value_type) { upb_map *map = upb_arena_malloc(a, sizeof(upb_map)); if (!map) { @@ -100,28 +176,11 @@ upb_map *upb_map_new(upb_arena *a) { } upb_strtable_init(&map->table, UPB_CTYPE_INT32); + map->key_type = key_type; + map->value_type = value_type; return map; } -void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena) { - upb_msg_internal *in = upb_msg_getinternal(msg); - if (len > in->unknown_size - in->unknown_len) { - upb_alloc *alloc = upb_arena_alloc(arena); - size_t need = in->unknown_size + len; - size_t newsize = UPB_MAX(in->unknown_size * 2, need); - in->unknown = upb_realloc(alloc, in->unknown, in->unknown_size, newsize); - in->unknown_size = newsize; - } - memcpy(in->unknown + in->unknown_len, data, len); - in->unknown_len += len; -} - -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { - const upb_msg_internal* in = upb_msg_getinternal_const(msg); - *len = in->unknown_len; - return in->unknown; -} #undef VOIDPTR_AT diff --git a/upb/msg.h b/upb/msg.h index d8a6defe8f..6c9d3eba62 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -1,7 +1,6 @@ /* -** Data structures for message tables, used for parsing and serialization. -** This are much lighter-weight than full reflection, but they are do not -** have enough information to convert to text format, JSON, etc. +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possible reflection. ** ** The definitions in this file are internal to upb. **/ @@ -46,29 +45,61 @@ typedef struct upb_msglayout { bool extendable; } upb_msglayout; -/** Message internal representation *******************************************/ +/** upb_msg *******************************************************************/ -/* Our internal representation for repeated fields. */ +/* Representation is in msg.c for now. */ + +/* Maps upb_fieldtype_t -> memory size. */ +extern char _upb_fieldtype_to_size[12]; + +/* Creates a new messages with the given layout on the given arena. */ +upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); + +/* 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); + +/** upb_array *****************************************************************/ + +/* Our internal representation for repeated fields. */ typedef struct { - void *data; /* Each element is element_size. */ + void *data; /* Tagged: low 2 bits of ptr are lg2(elem size). */ size_t len; /* Measured in elements. */ size_t size; /* Measured in elements. */ } upb_array; -/* Our internal representation for maps. Right now we use strmaps for - * everything. We'll likely want to use integer-specific maps for - * integer-keyed maps.*/ +/* Creates a new array on the given arena. */ +upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type); + +/* Resizes the capacity of the array to be at least min_size. */ +bool _upb_array_realloc(upb_array *arr, size_t min_size, int elem_size, + upb_arena *arena); + +/* Fallback functions for when the accessors require a resize. */ +void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, int elem_size, + upb_arena *arena); +bool _upb_array_append_fallback(upb_array **arr_ptr, int elem_size, + const void *value, upb_arena *arena); + +/** upb_map *******************************************************************/ + +/* Right now we use strmaps for everything. We'll likely want to use + * integer-specific maps for integer-keyed maps.*/ typedef struct { + /* We should pack these better and move them into table to avoid padding. */ + upb_fieldtype_t key_type; + upb_fieldtype_t value_type; + upb_strtable table; } upb_map; -upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); -upb_array *upb_array_new(upb_arena *a); -upb_map *upb_map_new(upb_arena *a); - -void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena); -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); +/* Creates a new map on the given arena with this key/value type. */ +upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, + upb_fieldtype_t value_type); #ifdef __cplusplus } /* extern "C" */ diff --git a/upbc/generator.cc b/upbc/generator.cc index 4d87a4f0f4..4419cc834c 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -429,37 +429,32 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output output( "UPB_INLINE $0* $1_resize_$2($1 *msg, size_t len, " "upb_arena *arena) {\n" - " return ($0*)_upb_array_resize_accessor(msg, $3, len, $4, $5, " - "arena);\n" + " return ($0*)_upb_array_resize_accessor(msg, $3, len, $4, arena);\n" "}\n", CType(field), msgname, field->name(), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size), - UpbType(field)); + GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size)); if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { output( "UPB_INLINE struct $0* $1_add_$2($1 *msg, upb_arena *arena) {\n" " struct $0* sub = (struct $0*)upb_msg_new(&$3, arena);\n" - " bool ok = _upb_array_append_accessor(\n" - " msg, $4, $5, $6, &sub, arena);\n" + " bool ok = _upb_array_append_accessor(" + " msg, $4, $5, &sub, arena);\n" " if (!ok) return NULL;\n" " return sub;\n" "}\n", MessageName(field->message_type()), msgname, field->name(), MessageInit(field->message_type()), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size), - UpbType(field)); + GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size)); } else { output( "UPB_INLINE bool $1_add_$2($1 *msg, $0 val, upb_arena *arena) {\n" - " return _upb_array_append_accessor(\n" - " msg, $3, $4, $5, &val, arena);\n" + " return _upb_array_append_accessor(msg, $3, $4, &val, arena);\n" "}\n", CType(field), msgname, field->name(), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size), - UpbType(field)); + GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size)); } } else { // Non-repeated field. From dc58b657eeb308b52939e4c487b0cb05bf03b837 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 11 Nov 2019 23:05:18 -0800 Subject: [PATCH 05/35] New reflection API doesn't need types as parameters for map/array. All tests are passing again. --- CMakeLists.txt | 3 +- .../google/protobuf/descriptor.upb.h | 108 +++++++++--------- upb/bindings/lua/msg.c | 43 ++++--- upb/decode.c | 34 ++---- upb/encode.c | 20 ++-- upb/generated_util.h | 17 +-- upb/legacy_msg_reflection.c | 61 +++++++--- upb/legacy_msg_reflection.h | 7 +- upb/msg.c | 72 ++++++------ upb/msg.h | 25 ++-- upb/upb.h | 15 +-- upbc/generator.cc | 15 ++- 12 files changed, 234 insertions(+), 186 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 836c5ff1fe..19752386eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,8 @@ add_library(legacy_msg_reflection upb/legacy_msg_reflection.h) target_link_libraries(legacy_msg_reflection table - upb) + upb + reflection) add_library(handlers upb/handlers.c upb/handlers-inl.h diff --git a/generated_for_cmake/google/protobuf/descriptor.upb.h b/generated_for_cmake/google/protobuf/descriptor.upb.h index 681614910e..c8c392185a 100644 --- a/generated_for_cmake/google/protobuf/descriptor.upb.h +++ b/generated_for_cmake/google/protobuf/descriptor.upb.h @@ -174,7 +174,7 @@ UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorS return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_arena *arena) { struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); @@ -228,17 +228,17 @@ UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_mutable_dependency(g return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_SIZE(8, 16), UPB_TYPE_STRING, arena); + return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_STRING, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(36, 72), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(36, 72), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, + arena); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); @@ -251,7 +251,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorP return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); @@ -264,7 +264,7 @@ UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescript return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); } UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(48, 96), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(48, 96), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); @@ -277,7 +277,7 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptor return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(52, 104), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(52, 104), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); @@ -316,21 +316,21 @@ UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependenc return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(56, 112), len, UPB_SIZE(4, 4), UPB_TYPE_INT32, arena); + return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(56, 112), len, UPB_TYPE_INT32, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(56, 112), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(56, 112), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, + arena); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(60, 120), len, UPB_SIZE(4, 4), UPB_TYPE_INT32, arena); + return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(60, 120), len, UPB_TYPE_INT32, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(60, 120), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(60, 120), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, + arena); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_strview value) { _upb_sethas(msg, 3); @@ -372,7 +372,7 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); @@ -385,7 +385,7 @@ UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mut return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); @@ -398,7 +398,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); @@ -411,7 +411,7 @@ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_Desc return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); @@ -424,7 +424,7 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(32, 64), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(32, 64), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); @@ -450,7 +450,7 @@ UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); @@ -463,7 +463,7 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_Descr return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); } UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); @@ -476,11 +476,11 @@ UPB_INLINE upb_strview* google_protobuf_DescriptorProto_mutable_reserved_name(go return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); } UPB_INLINE upb_strview* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_SIZE(8, 16), UPB_TYPE_STRING, arena); + return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_STRING, arena); } UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(44, 88), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(44, 88), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, + arena); } /* google.protobuf.DescriptorProto.ExtensionRange */ @@ -574,7 +574,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeO return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -736,7 +736,7 @@ UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescri return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); @@ -762,7 +762,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protob return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); @@ -775,11 +775,11 @@ UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_mutable_reserved_nam return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_SIZE(8, 16), UPB_TYPE_STRING, arena); + return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_STRING, arena); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(24, 48), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(24, 48), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, + arena); } /* google.protobuf.EnumDescriptorProto.EnumReservedRange */ @@ -881,7 +881,7 @@ UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescri return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); @@ -1105,7 +1105,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mut return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(108, 192), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(108, 192), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(108, 192), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1159,7 +1159,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_ return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(8, 8), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(8, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1225,7 +1225,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mu return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 32), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 32), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1255,7 +1255,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mu return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1297,7 +1297,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mut return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1333,7 +1333,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOption return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1369,7 +1369,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_ return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1411,7 +1411,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_m return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 24), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 24), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); @@ -1453,7 +1453,7 @@ UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_Uninte return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor(msg, UPB_SIZE(56, 80), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor(msg, UPB_SIZE(56, 80), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_arena *arena) { struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); @@ -1535,7 +1535,7 @@ UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeI return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_arena *arena) { - return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_arena *arena) { struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); @@ -1571,21 +1571,21 @@ UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_ return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_SIZE(4, 4), UPB_TYPE_INT32, arena); + return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_INT32, arena); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(20, 40), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(20, 40), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, + arena); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_SIZE(4, 4), UPB_TYPE_INT32, arena); + return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_INT32, arena); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(24, 48), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(24, 48), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, + arena); } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview value) { _upb_sethas(msg, 1); @@ -1599,11 +1599,11 @@ UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_mutable_leading_ return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_SIZE(8, 16), UPB_TYPE_STRING, arena); + return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_STRING, arena); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(28, 56), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(28, 56), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, + arena); } /* google.protobuf.GeneratedCodeInfo */ @@ -1626,7 +1626,7 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_Genera return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_arena *arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, arena); + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena) { struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); @@ -1662,11 +1662,11 @@ UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(go return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); } UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 32), len, UPB_SIZE(4, 4), UPB_TYPE_INT32, arena); + return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 32), len, UPB_TYPE_INT32, arena); } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor( - msg, UPB_SIZE(20, 32), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, arena); + return _upb_array_append_accessor(msg, UPB_SIZE(20, 32), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, + arena); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_strview value) { _upb_sethas(msg, 3); diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 8d319bc905..2d747a3d5c 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -549,18 +549,23 @@ static int lupb_array_new(lua_State *L) { larray = lupb_newuserdata(L, sizeof(*larray), LUPB_ARRAY); larray->type = type; larray->lmsgclass = lmsgclass; - larray->arr = upb_array_new(lupb_arena_get(L)); + larray->arr = upb_array_new(lupb_arena_get(L), type); return 1; } static int lupb_array_newindex(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); + size_t size = upb_array_size(larray->arr); upb_fieldtype_t type = larray->type; - uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(larray->arr) + 1); + uint32_t n = lupb_array_checkindex(L, 2, size + 1); upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->lmsgclass); - upb_array_set(larray->arr, larray->type, n, msgval, lupb_arena_get(L)); + if (n == size) { + upb_array_append(larray->arr, msgval, lupb_arena_get(L)); + } else { + upb_array_set(larray->arr, n, msgval); + } if (lupb_istypewrapped(type)) { lupb_uservalseti(L, 1, n, 3); @@ -571,14 +576,15 @@ static int lupb_array_newindex(lua_State *L) { static int lupb_array_index(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); - upb_array *array = larray->arr; - uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(array)); + size_t size = upb_array_size(larray->arr); + uint32_t n = lupb_array_checkindex(L, 2, size); upb_fieldtype_t type = larray->type; if (lupb_istypewrapped(type)) { lupb_uservalgeti(L, 1, n); } else { - lupb_pushmsgval(L, type, upb_array_get(array, type, n)); + upb_msgval val = upb_array_get(larray->arr, n); + lupb_pushmsgval(L, type, val); } return 1; @@ -638,6 +644,7 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, const upb_msgdef *entry = upb_fielddef_msgsubdef(f); const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); + upb_msgval val; UPB_ASSERT(entry && key_field && value_field); @@ -657,7 +664,8 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, lmap->value_lmsgclass); } - return upb_msgval_map(map); + val.map_val = map; + return val; } /* lupb_map Public API */ @@ -690,7 +698,7 @@ static int lupb_map_new(lua_State *L) { lmap->key_type = key_type; lmap->value_type = value_type; lmap->value_lmsgclass = value_lmsgclass; - lmap->map = upb_map_new(key_type, value_type, lupb_arena_get(L)); + lmap->map = upb_map_new(lupb_arena_get(L), key_type, value_type); return 1; } @@ -756,7 +764,7 @@ static int lupb_map_newindex(lua_State *L) { if (lua_isnil(L, 3)) { /* Delete from map. */ - upb_map_del(map, key); + upb_map_delete(map, key); if (lupb_istypewrapped(lmap->value_type)) { /* Delete in userval. */ @@ -771,7 +779,7 @@ static int lupb_map_newindex(lua_State *L) { upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, lmap->value_lmsgclass); - upb_map_set(map, key, val, NULL); + upb_map_set(map, key, val, lupb_arena_get(L)); if (lupb_istypewrapped(lmap->value_type)) { /* Set in userval. */ @@ -791,7 +799,6 @@ static int lupb_map_newindex(lua_State *L) { static int lupb_mapiter_next(lua_State *L) { upb_mapiter *i = lua_touserdata(L, lua_upvalueindex(1)); lupb_map *lmap = lupb_map_check(L, 1); - upb_map *map = lmap->map; if (upb_mapiter_done(i)) { return 0; @@ -969,7 +976,6 @@ static int lupb_msg_index(lua_State *L) { lupb_msg *lmsg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); const upb_msglayout *l = lmsg->lmsgclass->layout; - int field_index = upb_fielddef_index(f); if (in_userval(f)) { lupb_uservalgeti(L, 1, lupb_fieldindex(f)); @@ -982,16 +988,16 @@ static int lupb_msg_index(lua_State *L) { /* TODO(haberman) */ } else { UPB_ASSERT(upb_fielddef_isstring(f)); - if (upb_msg_has(lmsg->msg, field_index, l)) { - upb_msgval val = upb_msg_get(lmsg->msg, field_index, l); + if (upb_msg_has(lmsg->msg, f, l)) { + upb_msgval val = upb_msg_get(lmsg->msg, f, l); lua_pop(L, 1); - lua_pushlstring(L, val.str.data, val.str.size); + lua_pushlstring(L, val.str_val.data, val.str_val.size); lupb_uservalseti(L, 1, lupb_fieldindex(f), -1); } } } } else { - upb_msgval val = upb_msg_get(lmsg->msg, field_index, l); + upb_msgval val = upb_msg_get(lmsg->msg, f, l); lupb_pushmsgval(L, upb_fielddef_type(f), val); } @@ -1010,7 +1016,8 @@ static int lupb_msg_newindex(lua_State *L) { lupb_msg *lmsg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); upb_fieldtype_t type = upb_fielddef_type(f); - int field_index = upb_fielddef_index(f); + upb_arena *arena = lupb_arena_get(L); + const upb_msglayout *layout = lmsg->lmsgclass->layout; upb_msgval msgval; /* Typecheck and get msgval. */ @@ -1031,7 +1038,7 @@ static int lupb_msg_newindex(lua_State *L) { /* Set in upb_msg and userval (if necessary). */ - upb_msg_set(lmsg->msg, field_index, msgval, lmsg->lmsgclass->layout); + upb_msg_set(lmsg->msg, f, msgval, layout, arena); if (in_userval(f)) { lupb_uservalseti(L, 1, lupb_fieldindex(f), 3); diff --git a/upb/decode.c b/upb/decode.c index 4f07988595..1565a316ce 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -45,7 +45,9 @@ typedef struct { upb_decstate *state; } upb_decframe; -#define CHK(x) if (!(x)) { return 0; } +#define CHK(x) if (!(x)) { \ + fprintf(stderr, "Failure at %s:%d\n", __FILE__, __LINE__); \ + return 0; } static bool upb_skip_unknowngroup(upb_decstate *d, int field_number); static bool upb_decode_message(upb_decstate *d, char *msg, @@ -166,35 +168,12 @@ static bool upb_skip_unknowngroup(upb_decstate *d, int field_number) { return true; } -static bool upb_array_grow(upb_array *arr, size_t elements, size_t elem_size, - upb_arena *arena) { - size_t needed = arr->len + elements; - size_t new_size = UPB_MAX(arr->size, 8); - size_t new_bytes; - size_t old_bytes; - void *new_data; - upb_alloc *alloc = upb_arena_alloc(arena); - - while (new_size < needed) { - new_size *= 2; - } - - old_bytes = arr->len * elem_size; - new_bytes = new_size * elem_size; - new_data = upb_realloc(alloc, arr->data, old_bytes, new_bytes); - CHK(new_data); - - arr->data = new_data; - arr->size = new_size; - return true; -} - static void *upb_array_reserve(upb_array *arr, size_t elements, size_t elem_size, upb_arena *arena) { if (arr->size - arr->len < elements) { - CHK(upb_array_grow(arr, elements, elem_size, arena)); + CHK(_upb_array_realloc(arr, arr->len + elements, arena)); } - return (char*)arr->data + (arr->len * elem_size); + return (char*)_upb_array_ptr(arr) + (arr->len * elem_size); } bool upb_array_add(upb_array *arr, size_t elements, size_t elem_size, @@ -219,7 +198,8 @@ static upb_array *upb_getorcreatearr(upb_decframe *frame, upb_array *arr = upb_getarr(frame, field); if (!arr) { - arr = upb_array_new(frame->state->arena); + upb_fieldtype_t type = upb_desctype_to_fieldtype[field->descriptortype]; + arr = upb_array_new(frame->state->arena, type); CHK(arr); *(upb_array**)&frame->msg[field->offset] = arr; } diff --git a/upb/encode.c b/upb/encode.c index 43d24cdbfc..a86f67c381 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -70,6 +70,7 @@ static bool upb_encode_reserve(upb_encstate *e, size_t bytes) { /* Writes the given bytes to the buffer, handling reserve/advance. */ static bool upb_put_bytes(upb_encstate *e, const void *data, size_t len) { + if (len == 0) return true; CHK(upb_encode_reserve(e, len)); memcpy(e->ptr, data, len); return true; @@ -130,7 +131,8 @@ static bool upb_put_tag(upb_encstate *e, int field_number, int wire_type) { static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr, size_t size) { size_t bytes = arr->len * size; - return upb_put_bytes(e, arr->data, bytes) && upb_put_varint(e, bytes); + const void* data = _upb_array_constptr(arr); + return upb_put_bytes(e, data, bytes) && upb_put_varint(e, bytes); } bool upb_encode_message(upb_encstate *e, const char *msg, @@ -146,8 +148,8 @@ static bool upb_encode_array(upb_encstate *e, const char *field_mem, } #define VARINT_CASE(ctype, encode) { \ - ctype *start = arr->data; \ - ctype *ptr = start + arr->len; \ + const ctype *start = _upb_array_constptr(arr); \ + const ctype *ptr = start + arr->len; \ size_t pre_len = e->limit - e->ptr; \ do { \ ptr--; \ @@ -189,8 +191,8 @@ do { ; } while(0) VARINT_CASE(int64_t, upb_zzencode_64(*ptr)); case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: { - upb_strview *start = arr->data; - upb_strview *ptr = start + arr->len; + const upb_strview *start = _upb_array_constptr(arr); + const upb_strview *ptr = start + arr->len; do { ptr--; CHK(upb_put_bytes(e, ptr->data, ptr->size) && @@ -200,8 +202,8 @@ do { ; } while(0) return true; } case UPB_DESCRIPTOR_TYPE_GROUP: { - void **start = arr->data; - void **ptr = start + arr->len; + const void *const*start = _upb_array_constptr(arr); + const void *const*ptr = start + arr->len; const upb_msglayout *subm = m->submsgs[f->submsg_index]; do { size_t size; @@ -213,8 +215,8 @@ do { ; } while(0) return true; } case UPB_DESCRIPTOR_TYPE_MESSAGE: { - void **start = arr->data; - void **ptr = start + arr->len; + const void *const*start = _upb_array_constptr(arr); + const void *const*ptr = start + arr->len; const upb_msglayout *subm = m->submsgs[f->submsg_index]; do { size_t size; diff --git a/upb/generated_util.h b/upb/generated_util.h index 8151e45583..ac01a27b5c 100644 --- a/upb/generated_util.h +++ b/upb/generated_util.h @@ -18,7 +18,7 @@ UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs, const upb_array *arr = *PTR_AT(msg, ofs, const upb_array*); if (arr) { if (size) *size = arr->len; - return arr->data; + return _upb_array_constptr(arr); } else { if (size) *size = 0; return NULL; @@ -30,7 +30,7 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, upb_array *arr = *PTR_AT(msg, ofs, upb_array*); if (arr) { if (size) *size = arr->len; - return arr->data; + return _upb_array_ptr(arr); } else { if (size) *size = 0; return NULL; @@ -38,27 +38,30 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, } UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, - size_t elem_size, + upb_fieldtype_t type, upb_arena *arena) { upb_array **arr_ptr = 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, arena); + return _upb_array_resize_fallback(arr_ptr, size, type, arena); } arr->len = size; - return arr->data; + return _upb_array_ptr(arr); } UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, size_t elem_size, + upb_fieldtype_t type, const void *value, upb_arena *arena) { upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); upb_array *arr = *arr_ptr; + void* ptr; if (!arr || arr->len == arr->size) { - return _upb_array_append_fallback(arr_ptr, elem_size, value, arena); + return _upb_array_append_fallback(arr_ptr, value, type, arena); } - memcpy(PTR_AT(arr->data, arr->len * elem_size, char), value, elem_size); + ptr = _upb_array_ptr(arr); + memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); arr->len++; return true; } diff --git a/upb/legacy_msg_reflection.c b/upb/legacy_msg_reflection.c index ab0ad8e8e0..4f1ab970db 100644 --- a/upb/legacy_msg_reflection.c +++ b/upb/legacy_msg_reflection.c @@ -172,26 +172,59 @@ size_t upb_array_size(const upb_array *arr) { return arr->len; } -const void *upb_array_get(const upb_array *arr, size_t *size) { - if (size) *size = arr->len; - return arr->data; +upb_msgval upb_array_get(const upb_array *arr, size_t i) { + UPB_ASSERT(i < arr->len); + const char* data = _upb_array_constptr(arr); + int elem_size_lg2 = arr->data & 7; + upb_msgval ret; + + switch (elem_size_lg2) { + case 0: + ret.bool_val = *PTR_AT(data, i, bool); + break; + case 2: + memcpy(&ret, data + i * 4, 4); + break; + case 3: + memcpy(&ret, data + i * 8, 8); + break; + case 4: + memcpy(&ret, data + i * 16, 16); + break; + default: + UPB_UNREACHABLE(); + } + + return ret; } -void* upb_array_getmutable(upb_array *arr, size_t *size) { - if (size) *size = arr->len; - return arr->data; +void upb_array_set(upb_array *arr, size_t i, upb_msgval val) { + UPB_ASSERT(i < arr->len); + char* data = _upb_array_ptr(arr); + int elem_size_lg2 = arr->data & 7; + + switch (elem_size_lg2) { + case 0: + *PTR_AT(data, i, bool) = val.bool_val; + break; + case 2: + memcpy(data + i * 4, &val, 4); + break; + case 3: + memcpy(data + i * 8, &val, 8); + break; + case 4: + memcpy(data + i * 16, &val, 16); + break; + default: + UPB_UNREACHABLE(); + } } /* Resizes the array to the given size, reallocating if necessary, and returns a * pointer to the new array elements. */ -void *upb_array_resize(upb_array *arr, size_t size, upb_fieldtype_t type, - upb_arena *arena) { - int elem_size = _upb_fieldtype_to_size[type]; - if (size > arr->size && !_upb_array_realloc(arr, size, elem_size, arena)) { - return NULL; - } - arr->len = size; - return arr->data; +bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) { + return _upb_array_realloc(arr, size, arena); } #if 0 diff --git a/upb/legacy_msg_reflection.h b/upb/legacy_msg_reflection.h index cd6db7c1ec..b23ceaeb01 100644 --- a/upb/legacy_msg_reflection.h +++ b/upb/legacy_msg_reflection.h @@ -65,11 +65,11 @@ upb_msgval upb_array_get(const upb_array *arr, size_t i); void upb_array_set(upb_array *arr, size_t i, upb_msgval val); /* Appends an element to the array. Returns false on allocation failure. */ -bool upb_array_append(upb_array *array, upb_msgval val); +bool upb_array_append(upb_array *array, upb_msgval val, upb_arena *arena); /* Changes the size of a vector. New elements are initialized to empty/0. * Returns false on allocation failure. */ -bool upb_array_resize(upb_array *array, size_t size); +bool upb_array_resize(upb_array *array, size_t size, upb_arena *arena); /** upb_map *******************************************************************/ @@ -86,7 +86,8 @@ void upb_map_clear(upb_map *map); /* Sets the given key to the given value. Returns true if this was a new key in * the map, or false if an existing key was replaced. */ -bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val); +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, + upb_arena *arena); /* Deletes this key from the table. Returns true if the key was present. */ bool upb_map_delete(upb_map *map, upb_msgval key); diff --git a/upb/msg.c b/upb/msg.c index 80bd7c1392..0a70847a12 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -26,21 +26,26 @@ typedef struct { upb_msg_internal base; } upb_msg_internal_withext; -char _upb_fieldtype_to_size[12] = { +char _upb_fieldtype_to_sizelg2[12] = { 0, - 1, /* UPB_TYPE_BOOL */ - 4, /* UPB_TYPE_FLOAT */ - 4, /* UPB_TYPE_INT32 */ - 4, /* UPB_TYPE_UINT32 */ - 4, /* UPB_TYPE_ENUM */ - sizeof(void*), /* UPB_TYPE_STRING */ - sizeof(void*), /* UPB_TYPE_BYTES */ - sizeof(void*), /* UPB_TYPE_MESSAGE */ - 8, /* UPB_TYPE_DOUBLE */ - 8, /* UPB_TYPE_INT64 */ - 8, /* UPB_TYPE_UINT64 */ + 0, /* UPB_TYPE_BOOL */ + 2, /* UPB_TYPE_FLOAT */ + 2, /* UPB_TYPE_INT32 */ + 2, /* UPB_TYPE_UINT32 */ + 2, /* UPB_TYPE_ENUM */ + UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */ + 3, /* UPB_TYPE_DOUBLE */ + 3, /* UPB_TYPE_INT64 */ + 3, /* UPB_TYPE_UINT64 */ + UPB_SIZE(3, 4), /* UPB_TYPE_STRING */ + UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */ }; +static uintptr_t tag_arrptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + return (uintptr_t)ptr | elem_size_lg2; +} + static int upb_msg_internalsize(const upb_msglayout *l) { return sizeof(upb_msg_internal) - l->extendable * sizeof(void *); } @@ -113,56 +118,57 @@ const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { /** upb_array *****************************************************************/ -static void upb_array_init(upb_array *arr) { - arr->data = NULL; - arr->len = 0; - arr->size = 0; -} - -upb_array *upb_array_new(upb_arena *a) { +upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) { upb_array *arr = upb_arena_malloc(a, sizeof(upb_array)); if (!arr) { return NULL; } - upb_array_init(arr); + arr->data = tag_arrptr(NULL, _upb_fieldtype_to_sizelg2[type]); + arr->len = 0; + arr->size = 0; return arr; } -bool _upb_array_realloc(upb_array *arr, size_t min_size, int elem_size, - upb_arena *arena) { +bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) { size_t new_size = UPB_MAX(arr->size, 4); - size_t old_bytes = arr->size * elem_size; + int elem_size_lg2 = arr->data & 7; + size_t old_bytes = arr->size << elem_size_lg2; size_t new_bytes; + void* ptr = _upb_array_ptr(arr); + + /* Log2 ceiling of size. */ while (new_size < min_size) new_size *= 2; - new_bytes = new_size * elem_size; - arr->data = upb_arena_realloc(arena, arr->data, old_bytes, new_bytes); - if (!arr->data) { - arr->len = 0; - arr->size = 0; + + new_bytes = new_size << elem_size_lg2; + ptr = upb_arena_realloc(arena, ptr, old_bytes, new_bytes); + + if (!ptr) { return false; } + + arr->data = tag_arrptr(ptr, elem_size_lg2); arr->size = new_size; return true; } -void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, int elem_size, - upb_arena *arena) { +void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, + upb_fieldtype_t type, upb_arena *arena) { upb_array *arr = *arr_ptr; if (!arr) { - arr = upb_array_new(arena); + arr = upb_array_new(arena, type); if (!arr) return NULL; *arr_ptr = arr; } - if (size > arr->size && !_upb_array_realloc(arr, size, elem_size, arena)) { + if (size > arr->size && !_upb_array_realloc(arr, size, arena)) { return NULL; } arr->len = size; - return arr->data; + return _upb_array_ptr(arr); } /** upb_map *******************************************************************/ diff --git a/upb/msg.h b/upb/msg.h index 6c9d3eba62..a7b595b9e5 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -14,6 +14,8 @@ #include "upb/table.int.h" #include "upb/upb.h" +#include "upb/port_def.inc" + #ifdef __cplusplus extern "C" { #endif @@ -67,23 +69,30 @@ const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); /* Our internal representation for repeated fields. */ typedef struct { - void *data; /* Tagged: low 2 bits of ptr are lg2(elem size). */ + uintptr_t data; /* Tagged ptr: low 2 bits of ptr are lg2(elem size). */ size_t len; /* Measured in elements. */ size_t size; /* Measured in elements. */ } upb_array; +UPB_INLINE const void *_upb_array_constptr(const upb_array *arr) { + return (void*)((uintptr_t)arr->data & ~7UL); +} + +UPB_INLINE void *_upb_array_ptr(upb_array *arr) { + return (void*)_upb_array_constptr(arr); +} + /* Creates a new array on the given arena. */ upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type); /* Resizes the capacity of the array to be at least min_size. */ -bool _upb_array_realloc(upb_array *arr, size_t min_size, int elem_size, - upb_arena *arena); +bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena); /* Fallback functions for when the accessors require a resize. */ -void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, int elem_size, - upb_arena *arena); -bool _upb_array_append_fallback(upb_array **arr_ptr, int elem_size, - const void *value, upb_arena *arena); +void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, + upb_fieldtype_t type, upb_arena *arena); +bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, + upb_fieldtype_t type, upb_arena *arena); /** upb_map *******************************************************************/ @@ -105,4 +114,6 @@ upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, } /* extern "C" */ #endif +#include "upb/port_undef.inc" + #endif /* UPB_MSG_H_ */ diff --git a/upb/upb.h b/upb/upb.h index 79c19d281e..e4c8adea67 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -318,14 +318,15 @@ typedef enum { UPB_TYPE_INT32 = 3, UPB_TYPE_UINT32 = 4, UPB_TYPE_ENUM = 5, /* Enum values are int32. */ - /* Types stored as pointers (probably 4 or 8 bytes). */ - UPB_TYPE_STRING = 6, - UPB_TYPE_BYTES = 7, - UPB_TYPE_MESSAGE = 8, + /* Types stored as void* (probably 4 or 8 bytes). */ + UPB_TYPE_MESSAGE = 6, /* Types stored as 8 bytes. */ - UPB_TYPE_DOUBLE = 9, - UPB_TYPE_INT64 = 10, - UPB_TYPE_UINT64 = 11 + UPB_TYPE_DOUBLE = 7, + UPB_TYPE_INT64 = 8, + UPB_TYPE_UINT64 = 9, + /* Types stored as upb_strview (2 * void*) (probably 8 or 16 bytes). */ + UPB_TYPE_STRING = 10, + UPB_TYPE_BYTES = 11, } upb_fieldtype_t; /* The repeated-ness of each field; this matches descriptor.proto. */ diff --git a/upbc/generator.cc b/upbc/generator.cc index 4419cc834c..3ef1f6dbf9 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -433,28 +433,31 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output "}\n", CType(field), msgname, field->name(), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size)); + UpbType(field)); if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { output( "UPB_INLINE struct $0* $1_add_$2($1 *msg, upb_arena *arena) {\n" " struct $0* sub = (struct $0*)upb_msg_new(&$3, arena);\n" - " bool ok = _upb_array_append_accessor(" - " msg, $4, $5, &sub, arena);\n" + " bool ok = _upb_array_append_accessor(\n" + " msg, $4, $5, $6, &sub, arena);\n" " if (!ok) return NULL;\n" " return sub;\n" "}\n", MessageName(field->message_type()), msgname, field->name(), MessageInit(field->message_type()), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size)); + GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size), + UpbType(field)); } else { output( "UPB_INLINE bool $1_add_$2($1 *msg, $0 val, upb_arena *arena) {\n" - " return _upb_array_append_accessor(msg, $3, $4, &val, arena);\n" + " return _upb_array_append_accessor(msg, $3, $4, $5, &val,\n" + " arena);\n" "}\n", CType(field), msgname, field->name(), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size)); + GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size), + UpbType(field)); } } else { // Non-repeated field. From 9a360ad43de6d69a1fb1de714f87e18206b484f8 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 12 Nov 2019 08:08:46 -0800 Subject: [PATCH 06/35] Moved legacy_msg_reflection.{c,h} -> reflection.{c.h}. --- BUILD | 21 +++---------------- CMakeLists.txt | 11 +++------- upb/bindings/lua/msg.c | 6 +++--- upb/{legacy_msg_reflection.c => reflection.c} | 2 +- upb/{legacy_msg_reflection.h => reflection.h} | 0 5 files changed, 10 insertions(+), 30 deletions(-) rename upb/{legacy_msg_reflection.c => reflection.c} (99%) rename upb/{legacy_msg_reflection.h => reflection.h} (100%) diff --git a/BUILD b/BUILD index a9a421fe15..dd72362762 100644 --- a/BUILD +++ b/BUILD @@ -116,10 +116,12 @@ cc_library( srcs = [ "upb/def.c", "upb/msgfactory.c", + "upb/reflection.c", ], hdrs = [ "upb/def.h", "upb/msgfactory.h", + "upb/reflection.h", ], copts = select({ ":windows": [], @@ -143,23 +145,6 @@ cc_library( # Legacy C/C++ Libraries (not recommended for new code) ######################## -cc_library( - name = "legacy_msg_reflection", - srcs = [ - "upb/legacy_msg_reflection.c", - ], - hdrs = ["upb/legacy_msg_reflection.h"], - copts = select({ - ":windows": [], - "//conditions:default": COPTS - }), - deps = [ - ":table", - ":upb", - ":reflection", - ], -) - cc_library( name = "handlers", srcs = [ @@ -592,7 +577,7 @@ lua_cclibrary( "upb/bindings/lua/upb.h", ], deps = [ - "legacy_msg_reflection", + "reflection", "upb", "upb_pb", ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 19752386eb..2393dedee6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,8 +81,10 @@ target_link_libraries(generated_code_support__only_for_generated_code_do_not_use add_library(reflection upb/def.c upb/msgfactory.c + upb/reflection.c upb/def.h - upb/msgfactory.h) + upb/msgfactory.h + upb/reflection.h) target_link_libraries(reflection descriptor_upbproto table @@ -90,13 +92,6 @@ target_link_libraries(reflection add_library(table INTERFACE) target_link_libraries(table INTERFACE upb) -add_library(legacy_msg_reflection - upb/legacy_msg_reflection.c - upb/legacy_msg_reflection.h) -target_link_libraries(legacy_msg_reflection - table - upb - reflection) add_library(handlers upb/handlers.c upb/handlers-inl.h diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 2d747a3d5c..49c7d3f185 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -2,6 +2,8 @@ ** lupb_msg -- Message/Array/Map objects in Lua/C that wrap upb/msg.h */ +#include "upb/msg.h" + #include #include #include @@ -11,10 +13,8 @@ #include "lauxlib.h" #include "upb/bindings/lua/upb.h" #include "upb/handlers.h" -#include "upb/legacy_msg_reflection.h" -#include "upb/msg.h" - #include "upb/port_def.inc" +#include "upb/reflection.h" /* * Message/Array/Map objects can be constructed in one of two ways: diff --git a/upb/legacy_msg_reflection.c b/upb/reflection.c similarity index 99% rename from upb/legacy_msg_reflection.c rename to upb/reflection.c index 4f1ab970db..70ab323ba8 100644 --- a/upb/legacy_msg_reflection.c +++ b/upb/reflection.c @@ -1,5 +1,5 @@ -#include "upb/legacy_msg_reflection.h" +#include "upb/reflection.h" #include #include "upb/table.int.h" diff --git a/upb/legacy_msg_reflection.h b/upb/reflection.h similarity index 100% rename from upb/legacy_msg_reflection.h rename to upb/reflection.h From 27b95c969a30c3f13db415225ec74344f026cf51 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 22 Nov 2019 17:23:23 -0800 Subject: [PATCH 07/35] WIP. --- BUILD | 24 -- bazel/build_defs.bzl | 31 +- upb/bindings/lua/def.c | 406 +++++++++++++------------ upb/bindings/lua/msg.c | 573 +++++++++++++----------------------- upb/bindings/lua/upb.c | 73 ++--- upb/bindings/lua/upb.h | 87 +++--- upb/bindings/lua/upb/pb.c | 56 ---- upb/bindings/lua/upb/pb.lua | 3 - upb/reflection.h | 19 +- 9 files changed, 507 insertions(+), 765 deletions(-) delete mode 100644 upb/bindings/lua/upb/pb.c delete mode 100644 upb/bindings/lua/upb/pb.lua diff --git a/BUILD b/BUILD index dd72362762..488b3684ea 100644 --- a/BUILD +++ b/BUILD @@ -579,7 +579,6 @@ lua_cclibrary( deps = [ "reflection", "upb", - "upb_pb", ], ) @@ -590,23 +589,6 @@ lua_library( strip_prefix = "upb/bindings/lua", ) -lua_cclibrary( - name = "lua/upb/pb_c", - srcs = ["upb/bindings/lua/upb/pb.c"], - luadeps = ["lua/upb_c"], - deps = ["upb_pb"], -) - -lua_library( - name = "lua/upb/pb", - srcs = ["upb/bindings/lua/upb/pb.lua"], - luadeps = [ - "lua/upb", - "lua/upb/pb_c", - ], - strip_prefix = "upb/bindings/lua", -) - # Lua tests. ################################################################### lua_test( @@ -615,12 +597,6 @@ lua_test( luamain = "tests/bindings/lua/test_upb.lua", ) -lua_test( - name = "lua/test_upb_pb", - luadeps = ["lua/upb/pb"], - luamain = "tests/bindings/lua/test_upb.pb.lua", -) - # Test the CMake build ######################################################### filegroup( diff --git a/bazel/build_defs.bzl b/bazel/build_defs.bzl index 08bb44ee3f..67a79d482e 100644 --- a/bazel/build_defs.bzl +++ b/bazel/build_defs.bzl @@ -5,6 +5,19 @@ load(":upb_proto_library.bzl", "GeneratedSrcsInfo") def _librule(name): return name + "_lib" +runfiles_init = """\ +# --- begin runfiles.bash initialization v2 --- +# Copy-pasted from the Bazel Bash runfiles library v2. +set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v2 --- +""" + def _get_real_short_path(file): # For some reason, files from other archives have short paths that look like: # ../com_google_protobuf/google/protobuf/descriptor.proto @@ -26,7 +39,7 @@ def _get_real_roots(files): roots[real_root] = True return roots.keys() -def lua_cclibrary(name, srcs, hdrs = [], deps = [], luadeps = []): +def lua_cclibrary(name, srcs, hdrs = [], deps = []): lib_rule = name + "_lib" so_rule = "lib" + name + ".so" so_file = _remove_prefix(name, "lua/") + ".so" @@ -35,7 +48,7 @@ def lua_cclibrary(name, srcs, hdrs = [], deps = [], luadeps = []): name = _librule(name), hdrs = hdrs, srcs = srcs, - deps = deps + [_librule(dep) for dep in luadeps] + ["@lua//:liblua_headers"], + deps = deps + ["@lua//:liblua_headers"], ) native.cc_binary( @@ -87,7 +100,7 @@ def lua_library(name, srcs, strip_prefix, luadeps = []): ) def make_shell_script(name, contents, out): - contents = contents.replace("$", "$$") + contents = (runfiles_init + contents).replace("$", "$$") native.genrule( name = "gen_" + name, outs = [out], @@ -104,14 +117,20 @@ def _lua_binary_or_test(name, luamain, luadeps, rule): BASE=$(dirname $(rlocation upb/upb_c.so)) export LUA_CPATH="$BASE/?.so" export LUA_PATH="$BASE/?.lua" -$(rlocation lua/lua) $(rlocation upb/tools/upbc.lua) "$@" -""", +LUA=$(rlocation lua/lua) +MAIN=$(rlocation upb/%s) +$LUA $MAIN +""" % luamain, ) rule( name = name, srcs = [script], - data = ["@lua//:lua", luamain] + luadeps, + data = [ + "@lua//:lua", + luamain + ] + luadeps, + deps = ["@bazel_tools//tools/bash/runfiles"], ) def lua_binary(name, luamain, luadeps = []): diff --git a/upb/bindings/lua/def.c b/upb/bindings/lua/def.c index a9ab9a89db..a163ad13e9 100644 --- a/upb/bindings/lua/def.c +++ b/upb/bindings/lua/def.c @@ -15,97 +15,68 @@ #define LUPB_SYMTAB "lupb.symtab" #define LUPB_OBJCACHE "lupb.objcache" -#define CHK(pred) \ - do { \ - upb_status status; \ - upb_status_clear(&status); \ - pred; \ - lupb_checkstatus(L, &status); \ - } while (0) +static void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, + const char *type); /* lupb_wrapper ***************************************************************/ -/* Wrappers around upb objects. */ +/* Wrappers around upb def objects. The userval contains a reference to the + * symtab. */ -/* Checks type; if it matches, pulls the pointer out of the wrapper. */ -void *lupb_checkwrapper(lua_State *L, int narg, const char *type) { - void *ud = lua_touserdata(L, narg); - void *ret; +typedef struct { + const void* def; /* upb_msgdef, upb_enumdef, upb_oneofdef, etc. */ +} lupb_wrapper; + +static const void *lupb_wrapper_check(lua_State *L, int narg, + const char *type) { + lupb_wrapper *w = lua_touserdata(L, narg); - if (!ud) { + if (!w) { luaL_typerror(L, narg, "upb wrapper"); } - memcpy(&ret, ud, sizeof(ret)); - if (!ret) { + if (!w->def) { luaL_error(L, "called into dead object"); } luaL_checkudata(L, narg, type); - return ret; + return w->def; } -void lupb_pushwrapper(lua_State *L, const void *obj, const char *type) { - void *ud; - - if (obj == NULL) { - lua_pushnil(L); - return; - } - - /* Lookup our cache in the registry (we don't put our objects in the registry - * directly because we need our cache to be a weak table). */ - lua_getfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); - UPB_ASSERT(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */ - lua_pushlightuserdata(L, (void*)obj); - lua_rawget(L, -2); - /* Stack is now: objcache, cached value. */ - - if (lua_isnil(L, -1)) { - /* Remove bad cached value and push new value. */ - lua_pop(L, 1); - ud = lua_newuserdata(L, sizeof(*ud)); - memcpy(ud, &obj, sizeof(*ud)); - - luaL_getmetatable(L, type); - /* Should have been created by luaopen_upb. */ - lupb_assert(L, !lua_isnil(L, -1)); - lua_setmetatable(L, -2); - - /* Set it in the cache. */ - lua_pushlightuserdata(L, (void*)obj); - lua_pushvalue(L, -2); - lua_rawset(L, -4); - } - - lua_insert(L, -2); - lua_pop(L, 1); +static void lupb_wrapper_pushsymtab(lua_State *L, int narg) { + lua_getuserval(L, narg); + lua_rawgeti(L, -1, 1); + lua_replace(L, -2); } -void lupb_msgdef_pushwrapper(lua_State *L, const upb_msgdef *m); -void lupb_oneofdef_pushwrapper(lua_State *L, const upb_oneofdef *o); -static void lupb_enumdef_pushwrapper(lua_State *L, const upb_enumdef *e); - +/* lupb_wrapper_pushwrapper() + * + * For a given def wrapper at index |narg|, pushes a wrapper for the given |def| + * and the given |type|. The new wrapper will be part of the same symtab. */ +static void lupb_wrapper_pushwrapper(lua_State *L, int narg, const void *def, + const char *type) { + lupb_wrapper_pushsymtab(L, narg); + lupb_symtab_pushwrapper(L, -1, def, type); + lua_replace(L, -2); /* Remove symtab from stack. */ +} /* lupb_fielddef **************************************************************/ -void lupb_fielddef_pushwrapper(lua_State *L, const upb_fielddef *f) { - lupb_pushwrapper(L, f, LUPB_FIELDDEF); -} - const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { - return lupb_checkwrapper(L, narg, LUPB_FIELDDEF); + return lupb_wrapper_check(L, narg, LUPB_FIELDDEF); } static int lupb_fielddef_containingoneof(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); - lupb_oneofdef_pushwrapper(L, upb_fielddef_containingoneof(f)); + const upb_oneof *o = upb_fielddef_containingoneof(f); + lupb_wrapper_pushwrapper(L, 1, o, LUPB_ONEOFDEF); return 1; } static int lupb_fielddef_containingtype(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); - lupb_msgdef_pushwrapper(L, upb_fielddef_containingtype(f)); + const upb_msgdef *m = upb_fielddef_containingtype(f); + lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF); return 1; } @@ -146,17 +117,6 @@ static int lupb_fielddef_descriptortype(lua_State *L) { return 1; } -static int lupb_fielddef_getsel(lua_State *L) { - const upb_fielddef *f = lupb_fielddef_check(L, 1); - upb_selector_t sel; - if (upb_handlers_getselector(f, luaL_checknumber(L, 2), &sel)) { - lua_pushinteger(L, sel); - return 1; - } else { - return 0; - } -} - static int lupb_fielddef_hassubdef(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); lua_pushboolean(L, upb_fielddef_hassubdef(f)); @@ -211,22 +171,21 @@ static int lupb_fielddef_packed(lua_State *L) { static int lupb_fielddef_msgsubdef(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); - lupb_msgdef_pushwrapper(L, upb_fielddef_msgsubdef(f)); + const upb_msgdef *m = upb_fielddef_msgsubdef(f); + lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF); return 1; } static int lupb_fielddef_enumsubdef(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); - lupb_enumdef_pushwrapper(L, upb_fielddef_enumsubdef(f)); + const upb_enumdef *e = upb_fielddef_enumsubdef(f); + lupb_wrapper_pushwrapper(L, 1, e, LUPB_ENUMDEF); return 1; } static int lupb_fielddef_type(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); - if (upb_fielddef_typeisset(f)) - lua_pushinteger(L, upb_fielddef_type(f)); - else - lua_pushnil(L); + lua_pushinteger(L, upb_fielddef_type(f)); return 1; } @@ -235,7 +194,6 @@ static const struct luaL_Reg lupb_fielddef_m[] = { {"containing_type", lupb_fielddef_containingtype}, {"default", lupb_fielddef_default}, {"descriptor_type", lupb_fielddef_descriptortype}, - {"getsel", lupb_fielddef_getsel}, {"has_subdef", lupb_fielddef_hassubdef}, {"index", lupb_fielddef_index}, {"is_extension", lupb_fielddef_isextension}, @@ -250,55 +208,64 @@ static const struct luaL_Reg lupb_fielddef_m[] = { {NULL, NULL} }; - /* lupb_oneofdef **************************************************************/ -void lupb_oneofdef_pushwrapper(lua_State *L, const upb_oneofdef *o) { - lupb_pushwrapper(L, o, LUPB_ONEOFDEF); -} - const upb_oneofdef *lupb_oneofdef_check(lua_State *L, int narg) { - return lupb_checkwrapper(L, narg, LUPB_ONEOFDEF); + return lupb_wrapper_check(L, narg, LUPB_ONEOFDEF); } static int lupb_oneofdef_containingtype(lua_State *L) { const upb_oneofdef *o = lupb_oneofdef_check(L, 1); - lupb_msgdef_pushwrapper(L, upb_oneofdef_containingtype(o)); + const upb_msgdef *m = upb_oneofdef_containingtype(o); + lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF); return 1; } +/* lupb_oneofdef_field() + * + * Handles: + * oneof.field(field_number) + * oneof.field(field_name) + */ static int lupb_oneofdef_field(lua_State *L) { - const upb_oneofdef *o = lupb_oneofdef_check(L, 1); - int type = lua_type(L, 2); + const upb_oneofdef *o = lupb_oneofdef_check(L, narg); const upb_fielddef *f; - if (type == LUA_TNUMBER) { - f = upb_oneofdef_itof(o, lua_tointeger(L, 2)); - } else if (type == LUA_TSTRING) { - f = upb_oneofdef_ntofz(o, lua_tostring(L, 2)); - } else { - const char *msg = lua_pushfstring(L, "number or string expected, got %s", - luaL_typename(L, 2)); - return luaL_argerror(L, 2, msg); + + switch (lua_type(L, 2)) { + case LUA_TNUMBER: + f = upb_oneofdef_itof(o, lua_tointeger(L, 2)); + break; + case LUA_TSTRING: + f = upb_oneofdef_ntofz(o, lua_tostring(L, 2)); + break; + default: { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } } - lupb_fielddef_pushwrapper(L, f); + lupb_wrapper_pushwrapper(L, 1, f, LUPB_FIELDDEF); return 1; } static int lupb_oneofiter_next(lua_State *L) { upb_oneof_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + const upb_fielddef *f; if (upb_oneof_done(i)) return 0; - lupb_fielddef_pushwrapper(L, upb_oneof_iter_field(i)); + f = upb_oneof_iter_field(i); upb_oneof_next(i); + lupb_symtab_pushwrapper(L, lua_upvalueindex(2), f, LUPB_FIELDDEF); return 1; } static int lupb_oneofdef_fields(lua_State *L) { - const upb_oneofdef *o = lupb_oneofdef_check(L, 1); - upb_oneof_iter *i = lua_newuserdata(L, sizeof(upb_oneof_iter)); - upb_oneof_begin(i, o); - /* Need to guarantee that the msgdef outlives the iter. */ - lua_pushvalue(L, 1); + const upb_oneofdef *o = lupb_oneof_check(L, 1); + lupb_oneofiter *i = lua_newuserdata(L, sizeof(lupb_oneofiter)); + lupb_wrapper_pushsymtab(L, 1); + upb_oneof_begin(&i->iter, o); + + /* Closure upvalues are: iter, symtab. */ lua_pushcclosure(L, &lupb_oneofiter_next, 2); return 1; } @@ -335,12 +302,8 @@ typedef struct { const upb_msgdef *md; } lupb_msgdef; -void lupb_msgdef_pushwrapper(lua_State *L, const upb_msgdef *m) { - lupb_pushwrapper(L, m, LUPB_MSGDEF); -} - const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { - return lupb_checkwrapper(L, narg, LUPB_MSGDEF); + return lupb_wrapper_check(L, narg, LUPB_MSGDEF); } static int lupb_msgdef_len(lua_State *L) { @@ -349,42 +312,62 @@ static int lupb_msgdef_len(lua_State *L) { return 1; } +/* lupb_msgdef_field() + * + * Handles: + * msg.field(field_number) -> fielddef + * msg.field(field_name) -> fielddef + */ static int lupb_msgdef_field(lua_State *L) { const upb_msgdef *m = lupb_msgdef_check(L, 1); - int type = lua_type(L, 2); const upb_fielddef *f; - if (type == LUA_TNUMBER) { - f = upb_msgdef_itof(m, lua_tointeger(L, 2)); - } else if (type == LUA_TSTRING) { - f = upb_msgdef_ntofz(m, lua_tostring(L, 2)); - } else { - const char *msg = lua_pushfstring(L, "number or string expected, got %s", - luaL_typename(L, 2)); - return luaL_argerror(L, 2, msg); + + switch (lua_type(L, 2)) { + case LUA_TNUMBER: + f = upb_msgdef_itof(m, lua_tointeger(L, 2)); + break; + case LUA_TSTRING: + f = upb_msgdef_ntofz(m, lua_tostring(L, 2)); + break; + default: { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } } - lupb_fielddef_pushwrapper(L, f); + lupb_wrapper_pushwrapper(L, 1, f, LUPB_FIELDDEF); return 1; } +/* lupb_msgdef_lookupname() + * + * Handles: + * msg.lookup_name(name) -> fielddef or oneofdef + */ static int lupb_msgdef_lookupname(lua_State *L) { const upb_msgdef *m = lupb_msgdef_check(L, 1); const upb_fielddef *f; const upb_oneofdef *o; + if (!upb_msgdef_lookupnamez(m, lua_tostring(L, 2), &f, &o)) { lua_pushnil(L); } else if (o) { - lupb_oneofdef_pushwrapper(L, o); + lupb_wrapper_pushwrapper(L, 1, o, LUPB_ONEOFDEF); } else { - lupb_fielddef_pushwrapper(L, f); + lupb_wrapper_pushwrapper(L, 1, f, LUPB_FIELDDEF); } + return 1; } static int lupb_msgfielditer_next(lua_State *L) { upb_msg_field_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + const upb_fielddef *f; + if (upb_msg_field_done(i)) return 0; - lupb_fielddef_pushwrapper(L, upb_msg_iter_field(i)); + f = upb_msg_iter_field(i); + lupb_symtab_pushwrapper(L, lua_upvalueindex(2), f); upb_msg_field_next(i); return 1; } @@ -392,27 +375,31 @@ static int lupb_msgfielditer_next(lua_State *L) { static int lupb_msgdef_fields(lua_State *L) { const upb_msgdef *m = lupb_msgdef_check(L, 1); upb_msg_field_iter *i = lua_newuserdata(L, sizeof(upb_msg_field_iter)); + lupb_wrapper_pushsymtab(L, 1); upb_msg_field_begin(i, m); - /* Need to guarantee that the msgdef outlives the iter. */ - lua_pushvalue(L, 1); + + /* Closure upvalues are: iter, symtab. */ lua_pushcclosure(L, &lupb_msgfielditer_next, 2); return 1; } static int lupb_msgoneofiter_next(lua_State *L) { upb_msg_oneof_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + const upb_oneofdef *o; if (upb_msg_oneof_done(i)) return 0; - lupb_oneofdef_pushwrapper(L, upb_msg_iter_oneof(i)); + o = upb_msg_iter_oneof(i); upb_msg_oneof_next(i); + lupb_symtab_pushwrapper(L, lua_upvalueindex(2), o); return 1; } static int lupb_msgdef_oneofs(lua_State *L) { const upb_msgdef *m = lupb_msgdef_check(L, 1); upb_msg_oneof_iter *i = lua_newuserdata(L, sizeof(upb_msg_oneof_iter)); + lupb_wrapper_pushsymtab(L, 1); upb_msg_oneof_begin(i, m); - /* Need to guarantee that the msgdef outlives the iter. */ - lua_pushvalue(L, 1); + + /* Closure upvalues are: iter, symtab. */ lua_pushcclosure(L, &lupb_msgoneofiter_next, 2); return 1; } @@ -448,11 +435,7 @@ static const struct luaL_Reg lupb_msgdef_m[] = { /* lupb_enumdef ***************************************************************/ const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { - return lupb_checkwrapper(L, narg, LUPB_ENUMDEF); -} - -static void lupb_enumdef_pushwrapper(lua_State *L, const upb_enumdef *e) { - lupb_pushwrapper(L, e, LUPB_ENUMDEF); + return lupb_wrapper_check(L, narg, LUPB_ENUMDEF); } static int lupb_enumdef_len(lua_State *L) { @@ -461,26 +444,39 @@ static int lupb_enumdef_len(lua_State *L) { return 1; } +/* lupb_enumdef_value() + * + * Handles: + * enum.value(number) -> name + * enum.value(name) -> number + */ static int lupb_enumdef_value(lua_State *L) { const upb_enumdef *e = lupb_enumdef_check(L, 1); - int type = lua_type(L, 2); - if (type == LUA_TNUMBER) { - /* Pushes "nil" for a NULL pointer. */ - int32_t key = lupb_checkint32(L, 2); - lua_pushstring(L, upb_enumdef_iton(e, key)); - } else if (type == LUA_TSTRING) { - const char *key = lua_tostring(L, 2); - int32_t num; - if (upb_enumdef_ntoiz(e, key, &num)) { - lua_pushinteger(L, num); - } else { - lua_pushnil(L); + + switch (lua_type(L, 2)) { + case LUA_TNUMBER: { + int32_t key = lupb_checkint32(L, 2); + /* Pushes "nil" for a NULL pointer. */ + lua_pushstring(L, upb_enumdef_iton(e, key)); + break; + } + case LUA_TSTRING: { + const char *key = lua_tostring(L, 2); + int32_t num; + if (upb_enumdef_ntoiz(e, key, &num)) { + lua_pushinteger(L, num); + } else { + lua_pushnil(L); + } + break; + } + default: { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); } - } else { - const char *msg = lua_pushfstring(L, "number or string expected, got %s", - luaL_typename(L, 2)); - return luaL_argerror(L, 2, msg); } + return 1; } @@ -496,9 +492,10 @@ static int lupb_enumiter_next(lua_State *L) { static int lupb_enumdef_values(lua_State *L) { const upb_enumdef *e = lupb_enumdef_check(L, 1); upb_enum_iter *i = lua_newuserdata(L, sizeof(upb_enum_iter)); + lupb_wrapper_pushsymtab(L, 1); upb_enum_begin(i, e); - /* Need to guarantee that the enumdef outlives the iter. */ - lua_pushvalue(L, 1); + + /* Closure upvalues are: iter, symtab. */ lua_pushcclosure(L, &lupb_enumiter_next, 2); return 1; } @@ -517,18 +514,15 @@ static const struct luaL_Reg lupb_enumdef_m[] = { /* lupb_filedef ***************************************************************/ -void lupb_filedef_pushwrapper(lua_State *L, const upb_filedef *f) { - lupb_pushwrapper(L, f, LUPB_FILEDEF); -} - const upb_filedef *lupb_filedef_check(lua_State *L, int narg) { - return lupb_checkwrapper(L, narg, LUPB_FILEDEF); + return lupb_wrapper_check(L, narg, LUPB_FILEDEF); } static int lupb_filedef_dep(lua_State *L) { const upb_filedef *f = lupb_filedef_check(L, 1); int index = luaL_checkint(L, 2); - lupb_filedef_pushwrapper(L, upb_filedef_dep(f, index)); + const upb_filedef *dep = upb_filedef_dep(f, index); + lupb_wrapper_pushwrapper(L, 1, dep, LUPB_FILEDEF); return 1; } @@ -541,7 +535,8 @@ static int lupb_filedef_depcount(lua_State *L) { static int lupb_filedef_enum(lua_State *L) { const upb_filedef *f = lupb_filedef_check(L, 1); int index = luaL_checkint(L, 2); - lupb_enumdef_pushwrapper(L, upb_filedef_enum(f, index)); + const upb_enumdef *e = upb_filedef_enum(f, index); + lupb_wrapper_pushwrapper(L, 1, e, LUPB_ENUMDEF); return 1; } @@ -554,7 +549,8 @@ static int lupb_filedef_enumcount(lua_State *L) { static int lupb_filedef_msg(lua_State *L) { const upb_filedef *f = lupb_filedef_check(L, 1); int index = luaL_checkint(L, 2); - lupb_msgdef_pushwrapper(L, upb_filedef_msg(f, index)); + const upb_msgdef *m = upb_filedef_msg(f, index); + lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF); return 1; } @@ -598,6 +594,11 @@ static const struct luaL_Reg lupb_filedef_m[] = { /* lupb_symtab ****************************************************************/ +/* The symtab owns all defs. Thus GC-rooting the symtab ensures that all + * underlying defs stay alive. + * + * The symtab's userval is a cache of def* -> object. */ + typedef struct { upb_symtab *symtab; } lupb_symtab; @@ -610,11 +611,63 @@ upb_symtab *lupb_symtab_check(lua_State *L, int narg) { return lsymtab->symtab; } +void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, + const char *type) { + if (def == NULL) { + lua_pushnil(L); + return; + } + + lua_getuserval(L, narg); /* Get cache. */ + + /* Index by "def" pointer. */ + lua_pushlightuserdata(L, (void*)def); + lua_rawget(L, -2) + + /* Stack is now: cache, cached value. */ + if (lua_isnil(L, -1)) { + /* Create new wrapper. */ + lupb_wrapper *w = lua_newuserdata(L, sizeof(*w)); + w->def = def; + lua_replace(L, -2); /* Replace nil */ + + /* Set metatable of wrapper. */ + luaL_getmetatable(L, type); + lua_setmetatable(L, -2); + + /* Add wrapper to the the cache. */ + lua_pushlightuserdata(L, (void*)def); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } + + lua_replace(L, -2); /* Remove cache, leaving only the wrapper. */ +} + +/* upb_symtab_new() + * + * Handles: + * upb.SymbolTable() -> + */ static int lupb_symtab_new(lua_State *L) { lupb_symtab *lsymtab = lua_newuserdata(L, sizeof(*lsymtab)); lsymtab->symtab = upb_symtab_new(); + luaL_getmetatable(L, LUPB_SYMTAB); lua_setmetatable(L, -2); + + /* Create our object cache. */ + lua_newtable(L); + + /* Cache metatable: specifies that values are weak. */ + lua_createtable(L, 0, 1); + lua_pushstring(L, "v"); + lua_setfield(L, -2, "__mode"); + lua_setmetatable(L, -2); + + /* Set the cache as our userval. */ + lua_setuservalue(L, -2); + return 1; } @@ -625,9 +678,6 @@ static int lupb_symtab_gc(lua_State *L) { return 0; } -/* TODO(haberman): perhaps this should take a message object instead of a - * serialized string once we have a good story for vending compiled-in - * messages. */ static int lupb_symtab_add(lua_State *L) { upb_arena *arena; size_t i, n, len; @@ -635,8 +685,10 @@ static int lupb_symtab_add(lua_State *L) { google_protobuf_FileDescriptorSet *set; upb_symtab *s = lupb_symtab_check(L, 1); const char *str = luaL_checklstring(L, 2, &len); + upb_status status; lupb_arena_new(L); + upb_status_clear(&status); arena = lupb_arena_check(L, -1); set = google_protobuf_FileDescriptorSet_parse(str, len, arena); @@ -647,7 +699,8 @@ static int lupb_symtab_add(lua_State *L) { files = google_protobuf_FileDescriptorSet_file(set, &n); for (i = 0; i < n; i++) { - CHK(upb_symtab_addfile(s, files[i], &status)); + upb_symtab_addfile(s, files[i], &status); + lupb_checkstatus(L, &status); } return 0; @@ -656,14 +709,14 @@ static int lupb_symtab_add(lua_State *L) { static int lupb_symtab_lookupmsg(lua_State *L) { const upb_symtab *s = lupb_symtab_check(L, 1); const upb_msgdef *m = upb_symtab_lookupmsg(s, luaL_checkstring(L, 2)); - lupb_msgdef_pushwrapper(L, m); + lupb_symtab_pushwrapper(L, 1, m, LUPB_MSGDEF); return 1; } static int lupb_symtab_lookupenum(lua_State *L) { const upb_symtab *s = lupb_symtab_check(L, 1); const upb_enumdef *e = upb_symtab_lookupenum(s, luaL_checkstring(L, 2)); - lupb_enumdef_pushwrapper(L, e); + lupb_symtab_pushwrapper(L, 1, e, LUPB_ENUMDEF); return 1; } @@ -694,7 +747,7 @@ static const struct luaL_Reg lupbdef_toplevel_m[] = { void lupb_def_registertypes(lua_State *L) { lupb_setfuncs(L, lupbdef_toplevel_m); - /* Refcounted types. */ + /* Register types. */ lupb_register_type(L, LUPB_ENUMDEF, lupb_enumdef_m, lupb_enumdef_mm); lupb_register_type(L, LUPB_FIELDDEF, lupb_fielddef_m, NULL); lupb_register_type(L, LUPB_FILEDEF, lupb_filedef_m, NULL); @@ -702,14 +755,6 @@ void lupb_def_registertypes(lua_State *L) { lupb_register_type(L, LUPB_ONEOFDEF, lupb_oneofdef_m, lupb_oneofdef_mm); lupb_register_type(L, LUPB_SYMTAB, lupb_symtab_m, lupb_symtab_mm); - /* Create our object cache. */ - lua_newtable(L); - lua_createtable(L, 0, 1); /* Cache metatable. */ - lua_pushstring(L, "v"); /* Values are weak. */ - lua_setfield(L, -2, "__mode"); - lua_setmetatable(L, -2); - lua_setfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); - /* Register constants. */ lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL_OPTIONAL); lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL_REQUIRED); @@ -746,21 +791,6 @@ void lupb_def_registertypes(lua_State *L) { lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT32", UPB_DESCRIPTOR_TYPE_SINT32); lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT64", UPB_DESCRIPTOR_TYPE_SINT64); - lupb_setfieldi(L, "HANDLER_INT32", UPB_HANDLER_INT32); - lupb_setfieldi(L, "HANDLER_INT64", UPB_HANDLER_INT64); - lupb_setfieldi(L, "HANDLER_UINT32", UPB_HANDLER_UINT32); - lupb_setfieldi(L, "HANDLER_UINT64", UPB_HANDLER_UINT64); - lupb_setfieldi(L, "HANDLER_FLOAT", UPB_HANDLER_FLOAT); - lupb_setfieldi(L, "HANDLER_DOUBLE", UPB_HANDLER_DOUBLE); - lupb_setfieldi(L, "HANDLER_BOOL", UPB_HANDLER_BOOL); - lupb_setfieldi(L, "HANDLER_STARTSTR", UPB_HANDLER_STARTSTR); - lupb_setfieldi(L, "HANDLER_STRING", UPB_HANDLER_STRING); - lupb_setfieldi(L, "HANDLER_ENDSTR", UPB_HANDLER_ENDSTR); - lupb_setfieldi(L, "HANDLER_STARTSUBMSG", UPB_HANDLER_STARTSUBMSG); - lupb_setfieldi(L, "HANDLER_ENDSUBMSG", UPB_HANDLER_ENDSUBMSG); - lupb_setfieldi(L, "HANDLER_STARTSEQ", UPB_HANDLER_STARTSEQ); - lupb_setfieldi(L, "HANDLER_ENDSEQ", UPB_HANDLER_ENDSEQ); - lupb_setfieldi(L, "SYNTAX_PROTO2", UPB_SYNTAX_PROTO2); lupb_setfieldi(L, "SYNTAX_PROTO3", UPB_SYNTAX_PROTO3); } diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 49c7d3f185..012457d03d 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -12,97 +12,109 @@ #include "lauxlib.h" #include "upb/bindings/lua/upb.h" -#include "upb/handlers.h" -#include "upb/port_def.inc" #include "upb/reflection.h" +#include "upb/port_def.inc" + /* - * Message/Array/Map objects can be constructed in one of two ways: - * - * 1. To point to existing msg/array/map data inside an arena. - * 2. To create and uniquely own some brand new data. - * - * Case (1) is for when we've parsed some data into an arena (which is faster - * than parsing directly into Lua objects) or when we're pointing at some - * read-only data (like custom options in a def). - * - * Case (2) is for when a user creates the object directly in Lua. - * - * We use the userval of container objects (Message/Array/Map) to store - * references to sub-objects (Strings/Messages/Arrays/Maps). But we need to - * keep the userval in sync with the underlying upb_msg/upb_array/upb_map. - * We populate the userval lazily from the underlying data. - * - * This means that no one may remove/replace any String/Message/Array/Map - * field/entry in the underlying upb_{msg,array,map} behind our back. It's ok - * for entries to be added or for primitives to be modified, but *replacing* - * sub-containers is not. - * - * Luckily parse/merge follow this rule. However clear does not, so it's not - * safe to clear behind our back. + * Message/Map/Array objects. These objects form a directed graph: a message + * can contain submessages, arrays, and maps, which can then point to other + * messages. This graph can technically be cyclic, though this is an error and + * a cyclic graph cannot be serialized. So it's better to think of this as a + * tree of objects. + * + * The actual data exists at the upb level (upb_msg, upb_map, upb_array), + * independently of Lua. The upb objects contain all the canonical data and + * edges between objects. Lua wrapper objects expose the upb objects to Lua, + * but ultimately they are just wrappers. They pass through all reads and + * writes to the underlying upb objects. + * + * Each upb object lives in a upb arena. We have a Lua object to wrap the upb + * arena, but arenas are never exposed to the user. The Lua arena object just + * serves to own the upb arena and free it at the proper time, once the Lua GC + * has determined that there are no more references to anything that lives in + * that arena. All wrapper objects strongly reference the arena to which they + * belong. + * + * A global object cache stores a mapping of C pointer (upb_msg*, upb_array*, + * upb_map*) to a corresponding Lua wrapper. These references are weak so that + * the wrappers can be collected if they are no longer needed. A new wrapper + * object can always be recreated later. + * + * arena + * +->group + * | + * V +-----+ + * lupb_arena |cache|-weak-+ + * | ^ +-----+ | + * | | V + * Lua level | +------------lupb_msg + * ----------------|-----------------|------------------------------------------- + * upb level | | + * | +----V------------------------------+ + * +->upb_arena | upb_msg ...(empty arena storage) | + * +-----------------------------------+ + * + * If the user creates a reference between two objects that have different + * arenas, we need to merge the arenas into a single, bigger arena group. The + * arena group will reference both arenas, and will inherit the longest lifetime + * of anything in the arena. + * + * arena + * +--------------------------->group<-----------------+ + * | | + * V +-----+ V + * lupb_arena +-weak-|cache|-weak-+ lupb_arena + * | ^ | +-----+ | ^ | + * | | V V | | + * Lua level | +------------lupb_msg lupb_msg----+ | + * ----------------|-----------------|-------------------------|---------|------- + * upb level | | | | + * | +----V----+ +----V----+ V + * +->upb_arena | upb_msg | | upb_msg | upb_arena + * +------|--+ +--^------+ + * +---------------------+ + * Key invariants: + * 1. every wrapper references the arena that contains it. + * 2. every arena group references all arenas that own upb objects reachable + * from that arena. In other words, when a wrapper references an arena, + * this is sufficient to ensure that any upb object reachable from that + * wrapper will stay alive. + * + * Additionally, every message object contains a strong reference to the + * corresponding Descriptor object. Likewise, array/map objects reference a + * Descriptor object if they are typed to store message values. + * + * (The object cache could be per-arena-group. This would keep individual cache + * tables smaller, and when an arena group is freed the entire cache table could + * be collected in one fell swoop. However this makes merging another arena + * into the group an O(n) operation, since all entries would need to be copied + * from the existing cache table.) */ #define LUPB_ARENA "lupb.arena" - -#define LUPB_MSGCLASS "lupb.msgclass" -#define LUPB_MSGFACTORY "lupb.msgfactory" - #define LUPB_ARRAY "lupb.array" #define LUPB_MAP "lupb.map" #define LUPB_MSG "lupb.msg" -#define LUPB_STRING "lupb.string" static int lupb_msg_pushnew(lua_State *L, int narg); -/* Lazily creates the uservalue if it doesn't exist. */ -static void lupb_getuservalue(lua_State *L, int index) { - lua_getuservalue(L, index); - if (lua_isnil(L, -1)) { - /* Lazily create and set userval. */ - lua_pop(L, 1); /* nil. */ - lua_pushvalue(L, index); /* userdata copy. */ - lua_newtable(L); - lua_setuservalue(L, -2); - lua_pop(L, 1); /* userdata copy. */ - lua_getuservalue(L, index); +static void lupb_msg_typecheck(lua_State *L, const upb_msgdef *expected, + const upb_msgdef *actual) { + if (expected != actual) { + luaL_error(L, "Message had incorrect type, expected '%s', got '%s'", + upb_msgdef_fullname(expected), upb_msgdef_fullname(actual)); } - assert(!lua_isnil(L, -1)); -} - -static void lupb_uservalseti(lua_State *L, int userdata, int index, int val) { - lupb_getuservalue(L, userdata); - lua_pushvalue(L, val); - lua_rawseti(L, -2, index); - lua_pop(L, 1); /* Uservalue. */ -} - -static void lupb_uservalgeti(lua_State *L, int userdata, int index) { - lupb_getuservalue(L, userdata); - lua_rawgeti(L, -1, index); - lua_insert(L, -2); - lua_pop(L, 1); /* Uservalue. */ -} - -/* Pushes a new userdata with the given metatable. */ -static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) { - void *ret = lua_newuserdata(L, size); - - /* Set metatable. */ - luaL_getmetatable(L, type); - UPB_ASSERT(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */ - lua_setmetatable(L, -2); - - /* We don't set a uservalue here -- we lazily create it later if necessary. */ - - return ret; } /* lupb_arena *****************************************************************/ -/* lupb_arena only exists to wrap a upb_arena. It is never exposed to users; - * it is an internal memory management detail. Other objects refer to this - * object from their userdata to keep the arena-owned data alive. */ +/* lupb_arena only exists to wrap a upb_arena. It is never exposed to users; it + * is an internal memory management detail. Other wrapper objects refer to this + * object from their userdata to keep the arena-owned data alive. + * + * The arena contains a table that caches wrapper objects. */ typedef struct { upb_arena *arena; @@ -135,7 +147,7 @@ upb_arena *lupb_arena_get(lua_State *L) { lua_pushlightuserdata(L, &lupb_arena_cache_key); lua_gettable(L, LUA_REGISTRYINDEX); arena = lua_touserdata(L, -1); - UPB_ASSERT(arena); + assert(arena); lua_pop(L, 1); return arena; @@ -159,223 +171,6 @@ static const struct luaL_Reg lupb_arena_mm[] = { }; -/* lupb_msgfactory ************************************************************/ - -/* Userval contains a map of: - * [1] -> SymbolTable (to keep GC-reachable) - * [const upb_msgdef*] -> [lupb_msgclass userdata] - */ - -#define LUPB_MSGFACTORY_SYMTAB 1 - -typedef struct lupb_msgfactory { - upb_msgfactory *factory; -} lupb_msgfactory; - -static int lupb_msgclass_pushnew(lua_State *L, int factory, - const upb_msgdef *md); - -/* lupb_msgfactory helpers. */ - -static lupb_msgfactory *lupb_msgfactory_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, LUPB_MSGFACTORY); -} - -static void lupb_msgfactory_pushmsgclass(lua_State *L, int narg, - const upb_msgdef *md) { - lupb_getuservalue(L, narg); - lua_pushlightuserdata(L, (void*)md); - lua_rawget(L, -2); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - /* TODO: verify md is in symtab? */ - lupb_msgclass_pushnew(L, narg, md); - - /* Set in userval. */ - lua_pushlightuserdata(L, (void*)md); - lua_pushvalue(L, -2); - lua_rawset(L, -4); - } -} - -static int lupb_msgfactory_gc(lua_State *L) { - lupb_msgfactory *lfactory = lupb_msgfactory_check(L, 1); - - if (lfactory->factory) { - upb_msgfactory_free(lfactory->factory); - lfactory->factory = NULL; - } - - return 0; -} - -/* lupb_msgfactory Public API. */ - -/** - * lupb_msgfactory_new() - * - * Handles: - * msgfactory = upb.MessageFactory(symtab) - * - * Creates a new, empty MessageFactory for the given SymbolTable. - * Message classes will be created on demand when the user calls - * msgfactory.get_message_class(). - */ -static int lupb_msgfactory_new(lua_State *L) { - const upb_symtab *symtab = lupb_symtab_check(L, 1); - - lupb_msgfactory *lmsgfactory = - lupb_newuserdata(L, sizeof(lupb_msgfactory), LUPB_MSGFACTORY); - lmsgfactory->factory = upb_msgfactory_new(symtab); - lupb_uservalseti(L, -1, LUPB_MSGFACTORY_SYMTAB, 1); - - return 1; -} - -/** - * lupb_msgfactory_getmsgclass() - * - * Handles: - * MessageClass = factory.get_message_class(message_name) - */ -static int lupb_msgfactory_getmsgclass(lua_State *L) { - lupb_msgfactory *lfactory = lupb_msgfactory_check(L, 1); - const upb_symtab *symtab = upb_msgfactory_symtab(lfactory->factory); - const upb_msgdef *m = upb_symtab_lookupmsg(symtab, luaL_checkstring(L, 2)); - - if (!m) { - luaL_error(L, "No such message type: %s\n", lua_tostring(L, 2)); - } - - lupb_msgfactory_pushmsgclass(L, 1, m); - - return 1; -} - -static const struct luaL_Reg lupb_msgfactory_m[] = { - {"get_message_class", lupb_msgfactory_getmsgclass}, - {NULL, NULL} -}; - -static const struct luaL_Reg lupb_msgfactory_mm[] = { - {"__gc", lupb_msgfactory_gc}, - {NULL, NULL} -}; - - -/* lupb_msgclass **************************************************************/ - -/* Userval contains a map of: - * [1] -> MessageFactory (to keep GC-reachable) - * [const upb_msgdef*] -> [lupb_msgclass userdata] - */ - -#define LUPB_MSGCLASS_FACTORY 1 - -struct lupb_msgclass { - const upb_msglayout *layout; - const upb_msgdef *msgdef; -}; - -/* Type-checks for assigning to a message field. */ -static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, - const upb_fielddef *f); -static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, - const upb_fielddef *f); -static const lupb_msgclass *lupb_msg_getsubmsgclass(lua_State *L, int narg, - const upb_fielddef *f); -static const lupb_msgclass *lupb_msg_msgclassfor(lua_State *L, int narg, - const upb_msgdef *md); - -const lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, LUPB_MSGCLASS); -} - -const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg) { - return lupb_msgclass_check(L, narg)->layout; -} - -const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass) { - return lmsgclass->msgdef; -} - -/** - * lupb_msgclass_typecheck() - * - * Verifies that the expected msgclass matches the actual. If not, raises a Lua - * error. - */ -static void lupb_msgclass_typecheck(lua_State *L, const lupb_msgclass *expected, - const lupb_msgclass *actual) { - if (expected != actual) { - luaL_error(L, "Message had incorrect type, expected '%s', got '%s'", - upb_msgdef_fullname(expected->msgdef), - upb_msgdef_fullname(actual->msgdef)); - } -} - -static const lupb_msgclass *lupb_msgclass_msgclassfor(lua_State *L, int narg, - const upb_msgdef *md) { - lupb_uservalgeti(L, narg, LUPB_MSGCLASS_FACTORY); - lupb_msgfactory_pushmsgclass(L, -1, md); - return lupb_msgclass_check(L, -1); -} - -/** - * lupb_msgclass_getsubmsgclass() - * - * Given a MessageClass at index |narg| and the submessage field |f|, returns - * the message class for this field. - * - * Currently we do a hash table lookup for this. If we wanted we could try to - * optimize this by caching these pointers in our msgclass, in an array indexed - * by field index. We would still need to fall back to calling msgclassfor(), - * unless we wanted to eagerly create message classes for all submessages. But - * for big schemas that might be a lot of things to build, and we might end up - * not using most of them. */ -static const lupb_msgclass *lupb_msgclass_getsubmsgclass(lua_State *L, int narg, - const upb_fielddef *f) { - if (upb_fielddef_type(f) != UPB_TYPE_MESSAGE) { - return NULL; - } - - return lupb_msgclass_msgclassfor(L, narg, upb_fielddef_msgsubdef(f)); -} - -static int lupb_msgclass_pushnew(lua_State *L, int factory, - const upb_msgdef *md) { - const lupb_msgfactory *lfactory = lupb_msgfactory_check(L, factory); - lupb_msgclass *lmc = lupb_newuserdata(L, sizeof(*lmc), LUPB_MSGCLASS); - - lupb_uservalseti(L, -1, LUPB_MSGCLASS_FACTORY, factory); - lmc->layout = upb_msgfactory_getlayout(lfactory->factory, md); - lmc->msgdef = md; - - return 1; -} - -/* MessageClass Public API. */ - -/** - * lupb_msgclass_call() - * - * Handles: - * msg = MessageClass() - * - * Creates a new message from the given MessageClass. - */ -static int lupb_msgclass_call(lua_State *L) { - lupb_msg_pushnew(L, 1); - return 1; -} - -static const struct luaL_Reg lupb_msgclass_mm[] = { - {"__call", lupb_msgclass_call}, - {NULL, NULL} -}; - - /* upb <-> Lua type conversion ************************************************/ static bool lupb_istypewrapped(upb_fieldtype_t type) { @@ -384,7 +179,7 @@ static bool lupb_istypewrapped(upb_fieldtype_t type) { } static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg, - const lupb_msgclass *lmsgclass) { + const upb_msgdef *msgdef) { upb_msgval ret; switch (type) { case UPB_TYPE_INT32: @@ -417,8 +212,8 @@ static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg, break; } case UPB_TYPE_MESSAGE: - UPB_ASSERT(lmsgclass); - ret.msg_val = lupb_msg_checkmsg(L, narg, lmsgclass); + assert(msgdef); + ret.msg_val = lupb_msg_checkmsg(L, narg, msgdef); break; } return ret; @@ -454,7 +249,7 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, case UPB_TYPE_MESSAGE: break; /* Shouldn't call this function. */ } - UPB_UNREACHABLE(); + LUPB_UNREACHABLE(); } @@ -470,17 +265,18 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, * For string/submessage entries we keep in the userval: * * [number index] -> [lupb_string/lupb_msg userdata] + * + * Additionally, for message-typed arrays we keep: + * + * [ARRAY_MSGDEF_INDEX] -> [SymbolTable] (to keep msgdef GC-reachable) */ typedef struct { - /* Only needed for array of message. This wastes space in the non-message - * case but simplifies the code. Could optimize away if desired. */ - const lupb_msgclass *lmsgclass; upb_array *arr; upb_fieldtype_t type; } lupb_array; -#define ARRAY_MSGCLASS_INDEX 0 +#define ARRAY_MSGDEF_INDEX 1 static lupb_array *lupb_array_check(lua_State *L, int narg) { return luaL_checkudata(L, narg, LUPB_ARRAY); @@ -498,15 +294,13 @@ static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, lupb_array *larray = lupb_array_check(L, narg); upb_msgval val; - if (larray->type != upb_fielddef_type(f) || - lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) { + if (larray->type != upb_fielddef_type(f)) { luaL_error(L, "Array had incorrect type (expected: %d, got: %d)", (int)upb_fielddef_type(f), (int)larray->type); } if (larray->type == UPB_TYPE_MESSAGE) { - lupb_msgclass_typecheck(L, lupb_msg_getsubmsgclass(L, msg, f), - larray->lmsgclass); + lupb_msgdef_typecheck(L, upb_fielddef_msgsubdef(f), larray->msgdef); } val.array_val = larray->arr; @@ -531,35 +325,54 @@ static int lupb_array_checkindex(lua_State *L, int narg, uint32_t max) { return n - 1; /* Lua uses 1-based indexing. :( */ } +static void lupb_array_push(lua_State *L, upb_array *a, const upb_fielddef *f) { + +} + /* lupb_array Public API */ +/* lupb_array_new(): + * + * Handles: + * Array(upb.TYPE_INT32) + * Array(message_type) + */ static int lupb_array_new(lua_State *L) { lupb_array *larray; upb_fieldtype_t type; - const lupb_msgclass *lmsgclass = NULL; + int n = 1; + + lupb_arena_new(); /* Userval 1. */ if (lua_type(L, 1) == LUA_TNUMBER) { type = lupb_checkfieldtype(L, 1); } else { + lupb_msgdef_check(L, 1); type = UPB_TYPE_MESSAGE; - lmsgclass = lupb_msgclass_check(L, 1); - lupb_uservalseti(L, -1, ARRAY_MSGCLASS_INDEX, 1); /* GC-root lmsgclass. */ + n = 2; + lua_push(L, 1); /* Userval 2. */ } - larray = lupb_newuserdata(L, sizeof(*larray), LUPB_ARRAY); + larray = lupb_newuserdata(L, sizeof(*larray), n, LUPB_ARRAY); larray->type = type; - larray->lmsgclass = lmsgclass; larray->arr = upb_array_new(lupb_arena_get(L), type); return 1; } +/* lupb_array_newindex(): + * + * Handles: + * array[idx] = val + * + * idx can be within the array or one past the end to extend. + */ static int lupb_array_newindex(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); size_t size = upb_array_size(larray->arr); upb_fieldtype_t type = larray->type; uint32_t n = lupb_array_checkindex(L, 2, size + 1); - upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->lmsgclass); + upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->msgdef); if (n == size) { upb_array_append(larray->arr, msgval, lupb_arena_get(L)); @@ -574,6 +387,13 @@ static int lupb_array_newindex(lua_State *L) { return 0; /* 1 for chained assignments? */ } +/* lupb_array_index(): + * + * Handles: + * array[idx] -> val + * + * idx must be within the array. + */ static int lupb_array_index(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); size_t size = upb_array_size(larray->arr); @@ -590,6 +410,11 @@ static int lupb_array_index(lua_State *L) { return 1; } +/* lupb_array_len(): + * + * Handles: + * #array -> len + */ static int lupb_array_len(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); lua_pushnumber(L, upb_array_size(larray->arr)); @@ -612,17 +437,20 @@ static const struct luaL_Reg lupb_array_mm[] = { * * [Lua number/string] -> [lupb_string/lupb_msg userdata] * + * Additionally when the map is message, we store: + * + * [MAP_MSGDEF_INDEX] -> MessageDef + * * For other value types we don't use the userdata. */ typedef struct { - const lupb_msgclass *value_lmsgclass; + upb_map *map; upb_fieldtype_t key_type; upb_fieldtype_t value_type; - upb_map *map; } lupb_map; -#define MAP_MSGCLASS_INDEX 0 +#define MAP_MSGDEF_INDEX 1 /* lupb_map internal functions */ @@ -640,13 +468,12 @@ static lupb_map *lupb_map_check(lua_State *L, int narg) { static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, const upb_fielddef *f) { lupb_map *lmap = lupb_map_check(L, narg); - upb_map *map = lmap->map; const upb_msgdef *entry = upb_fielddef_msgsubdef(f); const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); upb_msgval val; - UPB_ASSERT(entry && key_field && value_field); + assert(entry && key_field && value_field); if (lmap->key_type != upb_fielddef_type(key_field)) { luaL_error(L, "Map had incorrect field type (expected: %s, got: %s)", @@ -659,12 +486,15 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, } if (lmap->value_type == UPB_TYPE_MESSAGE) { + lupb_uservalgeti(L, narg, MAP_MSGDEF_INDEX); + lupb_wrapper_pushwrapper(L + lupb_msgclass_typecheck( L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)), lmap->value_lmsgclass); } - val.map_val = map; + val.map_val = lmap->map; return val; } @@ -675,12 +505,12 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, * * Handles: * new_map = upb.Map(key_type, value_type) + * new_map = upb.Map(key_type, value_msgdef) */ static int lupb_map_new(lua_State *L) { lupb_map *lmap; upb_fieldtype_t key_type = lupb_checkfieldtype(L, 1); upb_fieldtype_t value_type; - const lupb_msgclass *value_lmsgclass = NULL; if (lua_type(L, 2) == LUA_TNUMBER) { value_type = lupb_checkfieldtype(L, 2); @@ -692,12 +522,11 @@ static int lupb_map_new(lua_State *L) { if (value_type == UPB_TYPE_MESSAGE) { value_lmsgclass = lupb_msgclass_check(L, 2); - lupb_uservalseti(L, -1, MAP_MSGCLASS_INDEX, 2); /* GC-root lmsgclass. */ + lupb_uservalseti(L, -1, MAP_MSGDEF_INDEX, 2); /* GC-root lmsgclass. */ } lmap->key_type = key_type; lmap->value_type = value_type; - lmap->value_lmsgclass = value_lmsgclass; lmap->map = upb_map_new(lupb_arena_get(L), key_type, value_type); return 1; @@ -776,8 +605,7 @@ static int lupb_map_newindex(lua_State *L) { } } else { /* Set in map. */ - upb_msgval val = - lupb_tomsgval(L, lmap->value_type, 3, lmap->value_lmsgclass); + upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, lmap->msgdef); upb_map_set(map, key, val, lupb_arena_get(L)); @@ -852,22 +680,18 @@ static const struct luaL_Reg lupb_map_mm[] = { * * Our userval contains: * - * - [0] -> our message class - * - [lupb_fieldindex(f)] -> [lupb_{string,array,map,msg} userdata] + * - [MSG_MSGDEF_INDEX] -> our message class * * Fields with scalar number/bool types don't go in the userval. */ -#define LUPB_MSG_MSGCLASSINDEX 0 -#define LUPB_MSG_ARENA -1 +#define MSG_MSGDEF_INDEX 1 int lupb_fieldindex(const upb_fielddef *f) { return upb_fielddef_index(f) + 1; /* 1-based Lua arrays. */ } - typedef struct { - const lupb_msgclass *lmsgclass; upb_msg *msg; } lupb_msg; @@ -878,15 +702,16 @@ static bool in_userval(const upb_fielddef *f) { upb_fielddef_ismap(f); } -lupb_msg *lupb_msg_check(lua_State *L, int narg) { +upb_msg *lupb_msg_check(lua_State *L, int narg) { lupb_msg *msg = luaL_checkudata(L, narg, LUPB_MSG); - if (!msg->lmsgclass) luaL_error(L, "called into dead msg"); - return msg; + if (!msg->msg) luaL_error(L, "called into dead msg"); + return msg->msg; } const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg, - const lupb_msgclass *lmsgclass) { - lupb_msg *lmsg = lupb_msg_check(L, narg); + const upb_msgdef *msgdef) { + lupb_msg_check(L, narg); + lupb_uservalgeti lupb_msgclass_typecheck(L, lmsgclass, lmsg->lmsgclass); return lmsg->msg; } @@ -898,10 +723,6 @@ upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg, return lmsg->msg; } -const upb_msgdef *lupb_msg_checkdef(lua_State *L, int narg) { - return lupb_msg_check(L, narg)->lmsgclass->msgdef; -} - static const upb_fielddef *lupb_msg_checkfield(lua_State *L, const lupb_msg *msg, int fieldarg) { @@ -919,31 +740,6 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, return f; } -static const lupb_msgclass *lupb_msg_msgclassfor(lua_State *L, int narg, - const upb_msgdef *md) { - lupb_uservalgeti(L, narg, LUPB_MSG_MSGCLASSINDEX); - return lupb_msgclass_msgclassfor(L, -1, md); -} - -static const lupb_msgclass *lupb_msg_getsubmsgclass(lua_State *L, int narg, - const upb_fielddef *f) { - lupb_uservalgeti(L, narg, LUPB_MSG_MSGCLASSINDEX); - return lupb_msgclass_getsubmsgclass(L, -1, f); -} - -int lupb_msg_pushref(lua_State *L, int msgclass, upb_msg *msg) { - const lupb_msgclass *lmsgclass = lupb_msgclass_check(L, msgclass); - lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), LUPB_MSG); - - lmsg->lmsgclass = lmsgclass; - lmsg->msg = msg; - - lupb_uservalseti(L, -1, LUPB_MSG_MSGCLASSINDEX, msgclass); - lupb_uservalseti(L, -1, LUPB_MSG_ARENA, -2); - - return 1; -} - /* lupb_msg Public API */ /** @@ -973,9 +769,8 @@ static int lupb_msg_pushnew(lua_State *L, int narg) { * msg[field_descriptor] # (for extensions) (TODO) */ static int lupb_msg_index(lua_State *L) { - lupb_msg *lmsg = lupb_msg_check(L, 1); + upb_msg *msg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); - const upb_msglayout *l = lmsg->lmsgclass->layout; if (in_userval(f)) { lupb_uservalgeti(L, 1, lupb_fieldindex(f)); @@ -987,9 +782,9 @@ static int lupb_msg_index(lua_State *L) { } else if (upb_fielddef_issubmsg(f)) { /* TODO(haberman) */ } else { - UPB_ASSERT(upb_fielddef_isstring(f)); - if (upb_msg_has(lmsg->msg, f, l)) { - upb_msgval val = upb_msg_get(lmsg->msg, f, l); + assert(upb_fielddef_isstring(f)); + if (upb_msg_has(msg, f)) { + upb_msgval val = upb_msg_get(msg, f); lua_pop(L, 1); lua_pushlstring(L, val.str_val.data, val.str_val.size); lupb_uservalseti(L, 1, lupb_fieldindex(f), -1); @@ -997,7 +792,7 @@ static int lupb_msg_index(lua_State *L) { } } } else { - upb_msgval val = upb_msg_get(lmsg->msg, f, l); + upb_msgval val = upb_msg_get(msg, f); lupb_pushmsgval(L, upb_fielddef_type(f), val); } @@ -1013,11 +808,10 @@ static int lupb_msg_index(lua_State *L) { * msg[field_descriptor] = bar # (for extensions) (TODO) */ static int lupb_msg_newindex(lua_State *L) { - lupb_msg *lmsg = lupb_msg_check(L, 1); + upb_msg *msg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); upb_fieldtype_t type = upb_fielddef_type(f); upb_arena *arena = lupb_arena_get(L); - const upb_msglayout *layout = lmsg->lmsgclass->layout; upb_msgval msgval; /* Typecheck and get msgval. */ @@ -1027,18 +821,14 @@ static int lupb_msg_newindex(lua_State *L) { } else if (upb_fielddef_ismap(f)) { msgval = lupb_map_typecheck(L, 3, 1, f); } else { - const lupb_msgclass *lmsgclass = NULL; - - if (type == UPB_TYPE_MESSAGE) { - lmsgclass = lupb_msg_getsubmsgclass(L, 1, f); - } - - msgval = lupb_tomsgval(L, type, 3, lmsgclass); + const upb_msgdef *msgdef = + type == UPB_TYPE_MESSAGE ? upb_fielddef_msgsubdef(f) : NULL; + msgval = lupb_tomsgval(L, type, 3, msgdef); } /* Set in upb_msg and userval (if necessary). */ - upb_msg_set(lmsg->msg, f, msgval, layout, arena); + upb_msg_set(msg, f, msgval, arena); if (in_userval(f)) { lupb_uservalseti(L, 1, lupb_fieldindex(f), 3); @@ -1056,10 +846,41 @@ static const struct luaL_Reg lupb_msg_mm[] = { /* lupb_msg toplevel **********************************************************/ +static int lupb_decode(lua_State *L) { + size_t len; + const upb_msglayout *layout; + upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout); + const char *pb = lua_tolstring(L, 2, &len); + + upb_decode(pb, len, msg, layout, lupb_arena_get(L)); + /* TODO(haberman): check for error. */ + + return 0; +} + +static int lupb_encode(lua_State *L) { + const upb_msglayout *layout; + const upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout); + upb_arena *arena = upb_arena_new(); + size_t size; + char *result; + + result = upb_encode(msg, (const void*)layout, arena, &size); + + /* Free resources before we potentially bail on error. */ + lua_pushlstring(L, result, size); + upb_arena_free(arena); + /* TODO(haberman): check for error. */ + + return 1; +} + static const struct luaL_Reg lupb_msg_toplevel_m[] = { {"Array", lupb_array_new}, {"Map", lupb_map_new}, {"MessageFactory", lupb_msgfactory_new}, + {"decode", lupb_decode}, + {"encode", lupb_encode}, {NULL, NULL} }; diff --git a/upb/bindings/lua/upb.c b/upb/bindings/lua/upb.c index 38fd24a27e..d4dc2b06e7 100644 --- a/upb/bindings/lua/upb.c +++ b/upb/bindings/lua/upb.c @@ -20,16 +20,16 @@ ** domain of [u]int64 values. */ +#include "upb/bindings/lua/upb.h" + #include #include #include #include + #include "lauxlib.h" -#include "upb/bindings/lua/upb.h" -#include "upb/handlers.h" #include "upb/msg.h" - /* Lua compatibility code *****************************************************/ /* Lua 5.1 and Lua 5.2 have slightly incompatible APIs. A little bit of @@ -53,10 +53,6 @@ void *luaL_testudata(lua_State *L, int ud, const char *tname) { return NULL; /* value is not a userdata with a metatable */ } -static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) { - luaL_register(L, name, funcs); -} - #elif LUA_VERSION_NUM == 502 int luaL_typerror(lua_State *L, int narg, const char *tname) { @@ -65,17 +61,6 @@ int luaL_typerror(lua_State *L, int narg, const char *tname) { return luaL_argerror(L, narg, msg); } -static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) { - /* Lua 5.2 modules are not expected to set a global variable, so "name" is - * unused. */ - UPB_UNUSED(name); - - /* Can't use luaL_newlib(), because funcs is not the actual array. - * Could (micro-)optimize this a bit to count funcs for initial table size. */ - lua_createtable(L, 0, 8); - luaL_setfuncs(L, funcs, 0); -} - #else #error Only Lua 5.1 and 5.2 are supported #endif @@ -90,28 +75,6 @@ bool lua_isinteger(lua_State *L, int argn) { /* Utility functions **********************************************************/ -/* We store our module table in the registry, keyed by ptr. - * For more info about the motivation/rationale, see this thread: - * http://thread.gmane.org/gmane.comp.lang.lua.general/110632 */ -bool lupb_openlib(lua_State *L, void *ptr, const char *name, - const luaL_Reg *funcs) { - /* Lookup cached module table. */ - lua_pushlightuserdata(L, ptr); - lua_rawget(L, LUA_REGISTRYINDEX); - if (!lua_isnil(L, -1)) { - return true; - } - - lupb_newlib(L, name, funcs); - - /* Save module table in cache. */ - lua_pushlightuserdata(L, ptr); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); - - return false; -} - void lupb_checkstatus(lua_State *L, upb_status *s) { if (!upb_ok(s)) { lua_pushstring(L, upb_status_errmsg(s)); @@ -119,6 +82,20 @@ void lupb_checkstatus(lua_State *L, upb_status *s) { } } +/* Pushes a new userdata with the given metatable. */ +static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) { + void *ret = lua_newuserdata(L, size); + + /* Set metatable. */ + luaL_getmetatable(L, type); + assert(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */ + lua_setmetatable(L, -2); + + /* We don't set a uservalue here -- we lazily create it later if necessary. */ + + return ret; +} + /* Scalar type mapping ********************************************************/ /* Functions that convert scalar/primitive values (numbers, strings, bool) @@ -205,10 +182,6 @@ void lupb_pushfloat(lua_State *L, float d) { } -static const struct luaL_Reg lupb_toplevel_m[] = { - {NULL, NULL} -}; - void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, const luaL_Reg *mm) { luaL_newmetatable(L, name); @@ -233,13 +206,13 @@ void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, } int luaopen_upb_c(lua_State *L) { - static char module_key; - if (lupb_openlib(L, &module_key, "upb_c", lupb_toplevel_m)) { - return 1; - } - +#if LUA_VERSION == 501 + const struct luaL_Reg funcs[] = {{NULL, NULL}}; + luaL_register(L, "upb_c", funcs); +#else + lua_createtable(L, 0, 8); +#endif lupb_def_registertypes(L); lupb_msg_registertypes(L); - return 1; /* Return package table. */ } diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h index 096e3fd9e9..02b0c7adba 100644 --- a/upb/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h @@ -7,65 +7,51 @@ #include "lauxlib.h" #include "upb/def.h" -#include "upb/handlers.h" #include "upb/msg.h" #include "upb/msgfactory.h" -/* Lua 5.1/5.2 compatibility code. */ +/* Lua changes its API in incompatible ways in every minor release. + * This is some shim code to paper over the differences. */ + #if LUA_VERSION_NUM == 501 #define lua_rawlen lua_objlen -/* Lua >= 5.2's getuservalue/setuservalue functions do not exist in prior - * versions but the older function lua_getfenv() can provide 100% of its - * capabilities (the reverse is not true). */ -#define lua_getuservalue(L, index) lua_getfenv(L, index) -#define lua_setuservalue(L, index) lua_setfenv(L, index) - void *luaL_testudata(lua_State *L, int ud, const char *tname); #define lupb_setfuncs(L, l) luaL_register(L, NULL, l) -#elif LUA_VERSION_NUM == 502 +#elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 504 int luaL_typerror(lua_State *L, int narg, const char *tname); #define lupb_setfuncs(L, l) luaL_setfuncs(L, l, 0) #else -#error Only Lua 5.1 and 5.2 are supported +#error Only Lua 5.1-5.4 are supported #endif -#define lupb_assert(L, predicate) \ - if (!(predicate)) \ - luaL_error(L, "internal error: %s, %s:%d ", #predicate, __FILE__, __LINE__); +/* Create a new userdata with the given type and |n| uservals, which are popped + * from the stack to initialize the userdata. */ +void *lupb_newuserdata(lua_State *L, size_t size, int n, const char *type); -/* Function for initializing the core library. This function is idempotent, - * and should be called at least once before calling any of the functions that - * construct core upb types. */ -int luaopen_upb(lua_State *L); - -/* Gets or creates a package table for a C module that is uniquely identified by - * "ptr". The easiest way to supply a unique "ptr" is to pass the address of a - * static variable private in the module's .c file. - * - * If this module has already been registered in this lua_State, pushes it and - * returns true. - * - * Otherwise, creates a new module table for this module with the given name, - * pushes it, and registers the given top-level functions in it. It also sets - * it as a global variable, but only if the current version of Lua expects that - * (ie Lua 5.1/LuaJIT). - * - * If "false" is returned, the caller is guaranteed that this lib has not been - * registered in this Lua state before (regardless of any funny business the - * user might have done to the global state), so the caller can safely perform - * one-time initialization. */ -bool lupb_openlib(lua_State *L, void *ptr, const char *name, - const luaL_Reg *funcs); +#if LUA_VERSION_NUM < 504 +/* Polyfills for this Lua 5.4 function. Pushes userval |n| for the userdata at + * |index|. */ +int lua_getiuservalue(lua_State *L, int index, int n); +#endif + +/* Registers a type with the given name, methods, and metamethods. */ +void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, + const luaL_Reg *mm); + +/* Checks the given upb_status and throws a Lua error if it is not ok. */ +void lupb_checkstatus(lua_State *L, upb_status *s); + +/* C <-> Lua value conversions. ***********************************************/ /* Custom check/push functions. Unlike the Lua equivalents, they are pinned to - * specific types (instead of lua_Number, etc), and do not allow any implicit + * specific C types (instead of lua_Number, etc), and do not allow any implicit * conversion or data loss. */ int64_t lupb_checkint64(lua_State *L, int narg); int32_t lupb_checkint32(lua_State *L, int narg); @@ -84,13 +70,6 @@ void lupb_pushuint32(lua_State *L, uint32_t val); void lupb_pushdouble(lua_State *L, double val); void lupb_pushfloat(lua_State *L, float val); -/* Registers a type with the given name, methods, and metamethods. */ -void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, - const luaL_Reg *mm); - -/* Checks the given upb_status and throws a Lua error if it is not ok. */ -void lupb_checkstatus(lua_State *L, upb_status *s); - /** From def.c. ***************************************************************/ @@ -106,21 +85,25 @@ void lupb_def_registertypes(lua_State *L); /** From msg.c. ***************************************************************/ -struct lupb_msgclass; -typedef struct lupb_msgclass lupb_msgclass; - upb_arena *lupb_arena_check(lua_State *L, int narg); int lupb_arena_new(lua_State *L); upb_arena *lupb_arena_get(lua_State *L); -int lupb_msg_pushref(lua_State *L, int msgclass, void *msg); const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg, - const lupb_msgclass *lmsgclass); + const upb_msgdef *msgdef); upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg, const upb_msglayout **layout); -const lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg); -const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg); -const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass); void lupb_msg_registertypes(lua_State *L); +#define lupb_assert(L, predicate) \ + if (!(predicate)) \ + luaL_error(L, "internal error: %s, %s:%d ", #predicate, __FILE__, __LINE__); + +#if defined(__GNUC__) || defined(__clang__) +#define LUPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) +#else +#define LUPB_UNREACHABLE() do { assert(0); } while(0) +#endif + + #endif /* UPB_LUA_UPB_H_ */ diff --git a/upb/bindings/lua/upb/pb.c b/upb/bindings/lua/upb/pb.c deleted file mode 100644 index 266bd974c9..0000000000 --- a/upb/bindings/lua/upb/pb.c +++ /dev/null @@ -1,56 +0,0 @@ -/* -** require("upb.pb") -- A Lua extension for upb.pb. -** -** Exposes all the types defined in upb/pb/{*}.h -** Also defines a few convenience functions on top. -*/ - -#include "upb/bindings/lua/upb.h" -#include "upb/decode.h" -#include "upb/encode.h" - -#define LUPB_PBDECODERMETHOD "lupb.pb.decodermethod" - -static int lupb_pb_decode(lua_State *L) { - size_t len; - const upb_msglayout *layout; - upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout); - const char *pb = lua_tolstring(L, 2, &len); - - upb_decode(pb, len, msg, layout, lupb_arena_get(L)); - /* TODO(haberman): check for error. */ - - return 0; -} - -static int lupb_pb_encode(lua_State *L) { - const upb_msglayout *layout; - const upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout); - upb_arena *arena = upb_arena_new(); - size_t size; - char *result; - - result = upb_encode(msg, (const void*)layout, arena, &size); - - /* Free resources before we potentially bail on error. */ - lua_pushlstring(L, result, size); - upb_arena_free(arena); - /* TODO(haberman): check for error. */ - - return 1; -} - -static const struct luaL_Reg toplevel_m[] = { - {"decode", lupb_pb_decode}, - {"encode", lupb_pb_encode}, - {NULL, NULL} -}; - -int luaopen_upb_pb_c(lua_State *L) { - static char module_key; - if (lupb_openlib(L, &module_key, "upb.pb_c", toplevel_m)) { - return 1; - } - - return 1; -} diff --git a/upb/bindings/lua/upb/pb.lua b/upb/bindings/lua/upb/pb.lua deleted file mode 100644 index b865902d3a..0000000000 --- a/upb/bindings/lua/upb/pb.lua +++ /dev/null @@ -1,3 +0,0 @@ - -require "upb" -return require "upb.pb_c" diff --git a/upb/reflection.h b/upb/reflection.h index b23ceaeb01..850149c930 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -30,35 +30,34 @@ typedef union { /** upb_msg *******************************************************************/ +/* Creates a new message of the given type in the given arena. */ +upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a); + /* Returns the value associated with this field. */ -upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f, - const upb_msglayout *l); +upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f); /* Returns a mutable pointer to a map, array, or submessage value, constructing * a new object if it was not previously present. May not be called for * primitive fields. */ -upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, - const upb_msglayout *l, upb_arena *a); +upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a); /* May only be called for fields where upb_fielddef_haspresence(f) == true. */ -bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f, - const upb_msglayout *l); +bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f); /* Sets the given field to the given value. For a msg/array/map/string, the * value must be in the same arena. */ void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, - const upb_msglayout *l, upb_arena *a); + upb_arena *a); /* Clears any field presence and sets the value back to its default. */ -void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f, - const upb_msglayout *l); +void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f); /** upb_array *****************************************************************/ /* Returns the size of the array. */ size_t upb_array_size(const upb_array *arr); -/* Returns the given element. */ +/* Returns the given element, which must be within the array's current size. */ upb_msgval upb_array_get(const upb_array *arr, size_t i); /* Sets the given element, which must be within the array's current size. */ From 23825332e15803b052239e3298da98aea5cec008 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sun, 1 Dec 2019 21:09:47 -0800 Subject: [PATCH 08/35] WIP. --- BUILD | 27 +- .../google/protobuf/descriptor.upb.h | 128 +-- upb/bindings/lua/def.c | 61 +- upb/bindings/lua/msg.c | 746 +++++++++--------- upb/bindings/lua/upb.c | 117 ++- upb/bindings/lua/upb.h | 32 +- upb/bindings/lua/upb.lua | 172 ---- upb/decode.c | 4 +- upb/def.c | 8 +- upb/msg.c | 24 +- upb/msg.h | 6 +- upb/port_def.inc | 5 + upb/reflection.c | 302 ++----- upb/reflection.h | 8 +- upb/table.c | 21 +- upb/table.int.h | 3 +- upbc/generator.cc | 6 +- 17 files changed, 678 insertions(+), 992 deletions(-) delete mode 100644 upb/bindings/lua/upb.lua diff --git a/BUILD b/BUILD index 488b3684ea..2b7d82e417 100644 --- a/BUILD +++ b/BUILD @@ -526,6 +526,7 @@ sh_test( ":conformance_upb", "@com_google_protobuf//:conformance_test_runner", ], + deps = ["@bazel_tools//tools/bash/runfiles"], ) # copybara:strip_for_google3_begin @@ -564,10 +565,10 @@ cc_library( }), ) -# Lua libraries. ############################################################### +# Lua ########################################################################## -lua_cclibrary( - name = "lua/upb_c", +cc_library( + name = "lupb", srcs = [ "upb/bindings/lua/def.c", "upb/bindings/lua/msg.c", @@ -577,20 +578,21 @@ lua_cclibrary( "upb/bindings/lua/upb.h", ], deps = [ - "reflection", - "upb", + ":reflection", + ":upb", + "@lua//:liblua", ], ) -lua_library( - name = "lua/upb", - srcs = ["upb/bindings/lua/upb.lua"], - luadeps = ["lua/upb_c"], - strip_prefix = "upb/bindings/lua", +cc_binary( + name = "lua_tester", + srcs = ["tests/bindings/lua/main.c"], + deps = [ + ":lupb", + "@lua//:liblua", + ] ) -# Lua tests. ################################################################### - lua_test( name = "lua/test_upb", luadeps = ["lua/upb"], @@ -621,6 +623,7 @@ sh_test( name = "cmake_build", srcs = ["run_cmake_build.sh"], data = [":cmake_files"], + deps = ["@bazel_tools//tools/bash/runfiles"], ) # Generated files ############################################################## diff --git a/generated_for_cmake/google/protobuf/descriptor.upb.h b/generated_for_cmake/google/protobuf/descriptor.upb.h index c8c392185a..33e020011d 100644 --- a/generated_for_cmake/google/protobuf/descriptor.upb.h +++ b/generated_for_cmake/google/protobuf/descriptor.upb.h @@ -157,7 +157,7 @@ typedef enum { /* google.protobuf.FileDescriptorSet */ UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_new(upb_arena *arena) { - return (google_protobuf_FileDescriptorSet *)upb_msg_new(&google_protobuf_FileDescriptorSet_msginit, arena); + return (google_protobuf_FileDescriptorSet *)_upb_msg_new(&google_protobuf_FileDescriptorSet_msginit, arena); } UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parse(const char *buf, size_t size, upb_arena *arena) { @@ -177,7 +177,7 @@ UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorS return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_arena *arena) { - struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); + struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -187,7 +187,7 @@ UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescr /* google.protobuf.FileDescriptorProto */ UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_FileDescriptorProto *)upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); + return (google_protobuf_FileDescriptorProto *)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -241,7 +241,7 @@ UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(40, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -254,7 +254,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorP return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(44, 88), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -267,7 +267,7 @@ UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescript return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(48, 96), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); + struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(48, 96), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -280,7 +280,7 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptor return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(52, 104), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(52, 104), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -293,7 +293,7 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_ UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_FileOptions*)upb_msg_new(&google_protobuf_FileOptions_msginit, arena); + sub = (struct google_protobuf_FileOptions*)_upb_msg_new(&google_protobuf_FileOptions_msginit, arena); if (!sub) return NULL; google_protobuf_FileDescriptorProto_set_options(msg, sub); } @@ -306,7 +306,7 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_ UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); if (sub == NULL) { - sub = (struct google_protobuf_SourceCodeInfo*)upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); + sub = (struct google_protobuf_SourceCodeInfo*)_upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); if (!sub) return NULL; google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); } @@ -340,7 +340,7 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_F /* google.protobuf.DescriptorProto */ UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_new(upb_arena *arena) { - return (google_protobuf_DescriptorProto *)upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); + return (google_protobuf_DescriptorProto *)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -375,7 +375,7 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -388,7 +388,7 @@ UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_res return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(20, 40), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -401,7 +401,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(24, 48), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -414,7 +414,7 @@ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_Desc return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); + struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(28, 56), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -427,7 +427,7 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(32, 64), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(32, 64), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -440,7 +440,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_Desc UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_arena *arena) { struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_MessageOptions*)upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); + sub = (struct google_protobuf_MessageOptions*)_upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); if (!sub) return NULL; google_protobuf_DescriptorProto_set_options(msg, sub); } @@ -453,7 +453,7 @@ UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); + struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(36, 72), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -466,7 +466,7 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_Descr return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); + struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(40, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -486,7 +486,7 @@ UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobu /* google.protobuf.DescriptorProto.ExtensionRange */ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_new(upb_arena *arena) { - return (google_protobuf_DescriptorProto_ExtensionRange *)upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); + return (google_protobuf_DescriptorProto_ExtensionRange *)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parse(const char *buf, size_t size, upb_arena *arena) { @@ -519,7 +519,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(googl UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_arena *arena) { struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_ExtensionRangeOptions*)upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); + sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); if (!sub) return NULL; google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); } @@ -529,7 +529,7 @@ UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_Descrip /* google.protobuf.DescriptorProto.ReservedRange */ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_new(upb_arena *arena) { - return (google_protobuf_DescriptorProto_ReservedRange *)upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); + return (google_protobuf_DescriptorProto_ReservedRange *)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); } UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parse(const char *buf, size_t size, upb_arena *arena) { @@ -557,7 +557,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_pro /* google.protobuf.ExtensionRangeOptions */ UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_new(upb_arena *arena) { - return (google_protobuf_ExtensionRangeOptions *)upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); + return (google_protobuf_ExtensionRangeOptions *)_upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); } UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -577,7 +577,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeO return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -587,7 +587,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_Extension /* google.protobuf.FieldDescriptorProto */ UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto *)upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); + return (google_protobuf_FieldDescriptorProto *)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -654,7 +654,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_FieldOptions*)upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); + sub = (struct google_protobuf_FieldOptions*)_upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); if (!sub) return NULL; google_protobuf_FieldDescriptorProto_set_options(msg, sub); } @@ -672,7 +672,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protob /* google.protobuf.OneofDescriptorProto */ UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_OneofDescriptorProto *)upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); + return (google_protobuf_OneofDescriptorProto *)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -699,7 +699,7 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_OneofOptions*)upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); + sub = (struct google_protobuf_OneofOptions*)_upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); if (!sub) return NULL; google_protobuf_OneofDescriptorProto_set_options(msg, sub); } @@ -709,7 +709,7 @@ UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorP /* google.protobuf.EnumDescriptorProto */ UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto *)upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); + return (google_protobuf_EnumDescriptorProto *)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -739,7 +739,7 @@ UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescri return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); + struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -752,7 +752,7 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_ UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_EnumOptions*)upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); + sub = (struct google_protobuf_EnumOptions*)_upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); if (!sub) return NULL; google_protobuf_EnumDescriptorProto_set_options(msg, sub); } @@ -765,7 +765,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protob return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); + struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(20, 40), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -785,7 +785,7 @@ UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_pro /* google.protobuf.EnumDescriptorProto.EnumReservedRange */ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange *)upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange *)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); } UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char *buf, size_t size, upb_arena *arena) { @@ -813,7 +813,7 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(go /* google.protobuf.EnumValueDescriptorProto */ UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_EnumValueDescriptorProto *)upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); + return (google_protobuf_EnumValueDescriptorProto *)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -846,7 +846,7 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_prot UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_EnumValueOptions*)upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); + sub = (struct google_protobuf_EnumValueOptions*)_upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); if (!sub) return NULL; google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); } @@ -856,7 +856,7 @@ UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDes /* google.protobuf.ServiceDescriptorProto */ UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_ServiceDescriptorProto *)upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); + return (google_protobuf_ServiceDescriptorProto *)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -884,7 +884,7 @@ UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescri return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); + struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -897,7 +897,7 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protob UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_ServiceOptions*)upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); + sub = (struct google_protobuf_ServiceOptions*)_upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); if (!sub) return NULL; google_protobuf_ServiceDescriptorProto_set_options(msg, sub); } @@ -907,7 +907,7 @@ UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescrip /* google.protobuf.MethodDescriptorProto */ UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_MethodDescriptorProto *)upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); + return (google_protobuf_MethodDescriptorProto *)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); } UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parse(const char *buf, size_t size, upb_arena *arena) { @@ -950,7 +950,7 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobu UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_arena *arena) { struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_MethodOptions*)upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); + sub = (struct google_protobuf_MethodOptions*)_upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); if (!sub) return NULL; google_protobuf_MethodDescriptorProto_set_options(msg, sub); } @@ -968,7 +968,7 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(googl /* google.protobuf.FileOptions */ UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_new(upb_arena *arena) { - return (google_protobuf_FileOptions *)upb_msg_new(&google_protobuf_FileOptions_msginit, arena); + return (google_protobuf_FileOptions *)_upb_msg_new(&google_protobuf_FileOptions_msginit, arena); } UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1108,7 +1108,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_res return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(108, 192), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(108, 192), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1118,7 +1118,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptio /* google.protobuf.MessageOptions */ UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_new(upb_arena *arena) { - return (google_protobuf_MessageOptions *)upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); + return (google_protobuf_MessageOptions *)_upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); } UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1162,7 +1162,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(8, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(8, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1172,7 +1172,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOp /* google.protobuf.FieldOptions */ UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_new(upb_arena *arena) { - return (google_protobuf_FieldOptions *)upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); + return (google_protobuf_FieldOptions *)_upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); } UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1228,7 +1228,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_re return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 32), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(28, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1238,7 +1238,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOpti /* google.protobuf.OneofOptions */ UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_new(upb_arena *arena) { - return (google_protobuf_OneofOptions *)upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); + return (google_protobuf_OneofOptions *)_upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); } UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1258,7 +1258,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_re return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1268,7 +1268,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOpti /* google.protobuf.EnumOptions */ UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_new(upb_arena *arena) { - return (google_protobuf_EnumOptions *)upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); + return (google_protobuf_EnumOptions *)_upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); } UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1300,7 +1300,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_res return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1310,7 +1310,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptio /* google.protobuf.EnumValueOptions */ UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_new(upb_arena *arena) { - return (google_protobuf_EnumValueOptions *)upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); + return (google_protobuf_EnumValueOptions *)_upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); } UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1336,7 +1336,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOption return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1346,7 +1346,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValue /* google.protobuf.ServiceOptions */ UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_new(upb_arena *arena) { - return (google_protobuf_ServiceOptions *)upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); + return (google_protobuf_ServiceOptions *)_upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); } UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1372,7 +1372,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1382,7 +1382,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOp /* google.protobuf.MethodOptions */ UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_new(upb_arena *arena) { - return (google_protobuf_MethodOptions *)upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); + return (google_protobuf_MethodOptions *)_upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); } UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1414,7 +1414,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_r return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 24), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(20, 24), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1424,7 +1424,7 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOpt /* google.protobuf.UninterpretedOption */ UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_new(upb_arena *arena) { - return (google_protobuf_UninterpretedOption *)upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); + return (google_protobuf_UninterpretedOption *)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); } UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1456,7 +1456,7 @@ UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_Uninte return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor(msg, UPB_SIZE(56, 80), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); + struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(56, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1490,7 +1490,7 @@ UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_p /* google.protobuf.UninterpretedOption.NamePart */ UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_new(upb_arena *arena) { - return (google_protobuf_UninterpretedOption_NamePart *)upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); + return (google_protobuf_UninterpretedOption_NamePart *)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1518,7 +1518,7 @@ UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(go /* google.protobuf.SourceCodeInfo */ UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_new(upb_arena *arena) { - return (google_protobuf_SourceCodeInfo *)upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); + return (google_protobuf_SourceCodeInfo *)_upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); } UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1538,7 +1538,7 @@ UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeI return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_arena *arena) { - struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); + struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1548,7 +1548,7 @@ UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_Sourc /* google.protobuf.SourceCodeInfo.Location */ UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_new(upb_arena *arena) { - return (google_protobuf_SourceCodeInfo_Location *)upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); + return (google_protobuf_SourceCodeInfo_Location *)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); } UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1609,7 +1609,7 @@ UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_com /* google.protobuf.GeneratedCodeInfo */ UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_new(upb_arena *arena) { - return (google_protobuf_GeneratedCodeInfo *)upb_msg_new(&google_protobuf_GeneratedCodeInfo_msginit, arena); + return (google_protobuf_GeneratedCodeInfo *)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_msginit, arena); } UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parse(const char *buf, size_t size, upb_arena *arena) { @@ -1629,7 +1629,7 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_Genera return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); } UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena) { - struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); + struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); bool ok = _upb_array_append_accessor( msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); if (!ok) return NULL; @@ -1639,7 +1639,7 @@ UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_ /* google.protobuf.GeneratedCodeInfo.Annotation */ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_new(upb_arena *arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation *)upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); + return (google_protobuf_GeneratedCodeInfo_Annotation *)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); } UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parse(const char *buf, size_t size, upb_arena *arena) { diff --git a/upb/bindings/lua/def.c b/upb/bindings/lua/def.c index a163ad13e9..75b49762d9 100644 --- a/upb/bindings/lua/def.c +++ b/upb/bindings/lua/def.c @@ -23,30 +23,20 @@ static void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, /* Wrappers around upb def objects. The userval contains a reference to the * symtab. */ +#define LUPB_SYMTAB_INDEX 1 + typedef struct { const void* def; /* upb_msgdef, upb_enumdef, upb_oneofdef, etc. */ } lupb_wrapper; static const void *lupb_wrapper_check(lua_State *L, int narg, const char *type) { - lupb_wrapper *w = lua_touserdata(L, narg); - - if (!w) { - luaL_typerror(L, narg, "upb wrapper"); - } - - if (!w->def) { - luaL_error(L, "called into dead object"); - } - - luaL_checkudata(L, narg, type); + lupb_wrapper *w = luaL_checkudata(L, narg, type); return w->def; } static void lupb_wrapper_pushsymtab(lua_State *L, int narg) { - lua_getuserval(L, narg); - lua_rawgeti(L, -1, 1); - lua_replace(L, -2); + lua_getiuservalue(L, narg, LUPB_SYMTAB_INDEX); } /* lupb_wrapper_pushwrapper() @@ -60,6 +50,11 @@ static void lupb_wrapper_pushwrapper(lua_State *L, int narg, const void *def, lua_replace(L, -2); /* Remove symtab from stack. */ } +void lupb_msgdef_pushmsgdef(lua_State *L, int narg, const upb_fielddef *f) { + const upb_msgdef *m = upb_fielddef_msgsubdef(f); + lupb_wrapper_pushwrapper(L, narg, m, LUPB_MSGDEF); +} + /* lupb_fielddef **************************************************************/ const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { @@ -68,7 +63,7 @@ const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { static int lupb_fielddef_containingoneof(lua_State *L) { const upb_fielddef *f = lupb_fielddef_check(L, 1); - const upb_oneof *o = upb_fielddef_containingoneof(f); + const upb_oneofdef *o = upb_fielddef_containingoneof(f); lupb_wrapper_pushwrapper(L, 1, o, LUPB_ONEOFDEF); return 1; } @@ -228,7 +223,7 @@ static int lupb_oneofdef_containingtype(lua_State *L) { * oneof.field(field_name) */ static int lupb_oneofdef_field(lua_State *L) { - const upb_oneofdef *o = lupb_oneofdef_check(L, narg); + const upb_oneofdef *o = lupb_oneofdef_check(L, 1); const upb_fielddef *f; switch (lua_type(L, 2)) { @@ -260,10 +255,10 @@ static int lupb_oneofiter_next(lua_State *L) { } static int lupb_oneofdef_fields(lua_State *L) { - const upb_oneofdef *o = lupb_oneof_check(L, 1); - lupb_oneofiter *i = lua_newuserdata(L, sizeof(lupb_oneofiter)); + const upb_oneofdef *o = lupb_oneofdef_check(L, 1); + upb_oneof_iter *i = lua_newuserdata(L, sizeof(upb_oneof_iter)); lupb_wrapper_pushsymtab(L, 1); - upb_oneof_begin(&i->iter, o); + upb_oneof_begin(i, o); /* Closure upvalues are: iter, symtab. */ lua_pushcclosure(L, &lupb_oneofiter_next, 2); @@ -367,7 +362,7 @@ static int lupb_msgfielditer_next(lua_State *L) { if (upb_msg_field_done(i)) return 0; f = upb_msg_iter_field(i); - lupb_symtab_pushwrapper(L, lua_upvalueindex(2), f); + lupb_symtab_pushwrapper(L, lua_upvalueindex(2), f, LUPB_FIELDDEF); upb_msg_field_next(i); return 1; } @@ -389,7 +384,7 @@ static int lupb_msgoneofiter_next(lua_State *L) { if (upb_msg_oneof_done(i)) return 0; o = upb_msg_iter_oneof(i); upb_msg_oneof_next(i); - lupb_symtab_pushwrapper(L, lua_upvalueindex(2), o); + lupb_symtab_pushwrapper(L, lua_upvalueindex(2), o, LUPB_ONEOFDEF); return 1; } @@ -417,6 +412,7 @@ static int lupb_msgdef_syntax(lua_State *L) { } static const struct luaL_Reg lupb_msgdef_mm[] = { + {"__call", lupb_msg_pushnew}, {"__len", lupb_msgdef_len}, {NULL, NULL} }; @@ -599,6 +595,8 @@ static const struct luaL_Reg lupb_filedef_m[] = { * * The symtab's userval is a cache of def* -> object. */ +#define LUPB_CACHE_INDEX 1 + typedef struct { upb_symtab *symtab; } lupb_symtab; @@ -618,11 +616,10 @@ void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, return; } - lua_getuserval(L, narg); /* Get cache. */ + lua_getiuservalue(L, narg, LUPB_CACHE_INDEX); /* Get cache. */ /* Index by "def" pointer. */ - lua_pushlightuserdata(L, (void*)def); - lua_rawget(L, -2) + lua_rawgetp(L, -1, def); /* Stack is now: cache, cached value. */ if (lua_isnil(L, -1)) { @@ -631,14 +628,17 @@ void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, w->def = def; lua_replace(L, -2); /* Replace nil */ + /* Set symtab as userval. */ + lua_pushvalue(L, narg); + lua_setiuservalue(L, -2, LUPB_SYMTAB_INDEX); + /* Set metatable of wrapper. */ luaL_getmetatable(L, type); lua_setmetatable(L, -2); /* Add wrapper to the the cache. */ - lua_pushlightuserdata(L, (void*)def); - lua_pushvalue(L, -2); - lua_rawset(L, -4); + lua_pushvalue(L, -1); + lua_rawsetp(L, -3, def); } lua_replace(L, -2); /* Remove cache, leaving only the wrapper. */ @@ -666,7 +666,7 @@ static int lupb_symtab_new(lua_State *L) { lua_setmetatable(L, -2); /* Set the cache as our userval. */ - lua_setuservalue(L, -2); + lua_setiuservalue(L, -2, LUPB_CACHE_INDEX); return 1; } @@ -679,18 +679,15 @@ static int lupb_symtab_gc(lua_State *L) { } static int lupb_symtab_add(lua_State *L) { - upb_arena *arena; size_t i, n, len; const google_protobuf_FileDescriptorProto *const *files; google_protobuf_FileDescriptorSet *set; upb_symtab *s = lupb_symtab_check(L, 1); const char *str = luaL_checklstring(L, 2, &len); + upb_arena *arena = lupb_arena_pushnew(L);; upb_status status; - lupb_arena_new(L); upb_status_clear(&status); - arena = lupb_arena_check(L, -1); - set = google_protobuf_FileDescriptorSet_parse(str, len, arena); if (!set) { diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 012457d03d..f1cd2db0db 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -86,7 +86,7 @@ * Descriptor object if they are typed to store message values. * * (The object cache could be per-arena-group. This would keep individual cache - * tables smaller, and when an arena group is freed the entire cache table could + * tables smaller, and when an arena group is freed the entire cache table(s) could * be collected in one fell swoop. However this makes merging another arena * into the group an O(n) operation, since all entries would need to be copied * from the existing cache table.) @@ -97,16 +97,72 @@ #define LUPB_MAP "lupb.map" #define LUPB_MSG "lupb.msg" -static int lupb_msg_pushnew(lua_State *L, int narg); +#define LUPB_ARENA_INDEX 1 +#define LUPB_MSGDEF_INDEX 2 /* For msg, and map/array that store msg */ -static void lupb_msg_typecheck(lua_State *L, const upb_msgdef *expected, - const upb_msgdef *actual) { - if (expected != actual) { - luaL_error(L, "Message had incorrect type, expected '%s', got '%s'", - upb_msgdef_fullname(expected), upb_msgdef_fullname(actual)); +static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val); +static upb_msg *lupb_msg_check(lua_State *L, int narg); + +static upb_fieldtype_t lupb_checkfieldtype(lua_State *L, int narg) { + uint32_t n = lupb_checkuint32(L, narg); + bool ok = n >= UPB_TYPE_BOOL && n <= UPB_TYPE_BYTES; + luaL_argcheck(L, ok, narg, "invalid field type"); + return n; +} + +char cache_key; + +/* lupb_cacheinit() + * + * Creates the global cache used by lupb_cacheget() and lupb_cacheset(). + */ +static void lupb_cacheinit(lua_State *L) { + /* Create our object cache. */ + lua_newtable(L); + + /* Cache metatable gives the cache weak values */ + lua_createtable(L, 0, 1); + lua_pushstring(L, "v"); + lua_setfield(L, -2, "__mode"); + lua_setmetatable(L, -2); + + /* Set cache in the registry. */ + lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key); +} + +/* lupb_cacheget() + * + * Pushes cache[key] and returns true if this key is present in the cache. + * Otherwise returns false and leaves nothing on the stack. + */ +static bool lupb_cacheget(lua_State *L, const void *key) { + if (key == NULL) { + lua_pushnil(L); + return true; + } + + lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key); + lua_rawgetp(L, -1, key); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); /* Pop table, nil. */ + return false; + } else { + lua_replace(L, -2); /* Replace cache table. */ + return true; } } +/* lupb_cacheset() + * + * Sets cache[key] = val, where "val" is the value at the top of the stack. + * Does not pop the value. + */ +static void lupb_cacheset(lua_State *L, const void *key) { + lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key); + lua_pushvalue(L, -2); + lua_rawsetp(L, -2, key); + lua_pop(L, 1); /* Pop table. */ +} /* lupb_arena *****************************************************************/ @@ -114,7 +170,12 @@ static void lupb_msg_typecheck(lua_State *L, const upb_msgdef *expected, * is an internal memory management detail. Other wrapper objects refer to this * object from their userdata to keep the arena-owned data alive. * - * The arena contains a table that caches wrapper objects. */ + * The arena userval is a table representing the arena group. Every arena in + * the group points to the same table, and the table references all arenas in + * the group. + */ + +#define LUPB_ARENAGROUP_INDEX 1 typedef struct { upb_arena *arena; @@ -122,41 +183,47 @@ typedef struct { upb_arena *lupb_arena_check(lua_State *L, int narg) { lupb_arena *a = luaL_checkudata(L, narg, LUPB_ARENA); - return a ? a->arena : NULL; + return a->arena; } -int lupb_arena_new(lua_State *L) { - lupb_arena *a = lupb_newuserdata(L, sizeof(lupb_arena), LUPB_ARENA); - - /* TODO(haberman): use Lua alloc func as block allocator? Would need to - * verify that all cases of upb_malloc in msg/table are longjmp-safe. */ +upb_arena *lupb_arena_pushnew(lua_State *L) { + lupb_arena *a = lupb_newuserdata(L, sizeof(lupb_arena), 1, LUPB_ARENA); a->arena = upb_arena_new(); - return 1; + /* Create arena group table and add this arena to it. */ + lua_createtable(L, 0, 1); + lua_pushvalue(L, -2); + lua_rawseti(L, -3, 1); + + /* Set arena group as this object's userval. */ + lua_setiuservalue(L, -2, LUPB_ARENAGROUP_INDEX); + + return a->arena; } -char lupb_arena_cache_key; +void lupb_arena_merge(lua_State *L, int to, int from) { + int i, from_count, to_count; + lua_getiuservalue(L, to, LUPB_ARENAGROUP_INDEX); + lua_getiuservalue(L, from, LUPB_ARENAGROUP_INDEX); -/* Returns the global lupb_arena func that was created in our luaopen(). - * Callers can be guaranteed that it will be alive as long as |L| is. - * TODO(haberman): we shouldn't use a global arena! We should have - * one arena for a parse, or per independently-created message. */ -upb_arena *lupb_arena_get(lua_State *L) { - upb_arena *arena; + if (lua_rawequal(L, -1, -2)) { + /* These arenas are already in the same group. */ + lua_pop(L, 2); + return; + } - lua_pushlightuserdata(L, &lupb_arena_cache_key); - lua_gettable(L, LUA_REGISTRYINDEX); - arena = lua_touserdata(L, -1); - assert(arena); - lua_pop(L, 1); + to_count = lua_rawlen(L, -2); + from_count = lua_rawlen(L, -1); - return arena; -} + /* Add everything in |from|'s arena group. */ + for (i = 1; i <= from_count; i++) { + lua_rawgeti(L, -1, i); + lua_rawseti(L, -3, i + to_count); + } -static void lupb_arena_initsingleton(lua_State *L) { - lua_pushlightuserdata(L, &lupb_arena_cache_key); - lupb_arena_new(L); - lua_settable(L, LUA_REGISTRYINDEX); + /* Make |from| point to |to|'s table. */ + lua_pop(L, 1); + lua_setiuservalue(L, from, LUPB_ARENAGROUP_INDEX); } static int lupb_arena_gc(lua_State *L) { @@ -170,16 +237,36 @@ static const struct luaL_Reg lupb_arena_mm[] = { {NULL, NULL} }; +/* lupb_arenaget() + * + * Returns the arena from the given message, array, or map object. + */ +static upb_arena *lupb_arenaget(lua_State *L, int narg) { + upb_arena *arena; + lua_getiuservalue(L, narg, LUPB_ARENA_INDEX); + arena = lupb_arena_check(L, -1); + lua_pop(L, 1); + return arena; +} /* upb <-> Lua type conversion ************************************************/ -static bool lupb_istypewrapped(upb_fieldtype_t type) { - return type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES || - type == UPB_TYPE_MESSAGE; -} +/* Whether string data should be copied into the containing arena. We can + * avoid a copy if the string data is only needed temporarily (like for a map + * lookup). + */ +typedef enum { + LUPB_COPY, /* Copy string data into the arena. */ + LUPB_REF /* Reference the Lua copy of the string data. */ +} lupb_copy_t; +/** + * lupb_tomsgval() + * + * Converts the given Lua value |narg| to a upb_msgval. + */ static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg, - const upb_msgdef *msgdef) { + int container, lupb_copy_t copy) { upb_msgval ret; switch (type) { case UPB_TYPE_INT32: @@ -208,18 +295,33 @@ static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg, case UPB_TYPE_BYTES: { size_t len; const char *ptr = lupb_checkstring(L, narg, &len); - ret.str_val = upb_strview_make(ptr, len); + switch (copy) { + case LUPB_COPY: { + upb_arena *arena = lupb_arenaget(L, container); + char *data = upb_arena_malloc(arena, len); + memcpy(data, ptr, len); + ret.str_val = upb_strview_make(data, len); + break; + } + case LUPB_REF: + ret.str_val = upb_strview_make(ptr, len); + break; + } break; } case UPB_TYPE_MESSAGE: - assert(msgdef); - ret.msg_val = lupb_msg_checkmsg(L, narg, msgdef); + ret.msg_val = lupb_msg_check(L, narg); + /* Typecheck message. */ + lua_getiuservalue(L, container, LUPB_MSGDEF_INDEX); + lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX); + luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch"); + lua_pop(L, 2); break; } return ret; } -static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, +static void lupb_pushmsgval(lua_State *L, int container, upb_fieldtype_t type, upb_msgval val) { switch (type) { case UPB_TYPE_INT32: @@ -236,17 +338,24 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, lupb_pushuint64(L, val.uint64_val); return; case UPB_TYPE_DOUBLE: - lupb_pushdouble(L, val.double_val); + lua_pushnumber(L, val.double_val); return; case UPB_TYPE_FLOAT: - lupb_pushfloat(L, val.float_val); + lua_pushnumber(L, val.float_val); return; case UPB_TYPE_BOOL: lua_pushboolean(L, val.bool_val); return; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: + lua_pushlstring(L, val.str_val.data, val.str_val.size); + return; case UPB_TYPE_MESSAGE: + assert(container); + if (!lupb_cacheget(L, val.msg_val)) { + lupb_msg_newmsgwrapper(L, container, val); + lupb_cacheset(L, val.msg_val); + } break; /* Shouldn't call this function. */ } LUPB_UNREACHABLE(); @@ -255,78 +364,26 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type, /* lupb_array *****************************************************************/ -/* A strongly typed array. Implemented by wrapping upb_array. - * - * - we only allow integer indices. - * - all entries must have the correct type. - * - we do not allow "holes" in the array; you can only assign to an existing - * index or one past the end (which will grow the array by one). - * - * For string/submessage entries we keep in the userval: - * - * [number index] -> [lupb_string/lupb_msg userdata] - * - * Additionally, for message-typed arrays we keep: - * - * [ARRAY_MSGDEF_INDEX] -> [SymbolTable] (to keep msgdef GC-reachable) - */ - typedef struct { upb_array *arr; upb_fieldtype_t type; } lupb_array; -#define ARRAY_MSGDEF_INDEX 1 - static lupb_array *lupb_array_check(lua_State *L, int narg) { return luaL_checkudata(L, narg, LUPB_ARRAY); } -/** - * lupb_array_typecheck() - * - * Verifies that the lupb_array object at index |narg| can be safely assigned - * to the field |f| of the lupb_msg object at index |msg|. If this is safe, - * returns a upb_msgval representing the array. Otherwise, throws a Lua error. - */ -static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, - const upb_fielddef *f) { - lupb_array *larray = lupb_array_check(L, narg); - upb_msgval val; - - if (larray->type != upb_fielddef_type(f)) { - luaL_error(L, "Array had incorrect type (expected: %d, got: %d)", - (int)upb_fielddef_type(f), (int)larray->type); - } - - if (larray->type == UPB_TYPE_MESSAGE) { - lupb_msgdef_typecheck(L, upb_fielddef_msgsubdef(f), larray->msgdef); - } - - val.array_val = larray->arr; - return val; -} - /** * lupb_array_checkindex() * * Checks the array index at Lua stack index |narg| to verify that it is an * integer between 1 and |max|, inclusively. Also corrects it to be zero-based * for C. - * - * We use "int" because of lua_rawseti/lua_rawgeti -- can re-evaluate if we want - * arrays bigger than 2^31. */ static int lupb_array_checkindex(lua_State *L, int narg, uint32_t max) { uint32_t n = lupb_checkuint32(L, narg); - if (n == 0 || n > max || n > INT_MAX) { - luaL_error(L, "Invalid array index: expected between 1 and %d", (int)max); - } - return n - 1; /* Lua uses 1-based indexing. :( */ -} - -static void lupb_array_push(lua_State *L, upb_array *a, const upb_fielddef *f) { - + luaL_argcheck(L, n != 0 && n <= max, narg, "invalid array index"); + return n - 1; /* Lua uses 1-based indexing. */ } /* lupb_array Public API */ @@ -339,23 +396,24 @@ static void lupb_array_push(lua_State *L, upb_array *a, const upb_fielddef *f) { */ static int lupb_array_new(lua_State *L) { lupb_array *larray; - upb_fieldtype_t type; - int n = 1; - - lupb_arena_new(); /* Userval 1. */ + upb_arena *arena; if (lua_type(L, 1) == LUA_TNUMBER) { - type = lupb_checkfieldtype(L, 1); + upb_fieldtype_t type = lupb_checkfieldtype(L, 1); + larray = lupb_newuserdata(L, sizeof(*larray), 1, LUPB_ARRAY); + larray->type = type; } else { lupb_msgdef_check(L, 1); - type = UPB_TYPE_MESSAGE; - n = 2; - lua_push(L, 1); /* Userval 2. */ + larray = lupb_newuserdata(L, sizeof(*larray), 2, LUPB_ARRAY); + larray->type = UPB_TYPE_MESSAGE; + lua_pushvalue(L, 1); + lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); } - larray = lupb_newuserdata(L, sizeof(*larray), n, LUPB_ARRAY); - larray->type = type; - larray->arr = upb_array_new(lupb_arena_get(L), type); + arena = lupb_arena_pushnew(L); + lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); + + larray->arr = upb_array_new(arena, larray->type); return 1; } @@ -370,20 +428,15 @@ static int lupb_array_new(lua_State *L) { static int lupb_array_newindex(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); size_t size = upb_array_size(larray->arr); - upb_fieldtype_t type = larray->type; uint32_t n = lupb_array_checkindex(L, 2, size + 1); - upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->msgdef); + upb_msgval msgval = lupb_tomsgval(L, larray->type, 3, 1, LUPB_COPY); if (n == size) { - upb_array_append(larray->arr, msgval, lupb_arena_get(L)); + upb_array_append(larray->arr, msgval, lupb_arenaget(L, 1)); } else { upb_array_set(larray->arr, n, msgval); } - if (lupb_istypewrapped(type)) { - lupb_uservalseti(L, 1, n, 3); - } - return 0; /* 1 for chained assignments? */ } @@ -398,14 +451,9 @@ static int lupb_array_index(lua_State *L) { lupb_array *larray = lupb_array_check(L, 1); size_t size = upb_array_size(larray->arr); uint32_t n = lupb_array_checkindex(L, 2, size); - upb_fieldtype_t type = larray->type; + upb_msgval val = upb_array_get(larray->arr, n); - if (lupb_istypewrapped(type)) { - lupb_uservalgeti(L, 1, n); - } else { - upb_msgval val = upb_array_get(larray->arr, n); - lupb_pushmsgval(L, type, val); - } + lupb_pushmsgval(L, 1, larray->type, val); return 1; } @@ -431,19 +479,6 @@ static const struct luaL_Reg lupb_array_mm[] = { /* lupb_map *******************************************************************/ -/* A map object. Implemented by wrapping upb_map. - * - * When the value type is string/bytes/message, the userval consists of: - * - * [Lua number/string] -> [lupb_string/lupb_msg userdata] - * - * Additionally when the map is message, we store: - * - * [MAP_MSGDEF_INDEX] -> MessageDef - * - * For other value types we don't use the userdata. - */ - typedef struct { upb_map *map; upb_fieldtype_t key_type; @@ -452,52 +487,10 @@ typedef struct { #define MAP_MSGDEF_INDEX 1 -/* lupb_map internal functions */ - static lupb_map *lupb_map_check(lua_State *L, int narg) { return luaL_checkudata(L, narg, LUPB_ARRAY); } -/** - * lupb_map_typecheck() - * - * Checks that the lupb_map at index |narg| can be safely assigned to the - * field |f| of the message at index |msg|. If so, returns a upb_msgval for - * this map. Otherwise, raises a Lua error. - */ -static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, - const upb_fielddef *f) { - lupb_map *lmap = lupb_map_check(L, narg); - const upb_msgdef *entry = upb_fielddef_msgsubdef(f); - const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); - const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); - upb_msgval val; - - assert(entry && key_field && value_field); - - if (lmap->key_type != upb_fielddef_type(key_field)) { - luaL_error(L, "Map had incorrect field type (expected: %s, got: %s)", - upb_fielddef_type(key_field), lmap->key_type); - } - - if (lmap->value_type != upb_fielddef_type(value_field)) { - luaL_error(L, "Map had incorrect value type (expected: %s, got: %s)", - upb_fielddef_type(value_field), lmap->value_type); - } - - if (lmap->value_type == UPB_TYPE_MESSAGE) { - lupb_uservalgeti(L, narg, MAP_MSGDEF_INDEX); - lupb_wrapper_pushwrapper(L - - lupb_msgclass_typecheck( - L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)), - lmap->value_lmsgclass); - } - - val.map_val = lmap->map; - return val; -} - /* lupb_map Public API */ /** @@ -508,26 +501,25 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, * new_map = upb.Map(key_type, value_msgdef) */ static int lupb_map_new(lua_State *L) { + upb_arena *arena; lupb_map *lmap; - upb_fieldtype_t key_type = lupb_checkfieldtype(L, 1); - upb_fieldtype_t value_type; if (lua_type(L, 2) == LUA_TNUMBER) { - value_type = lupb_checkfieldtype(L, 2); + lmap = lupb_newuserdata(L, sizeof(*lmap), 1, LUPB_MAP); + lmap->value_type = lupb_checkfieldtype(L, 2); } else { - value_type = UPB_TYPE_MESSAGE; + lupb_msgdef_check(L, 2); + lmap = lupb_newuserdata(L, sizeof(*lmap), 2, LUPB_MAP); + lmap->value_type = UPB_TYPE_MESSAGE; + lua_pushvalue(L, 2); + lua_setiuservalue(L, -2, MAP_MSGDEF_INDEX); } - lmap = lupb_newuserdata(L, sizeof(*lmap), LUPB_MAP); + arena = lupb_arena_pushnew(L); + lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); - if (value_type == UPB_TYPE_MESSAGE) { - value_lmsgclass = lupb_msgclass_check(L, 2); - lupb_uservalseti(L, -1, MAP_MSGDEF_INDEX, 2); /* GC-root lmsgclass. */ - } - - lmap->key_type = key_type; - lmap->value_type = value_type; - lmap->map = upb_map_new(lupb_arena_get(L), key_type, value_type); + lmap->key_type = lupb_checkfieldtype(L, 1); + lmap->map = upb_map_new(arena, lmap->key_type, lmap->value_type); return 1; } @@ -540,28 +532,13 @@ static int lupb_map_new(lua_State *L) { */ static int lupb_map_index(lua_State *L) { lupb_map *lmap = lupb_map_check(L, 1); - upb_map *map = lmap->map; - upb_fieldtype_t valtype = lmap->value_type; - /* We don't always use "key", but this call checks the key type. */ - upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, NULL); - - if (lupb_istypewrapped(valtype)) { - /* Userval contains the full map, lookup there by key. */ - lupb_getuservalue(L, 1); - lua_pushvalue(L, 2); - lua_rawget(L, -2); + upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF); + upb_msgval val; - if (lua_isnil(L, -1)) { - /* TODO: lazy read from upb_map */ - } + if (upb_map_get(lmap->map, key, &val)) { + lupb_pushmsgval(L, 1, lmap->value_type, val); } else { - /* Lookup in upb_map. */ - upb_msgval val; - if (upb_map_get(map, key, &val)) { - lupb_pushmsgval(L, lmap->value_type, val); - } else { - lua_pushnil(L); - } + lua_pushnil(L); } return 1; @@ -589,78 +566,51 @@ static int lupb_map_len(lua_State *L) { static int lupb_map_newindex(lua_State *L) { lupb_map *lmap = lupb_map_check(L, 1); upb_map *map = lmap->map; - upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, NULL); + upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF); if (lua_isnil(L, 3)) { - /* Delete from map. */ - upb_map_delete(map, key); - - if (lupb_istypewrapped(lmap->value_type)) { - /* Delete in userval. */ - lupb_getuservalue(L, 1); - lua_pushvalue(L, 2); - lua_pushnil(L); - lua_rawset(L, -3); - lua_pop(L, 1); - } + upb_map_delete(map, key, lupb_arenaget(L, 1)); } else { - /* Set in map. */ - upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, lmap->msgdef); - - upb_map_set(map, key, val, lupb_arena_get(L)); - - if (lupb_istypewrapped(lmap->value_type)) { - /* Set in userval. */ - lupb_getuservalue(L, 1); - lua_pushvalue(L, 2); - lua_pushvalue(L, 3); - lua_rawset(L, -3); - lua_pop(L, 1); - } + upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, 1, LUPB_COPY); + upb_map_set(map, key, val, lupb_arenaget(L, 1)); } return 0; } -/* upb_mapiter [[[ */ - static int lupb_mapiter_next(lua_State *L) { + int map = lua_upvalueindex(2); upb_mapiter *i = lua_touserdata(L, lua_upvalueindex(1)); - lupb_map *lmap = lupb_map_check(L, 1); + lupb_map *lmap = lupb_map_check(L, map); if (upb_mapiter_done(i)) { return 0; } - lupb_pushmsgval(L, lmap->key_type, upb_mapiter_key(i)); - lupb_pushmsgval(L, lmap->value_type, upb_mapiter_value(i)); + lupb_pushmsgval(L, map, lmap->key_type, upb_mapiter_key(i)); + lupb_pushmsgval(L, map, lmap->value_type, upb_mapiter_value(i)); upb_mapiter_next(i); return 2; } +/** + * lupb_map_pairs() + * + * Handles: + * pairs(map) + */ static int lupb_map_pairs(lua_State *L) { lupb_map *lmap = lupb_map_check(L, 1); + upb_mapiter *i = lua_newuserdata(L, upb_mapiter_sizeof()); - if (lupb_istypewrapped(lmap->key_type) || - lupb_istypewrapped(lmap->value_type)) { - /* Complex key or value type. - * Sync upb_map to userval if necessary, then iterate over userval. */ - - /* TODO: Lua tables don't know how many entries they have, gah!. */ - return 1; - } else { - /* Simple key and value type, iterate over the upb_map directly. */ - upb_mapiter *i = lua_newuserdata(L, upb_mapiter_sizeof()); - - upb_mapiter_begin(i, lmap->map); - lua_pushvalue(L, 1); + upb_mapiter_begin(i, lmap->map); + lua_pushvalue(L, 1); - /* Upvalues are [upb_mapiter, lupb_map]. */ - lua_pushcclosure(L, &lupb_mapiter_next, 2); + /* Upvalues are [upb_mapiter, lupb_map]. */ + lua_pushcclosure(L, &lupb_mapiter_next, 2); - return 1; - } + return 1; } /* upb_mapiter ]]] */ @@ -676,68 +626,136 @@ static const struct luaL_Reg lupb_map_mm[] = { /* lupb_msg *******************************************************************/ -/* A message object. Implemented by wrapping upb_msg. - * - * Our userval contains: - * - * - [MSG_MSGDEF_INDEX] -> our message class - * - * Fields with scalar number/bool types don't go in the userval. - */ - -#define MSG_MSGDEF_INDEX 1 - -int lupb_fieldindex(const upb_fielddef *f) { - return upb_fielddef_index(f) + 1; /* 1-based Lua arrays. */ -} - typedef struct { upb_msg *msg; } lupb_msg; /* lupb_msg helpers */ -static bool in_userval(const upb_fielddef *f) { - return lupb_istypewrapped(upb_fielddef_type(f)) || upb_fielddef_isseq(f) || - upb_fielddef_ismap(f); -} - -upb_msg *lupb_msg_check(lua_State *L, int narg) { +static upb_msg *lupb_msg_check(lua_State *L, int narg) { lupb_msg *msg = luaL_checkudata(L, narg, LUPB_MSG); - if (!msg->msg) luaL_error(L, "called into dead msg"); return msg->msg; } -const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg, - const upb_msgdef *msgdef) { - lupb_msg_check(L, narg); - lupb_uservalgeti - lupb_msgclass_typecheck(L, lmsgclass, lmsg->lmsgclass); - return lmsg->msg; +static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg, + int field) { + size_t len; + const char *fieldname = luaL_checklstring(L, field, &len); + const upb_msgdef *m; + const upb_fielddef *f; + + lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX); + m = lupb_msgdef_check(L, -1); + f = upb_msgdef_ntof(m, fieldname, len); + luaL_argcheck(L, f != NULL, field, "no such field"); + lua_pop(L, 1); + + return f; } -upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg, - const upb_msglayout **layout) { - lupb_msg *lmsg = lupb_msg_check(L, narg); - *layout = lmsg->lmsgclass->layout; - return lmsg->msg; +/** + * lupb_msg_newmsgwrapper() + * + * Creates a new wrapper for a message, copying the arena and msgdef references + * from |narg| (which should be an array or map). + */ +static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val) { + lupb_msg *lmsg = lupb_newuserdata(L, sizeof(*lmsg), 2, LUPB_MSG); + lmsg->msg = (upb_msg*)val.msg_val; /* XXX: cast isn't great. */ + + /* Copy both arena and msgdef into the wrapper. */ + lua_getiuservalue(L, narg, LUPB_ARENA_INDEX); + lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); + lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX); + lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); } -static const upb_fielddef *lupb_msg_checkfield(lua_State *L, - const lupb_msg *msg, - int fieldarg) { - size_t len; - const char *fieldname = luaL_checklstring(L, fieldarg, &len); - const upb_msgdef *msgdef = msg->lmsgclass->msgdef; - const upb_fielddef *f = upb_msgdef_ntof(msgdef, fieldname, len); - - if (!f) { - const char *msg = lua_pushfstring(L, "no such field: %s", fieldname); - luaL_argerror(L, fieldarg, msg); - return NULL; /* Never reached. */ +/** + * lupb_msg_lazycreate() + * + * For maps and repeated fields, we lazily create the map/array when the field + * is read, because we never want to return nil for these fields. Maps and + * repeated fields have no notion of presence, so we always want them to appear + * present. Messages on the other hand have presence so we return nil rather + * than lazily create them. + */ +static bool lupb_msg_lazycreate(lua_State *L, int narg, const upb_fielddef *f, + upb_msgval* val) { + if (val->msg_val == NULL && !upb_fielddef_isseq(f)) { + upb_msg *msg = lupb_msg_check(L, narg); + upb_arena *arena = lupb_arenaget(L, narg); + upb_mutmsgval mutval = upb_msg_mutable(msg, f, arena); + memcpy(val, &mutval, sizeof(void*)); + return true; + } else { + return false; } +} - return f; +/** + * lupb_msg_newud() + * + * Creates the Lua userdata for a new wrapper object, adding a reference to + * the msgdef if necessary. + */ +static void *lupb_msg_newud(lua_State *L, int narg, size_t size, + const char *type, const upb_fielddef *f) { + if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) { + /* Wrapper needs a reference to the msgdef. */ + void* ud = lupb_newuserdata(L, size, 2, type); + lupb_msgdef_pushmsgdef(L, narg, f); + lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); + return ud; + } else { + return lupb_newuserdata(L, size, 1, type); + } +} + +/** + * lupb_msg_newwrapper() + * + * Creates a new Lua wrapper object to wrap the given array, map, or message. + */ +static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f, + upb_msgval val) { + if (upb_fielddef_ismap(f)) { + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key_f = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); + const upb_fielddef *val_f = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); + lupb_map *lmap = lupb_msg_newud(L, narg, sizeof(*lmap), LUPB_MAP, val_f); + lmap->key_type = upb_fielddef_type(key_f); + lmap->value_type = upb_fielddef_type(val_f); + lmap->map = (upb_map*)val.map_val; /* XXX: cast isn't great. */ + } else if (upb_fielddef_isseq(f)) { + lupb_array *larr = lupb_msg_newud(L, narg, sizeof(*larr), LUPB_ARRAY, f); + larr->type = upb_fielddef_type(f); + larr->arr = (upb_array*)val.array_val; /* XXX: cast isn't great. */ + } else { + lupb_msg *lmsg = lupb_msg_newud(L, narg, sizeof(*lmsg), LUPB_MSG, f); + lmsg->msg = (upb_msg*)val.msg_val; /* XXX: cast isn't great. */ + } + + /* Copy arena ref to new wrapper. This may be a different arena than the + * underlying data was originally constructed from, but if so both arenas + * must be in the same group. */ + lua_getiuservalue(L, narg, LUPB_ARENA_INDEX); + lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); +} + +/** + * lupb_msg_typechecksubmsg() + * + * Typechecks the given array, map, or msg against this upb_fielddef. + */ +static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg, + const upb_fielddef *f) { + /* Typecheck this map's msgdef against this message field. */ + lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX); + lua_getiuservalue(L, msgarg, LUPB_MSGDEF_INDEX); + lupb_msgdef_pushmsgdef(L, -1, f); + lua_replace(L, -2); /* replace msg msgdef, leaving only map and field. */ + luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch"); + lua_pop(L, 2); } /* lupb_msg Public API */ @@ -748,14 +766,16 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, * Handles: * new_msg = MessageClass() */ -static int lupb_msg_pushnew(lua_State *L, int narg) { - const lupb_msgclass *lmsgclass = lupb_msgclass_check(L, narg); - lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), LUPB_MSG); +int lupb_msg_pushnew(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG); + upb_arena *arena = lupb_arena_pushnew(L); - lmsg->lmsgclass = lmsgclass; - lmsg->msg = upb_msg_new(lmsgclass->layout, lupb_arena_get(L)); + lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); + lua_pushvalue(L, 1); + lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); - lupb_uservalseti(L, -1, LUPB_MSG_MSGCLASSINDEX, narg); + lmsg->msg = upb_msg_new(m, arena); return 1; } @@ -770,30 +790,18 @@ static int lupb_msg_pushnew(lua_State *L, int narg) { */ static int lupb_msg_index(lua_State *L) { upb_msg *msg = lupb_msg_check(L, 1); - const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); - - if (in_userval(f)) { - lupb_uservalgeti(L, 1, lupb_fieldindex(f)); - - if (lua_isnil(L, -1)) { - /* Check if we need to lazily create wrapper. */ - if (upb_fielddef_isseq(f)) { - /* TODO(haberman) */ - } else if (upb_fielddef_issubmsg(f)) { - /* TODO(haberman) */ - } else { - assert(upb_fielddef_isstring(f)); - if (upb_msg_has(msg, f)) { - upb_msgval val = upb_msg_get(msg, f); - lua_pop(L, 1); - lua_pushlstring(L, val.str_val.data, val.str_val.size); - lupb_uservalseti(L, 1, lupb_fieldindex(f), -1); - } - } + const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2); + upb_msgval val = upb_msg_get(msg, f); + + if (upb_fielddef_isseq(f) || upb_fielddef_issubmsg(f)) { + /* Wrapped type; get or create wrapper. */ + if (lupb_msg_lazycreate(L, 1, f, &val) || !lupb_cacheget(L, val.msg_val)) { + lupb_msg_newwrapper(L, 1, f, val); + lupb_cacheset(L, val.msg_val); } } else { - upb_msgval val = upb_msg_get(msg, f); - lupb_pushmsgval(L, upb_fielddef_type(f), val); + /* Value type, just push value and return .*/ + lupb_pushmsgval(L, 0, upb_fielddef_type(f), val); } return 1; @@ -809,32 +817,43 @@ static int lupb_msg_index(lua_State *L) { */ static int lupb_msg_newindex(lua_State *L) { upb_msg *msg = lupb_msg_check(L, 1); - const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); - upb_fieldtype_t type = upb_fielddef_type(f); - upb_arena *arena = lupb_arena_get(L); + const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2); upb_msgval msgval; - /* Typecheck and get msgval. */ - - if (upb_fielddef_isseq(f)) { - msgval = lupb_array_typecheck(L, 3, 1, f); - } else if (upb_fielddef_ismap(f)) { - msgval = lupb_map_typecheck(L, 3, 1, f); + if (upb_fielddef_ismap(f)) { + lupb_map *lmap = lupb_map_check(L, 3); + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key_f = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); + const upb_fielddef *val_f = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); + upb_fieldtype_t key_type = upb_fielddef_type(key_f); + upb_fieldtype_t value_type = upb_fielddef_type(val_f); + luaL_argcheck(L, lmap->key_type == key_type, 3, "key type mismatch"); + luaL_argcheck(L, lmap->value_type == value_type, 3, "value type mismatch"); + if (value_type == UPB_TYPE_MESSAGE) { + lupb_msg_typechecksubmsg(L, 3, 1, val_f); + } + msgval.map_val = lmap->map; + } else if (upb_fielddef_isseq(f)) { + lupb_array *larr = lupb_array_check(L, 3); + upb_fieldtype_t type = upb_fielddef_type(f); + luaL_argcheck(L, larr->type == type, 3, "array type mismatch"); + if (type == UPB_TYPE_MESSAGE) { + lupb_msg_typechecksubmsg(L, 3, 1, f); + } + msgval.array_val = larr->arr; + } else if (upb_fielddef_issubmsg(f)) { + upb_msg *msg = lupb_msg_check(L, 3); + lupb_msg_typechecksubmsg(L, 3, 1, f); + msgval.msg_val = msg; } else { - const upb_msgdef *msgdef = - type == UPB_TYPE_MESSAGE ? upb_fielddef_msgsubdef(f) : NULL; - msgval = lupb_tomsgval(L, type, 3, msgdef); + msgval = lupb_tomsgval(L, upb_fielddef_type(f), 3, 1, LUPB_COPY); } - /* Set in upb_msg and userval (if necessary). */ + upb_msg_set(msg, f, msgval, lupb_arenaget(L, 1)); - upb_msg_set(msg, f, msgval, arena); - - if (in_userval(f)) { - lupb_uservalseti(L, 1, lupb_fieldindex(f), 3); - } - - return 0; /* 1 for chained assignments? */ + /* Return the new value for chained assignments. */ + lua_pushvalue(L, 3); + return 1; } static const struct luaL_Reg lupb_msg_mm[] = { @@ -846,13 +865,14 @@ static const struct luaL_Reg lupb_msg_mm[] = { /* lupb_msg toplevel **********************************************************/ +#if 0 static int lupb_decode(lua_State *L) { size_t len; const upb_msglayout *layout; - upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout); + upb_msg *msg = lupb_msg_checkmsg(L, 1); const char *pb = lua_tolstring(L, 2, &len); - upb_decode(pb, len, msg, layout, lupb_arena_get(L)); + upb_decode(pb, len, msg, layout, lupb_arenaget(L, 1)); /* TODO(haberman): check for error. */ return 0; @@ -860,7 +880,7 @@ static int lupb_decode(lua_State *L) { static int lupb_encode(lua_State *L) { const upb_msglayout *layout; - const upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout); + const upb_msg *msg = lupb_msg_checkmsg(L, 1); upb_arena *arena = upb_arena_new(); size_t size; char *result; @@ -874,25 +894,25 @@ static int lupb_encode(lua_State *L) { return 1; } +#endif static const struct luaL_Reg lupb_msg_toplevel_m[] = { {"Array", lupb_array_new}, {"Map", lupb_map_new}, - {"MessageFactory", lupb_msgfactory_new}, +#if 0 {"decode", lupb_decode}, {"encode", lupb_encode}, +#endif {NULL, NULL} }; void lupb_msg_registertypes(lua_State *L) { lupb_setfuncs(L, lupb_msg_toplevel_m); - lupb_register_type(L, LUPB_ARENA, NULL, lupb_arena_mm); - lupb_register_type(L, LUPB_MSGCLASS, NULL, lupb_msgclass_mm); - lupb_register_type(L, LUPB_MSGFACTORY, lupb_msgfactory_m, lupb_msgfactory_mm); - lupb_register_type(L, LUPB_ARRAY, NULL, lupb_array_mm); - lupb_register_type(L, LUPB_MAP, NULL, lupb_map_mm); - lupb_register_type(L, LUPB_MSG, NULL, lupb_msg_mm); + lupb_register_type(L, LUPB_ARENA, NULL, lupb_arena_mm); + lupb_register_type(L, LUPB_ARRAY, NULL, lupb_array_mm); + lupb_register_type(L, LUPB_MAP, NULL, lupb_map_mm); + lupb_register_type(L, LUPB_MSG, NULL, lupb_msg_mm); - lupb_arena_initsingleton(L); + lupb_cacheinit(L); } diff --git a/upb/bindings/lua/upb.c b/upb/bindings/lua/upb.c index d4dc2b06e7..3630ae2ef3 100644 --- a/upb/bindings/lua/upb.c +++ b/upb/bindings/lua/upb.c @@ -32,43 +32,10 @@ /* Lua compatibility code *****************************************************/ -/* Lua 5.1 and Lua 5.2 have slightly incompatible APIs. A little bit of - * compatibility code can help hide the difference. Not too many people still - * use Lua 5.1 but LuaJIT uses the Lua 5.1 API in some ways. */ - -#if LUA_VERSION_NUM == 501 - -/* taken from lua 5.2's source. */ -void *luaL_testudata(lua_State *L, int ud, const char *tname) { - void *p = lua_touserdata(L, ud); - if (p != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - luaL_getmetatable(L, tname); /* get correct metatable */ - if (!lua_rawequal(L, -1, -2)) /* not the same? */ - p = NULL; /* value is a userdata with wrong metatable */ - lua_pop(L, 2); /* remove both metatables */ - return p; - } - } - return NULL; /* value is not a userdata with a metatable */ -} - -#elif LUA_VERSION_NUM == 502 - -int luaL_typerror(lua_State *L, int narg, const char *tname) { - const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, luaL_typename(L, narg)); - return luaL_argerror(L, narg, msg); -} - -#else -#error Only Lua 5.1 and 5.2 are supported -#endif - /* Shims for upcoming Lua 5.3 functionality. */ -bool lua_isinteger(lua_State *L, int argn) { - UPB_UNUSED(L); - UPB_UNUSED(argn); +static bool lua_isinteger(lua_State *L, int argn) { + LUPB_UNUSED(L); + LUPB_UNUSED(argn); return false; } @@ -83,19 +50,63 @@ void lupb_checkstatus(lua_State *L, upb_status *s) { } /* Pushes a new userdata with the given metatable. */ -static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) { +void *lupb_newuserdata(lua_State *L, size_t size, int n, const char *type) { +#if LUA_VERSION_NUM >= 504 + void *ret = lua_newuserdatauv(L, size, n); +#else void *ret = lua_newuserdata(L, size); + lua_createtable(L, 0, n); + lua_setuservalue(L, -2); +#endif /* Set metatable. */ luaL_getmetatable(L, type); assert(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */ lua_setmetatable(L, -2); - /* We don't set a uservalue here -- we lazily create it later if necessary. */ - return ret; } +#if LUA_VERSION_NUM < 504 +int lua_setiuservalue(lua_State *L, int index, int n) { + lua_getuservalue(L, index); + lua_insert(L, -2); + lua_rawseti(L, -2, n); + lua_pop(L, 1); + return 1; +} + +int lua_getiuservalue(lua_State *L, int index, int n) { + lua_getuservalue(L, index); + lua_rawgeti(L, -1, n); + lua_replace(L, -2); + return 1; +} +#endif + +void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, + const luaL_Reg *mm) { + luaL_newmetatable(L, name); + + if (mm) { + lupb_setfuncs(L, mm); + } + + if (m) { + /* Methods go in the mt's __index method. This implies that you can' + * implement __index and also have methods. */ + lua_getfield(L, -1, "__index"); + lupb_assert(L, lua_isnil(L, -1)); + lua_pop(L, 1); + + lua_createtable(L, 0, 0); + lupb_setfuncs(L, m); + lua_setfield(L, -2, "__index"); + } + + lua_pop(L, 1); /* The mt. */ +} + /* Scalar type mapping ********************************************************/ /* Functions that convert scalar/primitive values (numbers, strings, bool) @@ -181,32 +192,10 @@ void lupb_pushfloat(lua_State *L, float d) { lua_pushnumber(L, d); } +/* Library entry point ********************************************************/ -void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, - const luaL_Reg *mm) { - luaL_newmetatable(L, name); - - if (mm) { - lupb_setfuncs(L, mm); - } - - if (m) { - /* Methods go in the mt's __index method. This implies that you can' - * implement __index and also have methods. */ - lua_getfield(L, -1, "__index"); - lupb_assert(L, lua_isnil(L, -1)); - lua_pop(L, 1); - - lua_createtable(L, 0, 0); - lupb_setfuncs(L, m); - lua_setfield(L, -2, "__index"); - } - - lua_pop(L, 1); /* The mt. */ -} - -int luaopen_upb_c(lua_State *L) { -#if LUA_VERSION == 501 +int luaopen_lupb(lua_State *L) { +#if LUA_VERSION_NUM == 501 const struct luaL_Reg funcs[] = {{NULL, NULL}}; luaL_register(L, "upb_c", funcs); #else diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h index 02b0c7adba..6626e9813b 100644 --- a/upb/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h @@ -14,19 +14,12 @@ * This is some shim code to paper over the differences. */ #if LUA_VERSION_NUM == 501 - #define lua_rawlen lua_objlen - -void *luaL_testudata(lua_State *L, int ud, const char *tname); - +#define lua_setuservalue(L, idx) lua_setfenv(L, idx) +#define lua_getuservalue(L, idx) lua_getfenv(L, idx) #define lupb_setfuncs(L, l) luaL_register(L, NULL, l) - #elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 504 - -int luaL_typerror(lua_State *L, int narg, const char *tname); - #define lupb_setfuncs(L, l) luaL_setfuncs(L, l, 0) - #else #error Only Lua 5.1-5.4 are supported #endif @@ -38,6 +31,7 @@ void *lupb_newuserdata(lua_State *L, size_t size, int n, const char *type); #if LUA_VERSION_NUM < 504 /* Polyfills for this Lua 5.4 function. Pushes userval |n| for the userdata at * |index|. */ +int lua_setiuservalue(lua_State *L, int index, int n); int lua_getiuservalue(lua_State *L, int index, int n); #endif @@ -48,6 +42,8 @@ void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, /* Checks the given upb_status and throws a Lua error if it is not ok. */ void lupb_checkstatus(lua_State *L, upb_status *s); +int luaopen_lupb(lua_State *L); + /* C <-> Lua value conversions. ***********************************************/ /* Custom check/push functions. Unlike the Lua equivalents, they are pinned to @@ -67,31 +63,21 @@ void lupb_pushint64(lua_State *L, int64_t val); void lupb_pushint32(lua_State *L, int32_t val); void lupb_pushuint64(lua_State *L, uint64_t val); void lupb_pushuint32(lua_State *L, uint32_t val); -void lupb_pushdouble(lua_State *L, double val); -void lupb_pushfloat(lua_State *L, float val); - /** From def.c. ***************************************************************/ -upb_fieldtype_t lupb_checkfieldtype(lua_State *L, int narg); - const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg); const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg); upb_symtab *lupb_symtab_check(lua_State *L, int narg); +void lupb_msgdef_pushmsgdef(lua_State *L, int narg, const upb_fielddef *f); void lupb_def_registertypes(lua_State *L); - /** From msg.c. ***************************************************************/ -upb_arena *lupb_arena_check(lua_State *L, int narg); -int lupb_arena_new(lua_State *L); -upb_arena *lupb_arena_get(lua_State *L); -const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg, - const upb_msgdef *msgdef); -upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg, - const upb_msglayout **layout); +int lupb_msg_pushnew(lua_State *L); +upb_arena *lupb_arena_pushnew(lua_State *L); void lupb_msg_registertypes(lua_State *L); @@ -99,6 +85,8 @@ void lupb_msg_registertypes(lua_State *L); if (!(predicate)) \ luaL_error(L, "internal error: %s, %s:%d ", #predicate, __FILE__, __LINE__); +#define LUPB_UNUSED(var) (void)var + #if defined(__GNUC__) || defined(__clang__) #define LUPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) #else diff --git a/upb/bindings/lua/upb.lua b/upb/bindings/lua/upb.lua deleted file mode 100644 index 728852e997..0000000000 --- a/upb/bindings/lua/upb.lua +++ /dev/null @@ -1,172 +0,0 @@ - --- Before calling require on "upb_c", we need to load the same library --- as RTLD_GLOBAL, for the benefit of other C extensions that depend on --- C functions in the core. --- --- This has to happen *before* the require call, because if the module --- is loaded RTLD_LOCAL first, a subsequent load as RTLD_GLOBAL won't --- have the proper effect, at least on some platforms. -local so = package.searchpath and package.searchpath("upb_c", package.cpath) -if so then - package.loadlib(so, "*") -end - -local upb = require("upb_c") - --- A convenience function for building/linking/freezing defs --- while maintaining their original order. --- --- Sample usage: --- local m1, m2 = upb.build_defs{ --- upb.MessageDef{full_name = "M1", fields = { --- upb.FieldDef{ --- name = "m2", --- number = 1, --- type = upb.TYPE_MESSAGE, --- subdef_name = ".M2" --- }, --- } --- }, --- upb.MessageDef{full_name = "M2"} --- } -upb.build_defs = function(defs) - upb.SymbolTable(defs) - -- Lua 5.2 puts unpack in the table library. - return (unpack or table.unpack)(defs) -end - -local ipairs_iter = function(array, last_index) - local next_index = last_index + 1 - if next_index > #array then - return nil - end - return next_index, array[next_index] -end - --- For iterating over the indexes and values of a upb.Array. --- --- for i, val in upb.ipairs(array) do --- -- ... --- end -upb.ipairs = function(array) - return ipairs_iter, array, 0 -end - -local set_named = function(obj, init) - for k, v in pairs(init) do - local func = obj["set_" .. k] - if not func then - error("Cannot set member: " .. k) - end - func(obj, v) - end -end - --- Capture references to the functions we're wrapping. -local RealFieldDef = upb.FieldDef -local RealEnumDef = upb.EnumDef -local RealMessageDef = upb.MessageDef -local RealOneofDef = upb.OneofDef -local RealSymbolTable = upb.SymbolTable - --- FieldDef constructor; a wrapper around the real constructor that can --- set initial properties. --- --- User can specify initialization values like so: --- upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, --- type=upb.TYPE_INT32, default_value=12, type_name="Foo"} -upb.FieldDef = function(init) - local f = RealFieldDef() - - if init then - -- Other members are often dependent on type, so set that first. - if init.type then - f:set_type(init.type) - init.type = nil - end - - set_named(f, init) - end - - return f -end - - --- MessageDef constructor; a wrapper around the real constructor that can --- set initial properties. --- --- User can specify initialization values like so: --- upb.MessageDef{full_name="MyMessage", extstart=8000, fields={...}} -upb.MessageDef = function(init) - local m = RealMessageDef() - - if init then - for _, f in pairs(init.fields or {}) do - m:add(f) - end - init.fields = nil - - set_named(m, init) - end - - return m -end - --- EnumDef constructor; a wrapper around the real constructor that can --- set initial properties. --- --- User can specify initialization values like so: --- upb.EnumDef{full_name="MyEnum", --- values={ --- {"FOO_VALUE_1", 1}, --- {"FOO_VALUE_2", 2} --- } --- } -upb.EnumDef = function(init) - local e = RealEnumDef() - - if init then - for _, val in pairs(init.values or {}) do - e:add(val[1], val[2]) - end - init.values = nil - - set_named(e, init) - end - - return e -end - --- OneofDef constructor; a wrapper around the real constructor that can --- set initial properties. --- --- User can specify initialization values like so: --- upb.OneofDef{name="foo", fields={...}} -upb.OneofDef = function(init) - local o = RealOneofDef() - - if init then - for _, val in pairs(init.fields or {}) do - o:add(val) - end - init.fields = nil - - set_named(o, init) - end - - return o -end - --- SymbolTable constructor; a wrapper around the real constructor that can --- add an initial set of defs. -upb.SymbolTable = function(defs) - local s = RealSymbolTable() - - if defs then - s:add(defs) - end - - return s -end - -return upb diff --git a/upb/decode.c b/upb/decode.c index 1565a316ce..0185be4de4 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -216,7 +216,7 @@ static upb_msg *upb_getorcreatemsg(upb_decframe *frame, UPB_ASSERT(field->label != UPB_LABEL_REPEATED); if (!*submsg) { - *submsg = upb_msg_new(*subm, frame->state->arena); + *submsg = _upb_msg_new(*subm, frame->state->arena); CHK(*submsg); } @@ -230,7 +230,7 @@ static upb_msg *upb_addmsg(upb_decframe *frame, upb_array *arr = upb_getorcreatearr(frame, field); *subm = frame->layout->submsgs[field->submsg_index]; - submsg = upb_msg_new(*subm, frame->state->arena); + submsg = _upb_msg_new(*subm, frame->state->arena); CHK(submsg); upb_array_add(arr, 1, sizeof(submsg), &submsg, frame->state->arena); diff --git a/upb/def.c b/upb/def.c index 98aead6b67..158becb7cb 100644 --- a/upb/def.c +++ b/upb/def.c @@ -52,6 +52,7 @@ struct upb_fielddef { }; struct upb_msgdef { + const upb_msglayout *layout; const upb_filedef *file; const char *full_name; uint32_t selector_count; @@ -379,7 +380,7 @@ const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { } const char *upb_enum_iter_name(upb_enum_iter *iter) { - return upb_strtable_iter_key(iter); + return upb_strtable_iter_key(iter).data; } int32_t upb_enum_iter_number(upb_enum_iter *iter) { @@ -1574,10 +1575,9 @@ static bool upb_symtab_addtotabs(upb_symtab *s, symtab_addctx *ctx, upb_strtable_begin(&iter, ctx->addtab); for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { - const char *key = upb_strtable_iter_key(&iter); - size_t keylen = upb_strtable_iter_keylength(&iter); + upb_strview key = upb_strtable_iter_key(&iter); upb_value value = upb_strtable_iter_value(&iter); - CHK_OOM(upb_strtable_insert3(&s->syms, key, keylen, value, alloc)); + CHK_OOM(upb_strtable_insert3(&s->syms, key.data, key.size, value, alloc)); } return true; diff --git a/upb/msg.c b/upb/msg.c index 0a70847a12..ccdf1a4863 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -26,7 +26,7 @@ typedef struct { upb_msg_internal base; } upb_msg_internal_withext; -char _upb_fieldtype_to_sizelg2[12] = { +static char _upb_fieldtype_to_sizelg2[12] = { 0, 0, /* UPB_TYPE_BOOL */ 2, /* UPB_TYPE_FLOAT */ @@ -41,6 +41,22 @@ char _upb_fieldtype_to_sizelg2[12] = { UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */ }; +/* Strings/bytes are special-cased in maps. */ +static char _upb_fieldtype_to_mapsizelg2[12] = { + 0, + 0, /* UPB_TYPE_BOOL */ + 2, /* UPB_TYPE_FLOAT */ + 2, /* UPB_TYPE_INT32 */ + 2, /* UPB_TYPE_UINT32 */ + 2, /* UPB_TYPE_ENUM */ + UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */ + 3, /* UPB_TYPE_DOUBLE */ + 3, /* UPB_TYPE_INT64 */ + 3, /* UPB_TYPE_UINT64 */ + UPB_MAPTYPE_STRING, /* UPB_TYPE_STRING */ + UPB_MAPTYPE_STRING, /* UPB_TYPE_BYTES */ +}; + static uintptr_t tag_arrptr(void* ptr, int elem_size_lg2) { UPB_ASSERT(elem_size_lg2 <= 4); return (uintptr_t)ptr | elem_size_lg2; @@ -68,7 +84,7 @@ static upb_msg_internal_withext *upb_msg_getinternalwithext( return VOIDPTR_AT(msg, -sizeof(upb_msg_internal_withext)); } -upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { +upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a) { upb_alloc *alloc = upb_arena_alloc(a); void *mem = upb_malloc(alloc, upb_msg_sizeof(l)); upb_msg_internal *in; @@ -182,8 +198,8 @@ upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, } upb_strtable_init(&map->table, UPB_CTYPE_INT32); - map->key_type = key_type; - map->value_type = value_type; + map->key_size_lg2 = _upb_fieldtype_to_mapsizelg2[key_type]; + map->val_size_lg2 = _upb_fieldtype_to_mapsizelg2[value_type]; return map; } diff --git a/upb/msg.h b/upb/msg.h index a7b595b9e5..717d05d10b 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -55,7 +55,7 @@ typedef struct upb_msglayout { extern char _upb_fieldtype_to_size[12]; /* Creates a new messages with the given layout on the given arena. */ -upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); +upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a); /* Adds unknown data (serialized protobuf data) to the given message. The data * is copied into the message instance. */ @@ -100,8 +100,8 @@ bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, * integer-specific maps for integer-keyed maps.*/ typedef struct { /* We should pack these better and move them into table to avoid padding. */ - upb_fieldtype_t key_type; - upb_fieldtype_t value_type; + char key_size_lg2; + char val_size_lg2; upb_strtable table; } upb_map; diff --git a/upb/port_def.inc b/upb/port_def.inc index a8967b3679..138c7a0c4f 100644 --- a/upb/port_def.inc +++ b/upb/port_def.inc @@ -30,6 +30,9 @@ #define UPB_SIZE(size32, size64) size64 #endif +/* These macros aren't really "port", they are helper macros that we don't want + * to leak. + */ #define UPB_FIELD_AT(msg, fieldtype, offset) \ *(fieldtype*)((const char*)(msg) + offset) @@ -42,6 +45,8 @@ UPB_FIELD_AT(msg, int, case_offset) = case_val; \ UPB_FIELD_AT(msg, fieldtype, offset) = value; +#define UPB_MAPTYPE_STRING 4 + /* UPB_INLINE: inline if possible, emit standalone code if required. */ #ifdef __cplusplus #define UPB_INLINE inline diff --git a/upb/reflection.c b/upb/reflection.c index 70ab323ba8..5e41d1a1c8 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -18,96 +18,6 @@ bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) { #define ENCODE_MAX_NESTING 64 #define CHECK_TRUE(x) if (!(x)) { return false; } -/** upb_msgval ****************************************************************/ - -#if 0 -/* These functions will generate real memcpy() calls on ARM sadly, because - * the compiler assumes they might not be aligned. */ - -static upb_msgval upb_msgval_read(const void *p, size_t ofs, - uint8_t size) { - upb_msgval val; - p = (char*)p + ofs; - memcpy(&val, p, size); - return val; -} - -static void upb_msgval_write(void *p, size_t ofs, upb_msgval val, - uint8_t size) { - p = (char*)p + ofs; - memcpy(p, &val, size); -} - -static size_t upb_msgval_sizeof(upb_descriptortype_t type) { - static uint8_t sizes[] = { - 0, /* none */ - 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE = 1 */ - 4, /* UPB_DESCRIPTOR_TYPE_FLOAT = 2 */ - 8, /* UPB_DESCRIPTOR_TYPE_INT64 = 3 */ - 8, /* UPB_DESCRIPTOR_TYPE_UINT64 = 4 */ - 4, /* UPB_DESCRIPTOR_TYPE_INT32 = 5 */ - 8, /* UPB_DESCRIPTOR_TYPE_FIXED64 = 6 */ - 4, /* UPB_DESCRIPTOR_TYPE_FIXED32 = 7 */ - 1, /* UPB_DESCRIPTOR_TYPE_BOOL = 8 */ - sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING = 9 */ - sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP = 11 */ - sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE = 12 */ - sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES = 13 */ - 4, /* UPB_DESCRIPTOR_TYPE_UINT32 = 14 */ - 4, /* UPB_DESCRIPTOR_TYPE_ENUM = 15 */ - 4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 = 16 */ - 8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 = 17 */ - 4, /* UPB_DESCRIPTOR_TYPE_SINT32 = 18 */ - 8, /* UPB_DESCRIPTOR_TYPE_SINT64 = 19 */ - }; - UPB_ASSERT(type < sizeof(sizes)); - return sizes[type]; -} - -static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { - static uint8_t sizes[] = { - 0, /* none */ - 1, /* UPB_TYPE_BOOL = 1, */ - 4, /* UPB_TYPE_FLOAT = 2, */ - 4, /* UPB_TYPE_INT32 = 3, */ - 4, /* UPB_TYPE_UINT32 = 4, */ - 4, /* UPB_TYPE_ENUM = 5, */ - sizeof(upb_strview), /* UPB_TYPE_STRING = 6, */ - sizeof(upb_strview), /* UPB_TYPE_BYTES = 7, */ - sizeof(void*), /* UPB_TYPE_MESSAGE = 8, */ - 8, /* UPB_TYPE_DOUBLE = 9, */ - 8, /* UPB_TYPE_INT64 = 10, */ - 8, /* UPB_TYPE_UINT64 = 11 */ - }; - UPB_ASSERT(type < sizeof(sizes)); - return sizes[type]; -} - -static uint8_t upb_msg_fieldsize(const upb_msglayout_field *field) { - if (field->label == UPB_LABEL_REPEATED) { - return sizeof(void*); - } else { - return upb_msgval_sizeof(field->descriptortype); - } -} - -/* TODO(haberman): this is broken right now because upb_msgval can contain - * a char* / size_t pair, which is too big for a upb_value. To fix this - * we'll probably need to dynamically allocate a upb_msgval and store a - * pointer to that in the tables for extensions/maps. */ -static upb_value upb_toval(upb_msgval val) { - upb_value ret; - UPB_UNUSED(val); - memset(&ret, 0, sizeof(upb_value)); /* XXX */ - return ret; -} - -static upb_msgval upb_msgval_fromval(upb_value val) { - upb_msgval ret; - UPB_UNUSED(val); - memset(&ret, 0, sizeof(upb_msgval)); /* XXX */ - return ret; -} /** upb_msg *******************************************************************/ @@ -116,6 +26,9 @@ static upb_msgval upb_msgval_fromval(upb_value val) { */ #define DEREF(msg, ofs, type) *PTR_AT(msg, ofs, type) +upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a); + +#if 0 static const upb_msglayout_field *upb_msg_checkfield(int field_index, const upb_msglayout *l) { UPB_ASSERT(field_index >= 0 && field_index < l->field_count); @@ -164,6 +77,7 @@ void upb_msg_set(upb_msg *msg, int field_index, upb_msgval val, upb_msgval_write(msg, field->offset, val, size); } +#undef DEREF #endif /** upb_array *****************************************************************/ @@ -174,51 +88,27 @@ size_t upb_array_size(const upb_array *arr) { upb_msgval upb_array_get(const upb_array *arr, size_t i) { UPB_ASSERT(i < arr->len); - const char* data = _upb_array_constptr(arr); - int elem_size_lg2 = arr->data & 7; upb_msgval ret; - - switch (elem_size_lg2) { - case 0: - ret.bool_val = *PTR_AT(data, i, bool); - break; - case 2: - memcpy(&ret, data + i * 4, 4); - break; - case 3: - memcpy(&ret, data + i * 8, 8); - break; - case 4: - memcpy(&ret, data + i * 16, 16); - break; - default: - UPB_UNREACHABLE(); - } - + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + memcpy(&ret, data + (i << lg2), 1 << lg2); return ret; } void upb_array_set(upb_array *arr, size_t i, upb_msgval val) { UPB_ASSERT(i < arr->len); char* data = _upb_array_ptr(arr); - int elem_size_lg2 = arr->data & 7; - - switch (elem_size_lg2) { - case 0: - *PTR_AT(data, i, bool) = val.bool_val; - break; - case 2: - memcpy(data + i * 4, &val, 4); - break; - case 3: - memcpy(data + i * 8, &val, 8); - break; - case 4: - memcpy(data + i * 16, &val, 16); - break; - default: - UPB_UNREACHABLE(); + int lg2 = arr->data & 7; + memcpy(data + (i << lg2), &val, 1 << lg2); +} + +bool upb_array_append(upb_array *arr, upb_msgval val, upb_arena *arena) { + if (!_upb_array_realloc(arr, arr->len + 1, arena)) { + return false; } + arr->len++; + upb_array_set(arr, arr->len - 1, val); + return true; } /* Resizes the array to the given size, reallocating if necessary, and returns a @@ -227,82 +117,51 @@ bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) { return _upb_array_realloc(arr, size, arena); } -#if 0 - /** upb_map *******************************************************************/ -static void upb_map_tokey(upb_descriptortype_t type, upb_msgval *key, - const char **out_key, size_t *out_len) { - switch (type) { - case UPB_DESCRIPTOR_TYPE_BYTES: - case UPB_DESCRIPTOR_TYPE_STRING: - /* Point to string data of the input key. */ - *out_key = key->str.data; - *out_len = key->str.size; - return; - case UPB_DESCRIPTOR_TYPE_BOOL: - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_SINT32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - case UPB_DESCRIPTOR_TYPE_FIXED32: - case UPB_DESCRIPTOR_TYPE_UINT32: - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_SINT64: - case UPB_DESCRIPTOR_TYPE_SFIXED64: - case UPB_DESCRIPTOR_TYPE_FIXED64: - case UPB_DESCRIPTOR_TYPE_UINT64: - /* Point to the key itself. XXX: big-endian. */ - *out_key = (const char*)key; - *out_len = upb_msgval_sizeof(type); - return; - case UPB_DESCRIPTOR_TYPE_DOUBLE: - case UPB_DESCRIPTOR_TYPE_ENUM: - case UPB_DESCRIPTOR_TYPE_FLOAT: - case UPB_DESCRIPTOR_TYPE_MESSAGE: - case UPB_DESCRIPTOR_TYPE_GROUP: - UPB_UNREACHABLE(); /* Cannot be a map key. */ +size_t upb_map_size(const upb_map *map) { + return upb_strtable_count(&map->table); +} + +static upb_strview upb_map_tokey(int size_lg2, upb_msgval *key) { + if (size_lg2 == UPB_MAPTYPE_STRING) { + return key->str_val; + } else { + return upb_strview_make((const char*)key, 1 << size_lg2); } - UPB_UNREACHABLE(); } -static upb_msgval upb_map_fromkey(upb_descriptortype_t type, const char *key, - size_t len) { - switch (type) { - case UPB_DESCRIPTOR_TYPE_BYTES: - case UPB_DESCRIPTOR_TYPE_STRING: - return upb_msgval_makestr(key, len); - case UPB_DESCRIPTOR_TYPE_BOOL: - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_SINT32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - case UPB_DESCRIPTOR_TYPE_FIXED32: - case UPB_DESCRIPTOR_TYPE_UINT32: - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_SINT64: - case UPB_DESCRIPTOR_TYPE_SFIXED64: - case UPB_DESCRIPTOR_TYPE_FIXED64: - case UPB_DESCRIPTOR_TYPE_UINT64: - return upb_msgval_read(key, 0, upb_msgval_sizeof(type)); - case UPB_DESCRIPTOR_TYPE_DOUBLE: - case UPB_DESCRIPTOR_TYPE_ENUM: - case UPB_DESCRIPTOR_TYPE_FLOAT: - case UPB_DESCRIPTOR_TYPE_MESSAGE: - case UPB_DESCRIPTOR_TYPE_GROUP: - UPB_UNREACHABLE(); /* Cannot be a map key. */ +static upb_msgval upb_map_fromvalue(int size_lg2, upb_value val) { + upb_msgval ret; + if (size_lg2 == UPB_MAPTYPE_STRING) { + upb_strview *strp = upb_value_getptr(val); + ret.str_val = *strp; + } else { + memcpy(&ret, &val, 8); } - UPB_UNREACHABLE(); + return ret; } -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val, - const upb_msglayout *layout) { +static upb_value upb_map_tovalue(int size_lg2, upb_msgval val, upb_arena *a) { + upb_value ret; + if (size_lg2 == UPB_MAPTYPE_STRING) { + upb_strview *strp = upb_arena_malloc(a, sizeof(*strp)); + *strp = val.str_val; + ret = upb_value_ptr(strp); + } else { + memcpy(&ret, &val, 8); + } + return ret; +} + +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { + upb_strview strkey = upb_map_tokey(map->key_size_lg2, &key); upb_value tabval; - const char *key_str; - size_t key_len; bool ret; - upb_map_tokey(layout->fields[0].descriptortype, &key, &key_str, &key_len); - ret = upb_strtable_lookup2(&map->table, key_str, key_len, &tabval); + ret = upb_strtable_lookup2(&map->table, strkey.data, strkey.size, &tabval); if (ret) { + *val = upb_map_fromvalue(map->val_size_lg2, tabval); memcpy(val, &tabval, sizeof(tabval)); } @@ -310,60 +169,41 @@ bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val, } bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, - const upb_msglayout *layout, upb_arena *arena) { - const char *key_str; - size_t key_len; - upb_value tabval = upb_toval(val); - upb_value removedtabval; + upb_arena *arena) { + upb_strview strkey = upb_map_tokey(map->key_size_lg2, &key); + upb_value tabval = upb_map_tovalue(map->val_size_lg2, val, arena); upb_alloc *a = upb_arena_alloc(arena); - upb_map_tokey(layout->fields[0].descriptortype, &key, &key_str, &key_len); - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - if (upb_strtable_lookup2(&map->table, key_str, key_len, NULL)) { - upb_strtable_remove3(&map->table, key_str, key_len, &removedtabval, a); + if (upb_strtable_lookup2(&map->table, strkey.data, strkey.size, NULL)) { + upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); } - return upb_strtable_insert3(&map->table, key_str, key_len, tabval, a); + return upb_strtable_insert3(&map->table, strkey.data, strkey.size, tabval, a); } -bool upb_map_del(upb_map *map, upb_msgval key, const upb_msglayout *layout, - upb_arena *arena) { - const char *key_str; - size_t key_len; +bool upb_map_delete(upb_map *map, upb_msgval key, upb_arena *arena) { + upb_strview strkey = upb_map_tokey(map->key_size_lg2, &key); upb_alloc *a = upb_arena_alloc(arena); - - upb_map_tokey(layout->fields[0].descriptortype, &key, &key_str, &key_len); - return upb_strtable_remove3(&map->table, key_str, key_len, NULL, a); + return upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); } /** upb_mapiter ***************************************************************/ struct upb_mapiter { upb_strtable_iter iter; - upb_descriptortype_t key_type; + char key_size_lg2; + char val_size_lg2; }; size_t upb_mapiter_sizeof(void) { return sizeof(upb_mapiter); } -void upb_mapiter_begin(upb_mapiter *i, const upb_msglayout *layout, - const upb_map *map) { +void upb_mapiter_begin(upb_mapiter *i, upb_map *map) { upb_strtable_begin(&i->iter, &map->table); - i->key_type = layout->fields[0].descriptortype; -} - -upb_mapiter *upb_mapiter_new(const upb_map *map, const upb_msglayout *layout, - upb_alloc *a) { - upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof()); - - if (!ret) { - return NULL; - } - - upb_mapiter_begin(ret, layout, map); - return ret; + i->key_size_lg2 = map->key_size_lg2; + i->val_size_lg2 = map->val_size_lg2; } void upb_mapiter_free(upb_mapiter *i, upb_alloc *a) { @@ -379,12 +219,18 @@ bool upb_mapiter_done(const upb_mapiter *i) { } upb_msgval upb_mapiter_key(const upb_mapiter *i) { - return upb_map_fromkey(i->key_type, upb_strtable_iter_key(&i->iter), - upb_strtable_iter_keylength(&i->iter)); + upb_strview key = upb_strtable_iter_key(&i->iter); + upb_msgval ret; + if (i->key_size_lg2 == UPB_MAPTYPE_STRING) { + ret.str_val = key; + } else { + memcpy(&ret, key.data, 1 << i->key_size_lg2); + } + return ret; } upb_msgval upb_mapiter_value(const upb_mapiter *i) { - return upb_msgval_fromval(upb_strtable_iter_value(&i->iter)); + return upb_map_fromvalue(i->val_size_lg2, upb_strtable_iter_value(&i->iter)); } void upb_mapiter_setdone(upb_mapiter *i) { @@ -394,5 +240,3 @@ void upb_mapiter_setdone(upb_mapiter *i) { bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) { return upb_strtable_iter_isequal(&i1->iter, &i2->iter); } - -#endif diff --git a/upb/reflection.h b/upb/reflection.h index 850149c930..d6825dbc82 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -89,7 +89,9 @@ bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, upb_arena *arena); /* Deletes this key from the table. Returns true if the key was present. */ -bool upb_map_delete(upb_map *map, upb_msgval key); +/* TODO(haberman): can |arena| be removed once upb_table is arena-only and no + * longer tries to free keys? */ +bool upb_map_delete(upb_map *map, upb_msgval key, upb_arena *arena); /** upb_mapiter ***************************************************************/ @@ -106,8 +108,8 @@ size_t upb_mapiter_sizeof(void); /* Starts iteration. If the map is mutable then we can modify entries while * iterating. */ -void upb_mapiter_constbegin(upb_mapiter *i, const upb_map *t); -void upb_mapiter_begin(upb_mapiter *i, upb_map *t); +void upb_mapiter_constbegin(upb_mapiter *i, const upb_map *map); +void upb_mapiter_begin(upb_mapiter *i, upb_map *map); /* Sets the iterator to "done" state. This will return "true" from * upb_mapiter_done() and will compare equal to other "done" iterators. */ diff --git a/upb/table.c b/upb/table.c index 8896d217db..cf8b5c8675 100644 --- a/upb/table.c +++ b/upb/table.c @@ -314,12 +314,10 @@ bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { return false; 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, - upb_strtable_iter_key(&i), - upb_strtable_iter_keylength(&i), - upb_strtable_iter_value(&i), - a); + &new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); } upb_strtable_uninit2(t, a); *t = new_table; @@ -389,16 +387,13 @@ bool upb_strtable_done(const upb_strtable_iter *i) { upb_tabent_isempty(str_tabent(i)); } -const char *upb_strtable_iter_key(const upb_strtable_iter *i) { +upb_strview upb_strtable_iter_key(const upb_strtable_iter *i) { UPB_ASSERT(!upb_strtable_done(i)); - return upb_tabstr(str_tabent(i)->key, NULL); -} - -size_t upb_strtable_iter_keylength(const upb_strtable_iter *i) { + upb_strview key; uint32_t len; - UPB_ASSERT(!upb_strtable_done(i)); - upb_tabstr(str_tabent(i)->key, &len); - return len; + key.data = upb_tabstr(str_tabent(i)->key, &len); + key.size = len; + return key; } upb_value upb_strtable_iter_value(const upb_strtable_iter *i) { diff --git a/upb/table.int.h b/upb/table.int.h index 23b0b2f221..d3c2bc7716 100644 --- a/upb/table.int.h +++ b/upb/table.int.h @@ -463,8 +463,7 @@ typedef struct { void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); void upb_strtable_next(upb_strtable_iter *i); bool upb_strtable_done(const upb_strtable_iter *i); -const char *upb_strtable_iter_key(const upb_strtable_iter *i); -size_t upb_strtable_iter_keylength(const upb_strtable_iter *i); +upb_strview upb_strtable_iter_key(const upb_strtable_iter *i); upb_value upb_strtable_iter_value(const upb_strtable_iter *i); void upb_strtable_iter_setdone(upb_strtable_iter *i); bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, diff --git a/upbc/generator.cc b/upbc/generator.cc index 3ef1f6dbf9..99634d9559 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -333,7 +333,7 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output std::string msgname = ToCIdent(message->full_name()); output( "UPB_INLINE $0 *$0_new(upb_arena *arena) {\n" - " return ($0 *)upb_msg_new(&$1, arena);\n" + " return ($0 *)_upb_msg_new(&$1, arena);\n" "}\n" "UPB_INLINE $0 *$0_parse(const char *buf, size_t size,\n" " upb_arena *arena) {\n" @@ -437,7 +437,7 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { output( "UPB_INLINE struct $0* $1_add_$2($1 *msg, upb_arena *arena) {\n" - " struct $0* sub = (struct $0*)upb_msg_new(&$3, arena);\n" + " struct $0* sub = (struct $0*)_upb_msg_new(&$3, arena);\n" " bool ok = _upb_array_append_accessor(\n" " msg, $4, $5, $6, &sub, arena);\n" " if (!ok) return NULL;\n" @@ -484,7 +484,7 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output "UPB_INLINE struct $0* $1_mutable_$2($1 *msg, upb_arena *arena) {\n" " struct $0* sub = (struct $0*)$1_$2(msg);\n" " if (sub == NULL) {\n" - " sub = (struct $0*)upb_msg_new(&$3, arena);\n" + " sub = (struct $0*)_upb_msg_new(&$3, arena);\n" " if (!sub) return NULL;\n" " $1_set_$2(msg, sub);\n" " }\n" From 5239655b991a37ec1d0af30db65113d60e5afaa3 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 2 Dec 2019 00:42:18 -0800 Subject: [PATCH 09/35] WIP. --- BUILD | 12 +- upb/bindings/lua/upb.h | 1 - upb/def.c | 226 +++++++++++++++++++++++++++++++++++-- upb/def.h | 7 +- upb/msgfactory.c | 248 ----------------------------------------- upb/msgfactory.h | 53 --------- upb/reflection.c | 30 ++--- upbc/generator.cc | 23 +++- 8 files changed, 254 insertions(+), 346 deletions(-) delete mode 100644 upb/msgfactory.c delete mode 100644 upb/msgfactory.h diff --git a/BUILD b/BUILD index 2b7d82e417..c02c2cf887 100644 --- a/BUILD +++ b/BUILD @@ -115,12 +115,10 @@ cc_library( name = "reflection", srcs = [ "upb/def.c", - "upb/msgfactory.c", "upb/reflection.c", ], hdrs = [ "upb/def.h", - "upb/msgfactory.h", "upb/reflection.h", ], copts = select({ @@ -593,11 +591,11 @@ cc_binary( ] ) -lua_test( - name = "lua/test_upb", - luadeps = ["lua/upb"], - luamain = "tests/bindings/lua/test_upb.lua", -) +#lua_test( +# name = "lua/test_upb", +# luadeps = ["lua/upb"], +# luamain = "tests/bindings/lua/test_upb.lua", +#) # Test the CMake build ######################################################### diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h index 6626e9813b..4040607994 100644 --- a/upb/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h @@ -8,7 +8,6 @@ #include "lauxlib.h" #include "upb/def.h" #include "upb/msg.h" -#include "upb/msgfactory.h" /* Lua changes its API in incompatible ways in every minor release. * This is some shim code to paper over the differences. */ diff --git a/upb/def.c b/upb/def.c index 158becb7cb..cc3665b842 100644 --- a/upb/def.c +++ b/upb/def.c @@ -42,7 +42,8 @@ struct upb_fielddef { const google_protobuf_FieldDescriptorProto *unresolved; } sub; uint32_t number_; - uint32_t index_; + uint16_t index_; + uint16_t layout_index; uint32_t selector_base; /* Used to index into a upb::Handlers table. */ bool is_extension_; bool lazy_; @@ -576,6 +577,10 @@ const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { return f->sub.enumdef; } +const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) { + return &f->containing_type->layout->fields[f->layout_index]; +} + bool upb_fielddef_issubmsg(const upb_fielddef *f) { return upb_fielddef_type(f) == UPB_TYPE_MESSAGE; } @@ -698,6 +703,10 @@ int upb_msgdef_numoneofs(const upb_msgdef *m) { return upb_strtable_count(&m->ntof) - upb_inttable_count(&m->itof); } +const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m) { + return m->layout; +} + bool upb_msgdef_mapentry(const upb_msgdef *m) { return m->map_entry; } @@ -820,6 +829,178 @@ void upb_oneof_iter_setdone(upb_oneof_iter *iter) { upb_inttable_iter_setdone(iter); } +/* Dynamic Layout Generation. *************************************************/ + +static bool is_power_of_two(size_t val) { + return (val & (val - 1)) == 0; +} + +/* Align up to the given power of 2. */ +static size_t align_up(size_t val, size_t align) { + UPB_ASSERT(is_power_of_two(align)); + return (val + align - 1) & ~(align - 1); +} + +static size_t div_round_up(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE_DOUBLE: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + return 8; + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_FLOAT: + return 4; + case UPB_TYPE_BOOL: + return 1; + case UPB_TYPE_MESSAGE: + return sizeof(void*); + case UPB_TYPE_BYTES: + case UPB_TYPE_STRING: + return sizeof(upb_strview); + } + UPB_UNREACHABLE(); +} + +static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { + if (upb_fielddef_isseq(f)) { + return sizeof(void*); + } else { + return upb_msgval_sizeof2(upb_fielddef_type(f)); + } +} + +static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { + size_t ret; + + l->size = align_up(l->size, size); + ret = l->size; + l->size += size; + return ret; +} + +static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { + upb_msglayout *l = (upb_msglayout*)m->layout; + upb_msg_field_iter it; + upb_msg_oneof_iter oit; + size_t hasbit; + size_t submsg_count = m->submsg_field_count; + const upb_msglayout **submsgs; + upb_msglayout_field *fields; + upb_alloc *alloc = upb_arena_alloc(symtab->arena); + + memset(l, 0, sizeof(*l)); + + fields = upb_malloc(alloc, upb_msgdef_numfields(m) * sizeof(*fields)); + submsgs = upb_malloc(alloc, submsg_count * sizeof(*submsgs)); + + if ((!fields && upb_msgdef_numfields(m)) || + (!submsgs && submsg_count)) { + /* OOM. */ + return false; + } + + l->field_count = upb_msgdef_numfields(m); + l->fields = fields; + l->submsgs = submsgs; + + /* Allocate data offsets in three stages: + * + * 1. hasbits. + * 2. regular fields. + * 3. oneof fields. + * + * OPT: There is a lot of room for optimization here to minimize the size. + */ + + /* Allocate hasbits and set basic field attributes. */ + submsg_count = 0; + for (upb_msg_field_begin(&it, m), hasbit = 0; + !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* f = upb_msg_iter_field(&it); + upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; + + field->number = upb_fielddef_number(f); + field->descriptortype = upb_fielddef_descriptortype(f); + field->label = upb_fielddef_label(f); + + if (upb_fielddef_issubmsg(f)) { + const upb_msgdef *subm = upb_fielddef_msgsubdef(f); + field->submsg_index = submsg_count++; + submsgs[field->submsg_index] = subm->layout; + } + + if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) { + field->presence = (hasbit++); + } else { + field->presence = 0; + } + } + + /* Account for space used by hasbits. */ + l->size = div_round_up(hasbit, 8); + + /* Allocate non-oneof fields. */ + for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* f = upb_msg_iter_field(&it); + size_t field_size = upb_msg_fielddefsize(f); + size_t index = upb_fielddef_index(f); + + if (upb_fielddef_containingoneof(f)) { + /* Oneofs are handled separately below. */ + continue; + } + + fields[index].offset = upb_msglayout_place(l, field_size); + } + + /* Allocate oneof fields. Each oneof field consists of a uint32 for the case + * and space for the actual data. */ + for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); + upb_msg_oneof_next(&oit)) { + const upb_oneofdef* o = upb_msg_iter_oneof(&oit); + upb_oneof_iter fit; + + size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ + size_t field_size = 0; + uint32_t case_offset; + uint32_t data_offset; + + /* Calculate field size: the max of all field sizes. */ + for (upb_oneof_begin(&fit, o); + !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* f = upb_oneof_iter_field(&fit); + field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + } + + /* Align and allocate case offset. */ + case_offset = upb_msglayout_place(l, case_size); + data_offset = upb_msglayout_place(l, field_size); + + for (upb_oneof_begin(&fit, o); + !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* f = upb_oneof_iter_field(&fit); + fields[upb_fielddef_index(f)].offset = data_offset; + fields[upb_fielddef_index(f)].presence = ~case_offset; + } + } + + /* Size of the entire structure should be a multiple of its greatest + * alignment. TODO: track overall alignment for real? */ + l->size = align_up(l->size, 8); + + return true; +} + /* Code to build defs from descriptor protos. *********************************/ /* There is a question of how much validation to do here. It will be difficult @@ -832,11 +1013,12 @@ void upb_oneof_iter_setdone(upb_oneof_iter *iter) { typedef struct { const upb_symtab *symtab; - upb_filedef *file; /* File we are building. */ - upb_alloc *alloc; /* Allocate defs here. */ - upb_alloc *tmp; /* Alloc for addtab and any other tmp data. */ - upb_strtable *addtab; /* full_name -> packed def ptr for new defs. */ - upb_status *status; /* Record errors here. */ + upb_filedef *file; /* File we are building. */ + upb_alloc *alloc; /* Allocate defs here. */ + upb_alloc *tmp; /* Alloc for addtab and any other tmp data. */ + upb_strtable *addtab; /* full_name -> packed def ptr for new defs */ + const upb_msglayout **layouts; /* NULL if we should build layouts. */ + upb_status *status; /* Record errors here. */ } symtab_addctx; static char* strviewdup(const symtab_addctx *ctx, upb_strview view) { @@ -1258,7 +1440,7 @@ static bool create_enumdef( return true; } -static bool create_msgdef(const symtab_addctx *ctx, const char *prefix, +static bool create_msgdef(symtab_addctx *ctx, const char *prefix, const google_protobuf_DescriptorProto *msg_proto) { upb_msgdef *m; const google_protobuf_MessageOptions *options; @@ -1288,6 +1470,14 @@ static bool create_msgdef(const symtab_addctx *ctx, const char *prefix, m->map_entry = google_protobuf_MessageOptions_map_entry(options); } + if (ctx->layouts) { + m->layout = *ctx->layouts; + ctx->layouts++; + } else { + /* Allocate now (to allow cross-linking), populate later. */ + m->layout = upb_malloc(ctx->alloc, sizeof(*m->layout)); + } + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n); m->oneof_count = 0; m->oneofs = upb_malloc(ctx->alloc, sizeof(*m->oneofs) * n); @@ -1434,7 +1624,7 @@ static bool resolve_fielddef(const symtab_addctx *ctx, const char *prefix, } static bool build_filedef( - const symtab_addctx *ctx, upb_filedef *file, + symtab_addctx *ctx, upb_filedef *file, const google_protobuf_FileDescriptorProto *file_proto) { upb_alloc *alloc = ctx->alloc; const google_protobuf_FileOptions *file_options_proto; @@ -1548,7 +1738,7 @@ static bool build_filedef( CHK(create_fielddef(ctx, file->package, NULL, exts[i])); } - /* Now that all names are in the table, resolve references. */ + /* Now that all names are in the table, build layouts and resolve refs. */ for (i = 0; i < file->ext_count; i++) { CHK(resolve_fielddef(ctx, file->package, (upb_fielddef*)&file->exts[i])); } @@ -1561,6 +1751,11 @@ static bool build_filedef( } } + for (i = 0; i < file->msg_count; i++) { + const upb_msgdef *m = &file->msgs[i]; + make_layout(ctx->symtab, m); + } + return true; } @@ -1679,9 +1874,9 @@ const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) : NULL; } -const upb_filedef *upb_symtab_addfile( +static const upb_filedef *_upb_symtab_addfile( upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, - upb_status *status) { + const upb_msglayout **layouts, upb_status *status) { upb_arena *tmparena = upb_arena_new(); upb_strtable addtab; upb_alloc *alloc = upb_arena_alloc(s->arena); @@ -1694,6 +1889,7 @@ const upb_filedef *upb_symtab_addfile( ctx.alloc = alloc; ctx.tmp = upb_arena_alloc(tmparena); ctx.addtab = &addtab; + ctx.layouts = layouts; ctx.status = status; ok = file && @@ -1705,6 +1901,12 @@ const upb_filedef *upb_symtab_addfile( return ok ? file : NULL; } +const upb_filedef *upb_symtab_addfile( + upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, + upb_status *status) { + return _upb_symtab_addfile(s, file_proto, NULL, status); +} + /* Include here since we want most of this file to be stdio-free. */ #include @@ -1740,7 +1942,7 @@ bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init) { goto err; } - if (!upb_symtab_addfile(s, file, &status)) goto err; + if (!_upb_symtab_addfile(s, file, init->layouts, &status)) goto err; upb_arena_free(arena); return true; diff --git a/upb/def.h b/upb/def.h index 9be285794e..0ff26eb09e 100644 --- a/upb/def.h +++ b/upb/def.h @@ -123,6 +123,7 @@ bool upb_fielddef_hassubdef(const upb_fielddef *f); bool upb_fielddef_haspresence(const upb_fielddef *f); 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); @@ -425,6 +426,7 @@ const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, size_t len); int upb_msgdef_numfields(const upb_msgdef *m); int upb_msgdef_numoneofs(const upb_msgdef *m); +const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m); UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m, const char *name) { @@ -851,9 +853,10 @@ const upb_filedef *upb_symtab_addfile( /* For generated code only: loads a generated descriptor. */ typedef struct upb_def_init { - struct upb_def_init **deps; + struct upb_def_init **deps; /* Dependencies of this file. */ + const upb_msglayout **layouts; /* Pre-order layouts of all messages. */ const char *filename; - upb_strview descriptor; + upb_strview descriptor; /* Serialized descriptor. */ } upb_def_init; bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init); diff --git a/upb/msgfactory.c b/upb/msgfactory.c deleted file mode 100644 index 4ecf2725b1..0000000000 --- a/upb/msgfactory.c +++ /dev/null @@ -1,248 +0,0 @@ - -#include "upb/msgfactory.h" - -#include "upb/port_def.inc" - -static bool is_power_of_two(size_t val) { - return (val & (val - 1)) == 0; -} - -/* Align up to the given power of 2. */ -static size_t align_up(size_t val, size_t align) { - UPB_ASSERT(is_power_of_two(align)); - return (val + align - 1) & ~(align - 1); -} - -static size_t div_round_up(size_t n, size_t d) { - return (n + d - 1) / d; -} - -static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_DOUBLE: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - return 8; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_FLOAT: - return 4; - case UPB_TYPE_BOOL: - return 1; - case UPB_TYPE_MESSAGE: - return sizeof(void*); - case UPB_TYPE_BYTES: - case UPB_TYPE_STRING: - return sizeof(upb_strview); - } - UPB_UNREACHABLE(); -} - -static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { - if (upb_fielddef_isseq(f)) { - return sizeof(void*); - } else { - return upb_msgval_sizeof2(upb_fielddef_type(f)); - } -} - - -/** upb_msglayout *************************************************************/ - -static void upb_msglayout_free(upb_msglayout *l) { - upb_gfree(l); -} - -static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { - size_t ret; - - l->size = align_up(l->size, size); - ret = l->size; - l->size += size; - return ret; -} - -static bool upb_msglayout_init(const upb_msgdef *m, - upb_msglayout *l, - upb_msgfactory *factory) { - upb_msg_field_iter it; - upb_msg_oneof_iter oit; - size_t hasbit; - size_t submsg_count = 0; - const upb_msglayout **submsgs; - upb_msglayout_field *fields; - - for (upb_msg_field_begin(&it, m); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* f = upb_msg_iter_field(&it); - if (upb_fielddef_issubmsg(f)) { - submsg_count++; - } - } - - memset(l, 0, sizeof(*l)); - - fields = upb_gmalloc(upb_msgdef_numfields(m) * sizeof(*fields)); - submsgs = upb_gmalloc(submsg_count * sizeof(*submsgs)); - - if ((!fields && upb_msgdef_numfields(m)) || - (!submsgs && submsg_count)) { - /* OOM. */ - upb_gfree(fields); - upb_gfree(submsgs); - return false; - } - - l->field_count = upb_msgdef_numfields(m); - l->fields = fields; - l->submsgs = submsgs; - - /* Allocate data offsets in three stages: - * - * 1. hasbits. - * 2. regular fields. - * 3. oneof fields. - * - * OPT: There is a lot of room for optimization here to minimize the size. - */ - - /* Allocate hasbits and set basic field attributes. */ - submsg_count = 0; - for (upb_msg_field_begin(&it, m), hasbit = 0; - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* f = upb_msg_iter_field(&it); - upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; - - field->number = upb_fielddef_number(f); - field->descriptortype = upb_fielddef_descriptortype(f); - field->label = upb_fielddef_label(f); - - if (upb_fielddef_issubmsg(f)) { - const upb_msglayout *sub_layout = - upb_msgfactory_getlayout(factory, upb_fielddef_msgsubdef(f)); - field->submsg_index = submsg_count++; - submsgs[field->submsg_index] = sub_layout; - } - - if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) { - field->presence = (hasbit++); - } else { - field->presence = 0; - } - } - - /* Account for space used by hasbits. */ - l->size = div_round_up(hasbit, 8); - - /* Allocate non-oneof fields. */ - for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* f = upb_msg_iter_field(&it); - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_fielddef_index(f); - - if (upb_fielddef_containingoneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } - - fields[index].offset = upb_msglayout_place(l, field_size); - } - - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* o = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; - - /* Calculate field size: the max of all field sizes. */ - for (upb_oneof_begin(&fit, o); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* f = upb_oneof_iter_field(&fit); - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); - } - - /* Align and allocate case offset. */ - case_offset = upb_msglayout_place(l, case_size); - data_offset = upb_msglayout_place(l, field_size); - - for (upb_oneof_begin(&fit, o); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* f = upb_oneof_iter_field(&fit); - fields[upb_fielddef_index(f)].offset = data_offset; - fields[upb_fielddef_index(f)].presence = ~case_offset; - } - } - - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = align_up(l->size, 8); - - return true; -} - - -/** upb_msgfactory ************************************************************/ - -struct upb_msgfactory { - const upb_symtab *symtab; /* We own a ref. */ - upb_inttable layouts; -}; - -upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) { - upb_msgfactory *ret = upb_gmalloc(sizeof(*ret)); - - ret->symtab = symtab; - upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR); - - return ret; -} - -void upb_msgfactory_free(upb_msgfactory *f) { - upb_inttable_iter i; - upb_inttable_begin(&i, &f->layouts); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i)); - upb_msglayout_free(l); - } - - upb_inttable_uninit(&f->layouts); - upb_gfree(f); -} - -const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) { - return f->symtab; -} - -const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, - const upb_msgdef *m) { - upb_value v; - UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m); - UPB_ASSERT(!upb_msgdef_mapentry(m)); - - if (upb_inttable_lookupptr(&f->layouts, m, &v)) { - UPB_ASSERT(upb_value_getptr(v)); - return upb_value_getptr(v); - } else { - /* In case of circular dependency, layout has to be inserted first. */ - upb_msglayout *l = upb_gmalloc(sizeof(*l)); - upb_msgfactory *mutable_f = (void*)f; - upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l)); - UPB_ASSERT(l); - if (!upb_msglayout_init(m, l, f)) { - upb_msglayout_free(l); - } - return l; - } -} diff --git a/upb/msgfactory.h b/upb/msgfactory.h deleted file mode 100644 index 3770faf5f2..0000000000 --- a/upb/msgfactory.h +++ /dev/null @@ -1,53 +0,0 @@ - -#include "upb/def.h" -#include "upb/msg.h" - -#ifndef UPB_MSGFACTORY_H_ -#define UPB_MSGFACTORY_H_ - -/** upb_msgfactory ************************************************************/ - -struct upb_msgfactory; -typedef struct upb_msgfactory upb_msgfactory; - -#ifdef __cplusplus -extern "C" { -#endif - -/* A upb_msgfactory contains a cache of upb_msglayout, upb_handlers, and - * upb_visitorplan objects. These are the objects necessary to represent, - * populate, and and visit upb_msg objects. - * - * These caches are all populated by upb_msgdef, and lazily created on demand. - */ - -/* Creates and destroys a msgfactory, respectively. The messages for this - * msgfactory must come from |symtab| (which should outlive the msgfactory). */ -upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab); -void upb_msgfactory_free(upb_msgfactory *f); - -const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f); - -/* The functions to get cached objects, lazily creating them on demand. These - * all require: - * - * - m is in upb_msgfactory_symtab(f) - * - upb_msgdef_mapentry(m) == false (since map messages can't have layouts). - * - * The returned objects will live for as long as the msgfactory does. - * - * TODO(haberman): consider making this thread-safe and take a const - * upb_msgfactory. */ -const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, - const upb_msgdef *m); - -const upb_msglayout *upb_msgfactory_getmaplayout(upb_msgfactory *f, - const upb_fieldtype_t keytype, - const upb_fieldtype_t valtype, - const upb_msgdef *valmsg); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_MSGFACTORY_H_ */ diff --git a/upb/reflection.c b/upb/reflection.c index 5e41d1a1c8..6db68ec4aa 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -7,16 +7,7 @@ #include "upb/port_def.inc" -bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) { - return type == UPB_TYPE_BOOL || type == UPB_TYPE_INT32 || - type == UPB_TYPE_UINT32 || type == UPB_TYPE_INT64 || - type == UPB_TYPE_UINT64 || type == UPB_TYPE_STRING; -} - #define PTR_AT(msg, ofs, type) (type*)((char*)msg + ofs) -#define VOIDPTR_AT(msg, ofs) PTR_AT(msg, ofs, void) -#define ENCODE_MAX_NESTING 64 -#define CHECK_TRUE(x) if (!(x)) { return false; } /** upb_msg *******************************************************************/ @@ -26,9 +17,10 @@ bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) { */ #define DEREF(msg, ofs, type) *PTR_AT(msg, ofs, type) -upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a); +upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a) { + return _upb_msg_new(upb_msgdef_layout(m), a); +} -#if 0 static const upb_msglayout_field *upb_msg_checkfield(int field_index, const upb_msglayout *l) { UPB_ASSERT(field_index >= 0 && field_index < l->field_count); @@ -46,10 +38,8 @@ static uint32_t *upb_msg_oneofcase(const upb_msg *msg, int field_index, return PTR_AT(msg, ~field->presence, uint32_t); } -bool upb_msg_has(const upb_msg *msg, - int field_index, - const upb_msglayout *l) { - const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); +bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { + const upb_msglayout_field *field = upb_fielddef_layout(f); UPB_ASSERT(field->presence); @@ -63,22 +53,20 @@ bool upb_msg_has(const upb_msg *msg, } } -upb_msgval upb_msg_get(const upb_msg *msg, int field_index, - const upb_msglayout *l) { - const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); +upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { + const upb_msglayout_field *field = upb_fielddef_layout(f); int size = upb_msg_fieldsize(field); return upb_msgval_read(msg, field->offset, size); } -void upb_msg_set(upb_msg *msg, int field_index, upb_msgval val, - const upb_msglayout *l) { +void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, + upb_arena *a) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); int size = upb_msg_fieldsize(field); upb_msgval_write(msg, field->offset, val, size); } #undef DEREF -#endif /** upb_array *****************************************************************/ diff --git a/upbc/generator.cc b/upbc/generator.cc index 99634d9559..184a524ee0 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -761,12 +761,27 @@ void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) { output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i))); } + std::vector file_messages = + SortedMessages(file); + + for (auto message : file_messages) { + output("extern const upb_msglayout $0;\n", MessageInit(message)); + } + output("\n"); + + output("static const upb_msglayout *layouts[$0] = {\n", file_messages.size()); + for (auto message : file_messages) { + output(" &$0,\n", MessageInit(message)); + } + output("};\n"); + output("\n"); + protobuf::FileDescriptorProto file_proto; file->CopyTo(&file_proto); std::string file_data; file_proto.SerializeToString(&file_data); - output("static const char descriptor[$0] =\n", file_data.size()); + output("static const char descriptor[$0] =", file_data.size()); { if (file_data.size() > 65535) { @@ -786,13 +801,15 @@ void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) { // Only write 40 bytes per line. static const size_t kBytesPerLine = 40; for (size_t i = 0; i < file_data.size(); i += kBytesPerLine) { + output("\n"); output( - "\"$0\"\n", + " \"$0\"", EscapeTrigraphs(absl::CEscape(file_data.substr(i, kBytesPerLine)))); } } output(";\n"); } + output("\n"); output("static upb_def_init *deps[$0] = {\n", file->dependency_count() + 1); for (int i = 0; i < file->dependency_count(); i++) { @@ -800,9 +817,11 @@ void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) { } output(" NULL\n"); output("};\n"); + output("\n"); output("upb_def_init $0 = {\n", DefInitSymbol(file)); output(" deps,\n"); + output(" layouts,\n"); output(" \"$0\",\n", file->name()); output(" UPB_STRVIEW_INIT(descriptor, $0)\n", file_data.size()); output("};\n"); From 626ec4bfcf3f8cf53f191a8a3b8e7c6cd104661b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 3 Dec 2019 20:18:24 -0800 Subject: [PATCH 10/35] Everything builds, test pass except test_decoder. --- CMakeLists.txt | 2 - bazel/upb_proto_library.bzl | 73 +++++++++++++++++---- tests/test_table.cc | 3 +- tools/make_cmakelists.py | 2 + upb/def.c | 6 +- upb/reflection.c | 123 ++++++++++++++++++++++++++++-------- 6 files changed, 165 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2393dedee6..1235bdb098 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,10 +80,8 @@ target_link_libraries(generated_code_support__only_for_generated_code_do_not_use upb) add_library(reflection upb/def.c - upb/msgfactory.c upb/reflection.c upb/def.h - upb/msgfactory.h upb/reflection.h) target_link_libraries(reflection descriptor_upbproto diff --git a/bazel/upb_proto_library.bzl b/bazel/upb_proto_library.bzl index f148745be5..f1f9fbe288 100644 --- a/bazel/upb_proto_library.bzl +++ b/bazel/upb_proto_library.bzl @@ -146,8 +146,10 @@ GeneratedSrcsInfo = provider( }, ) -_WrappedCcInfo = provider(fields = ["cc_info"]) +_UpbWrappedCcInfo = provider(fields = ["cc_info"]) +_UpbDefsWrappedCcInfo = provider(fields = ["cc_info"]) _WrappedGeneratedSrcsInfo = provider(fields = ["srcs"]) +_WrappedDefsGeneratedSrcsInfo = provider(fields = ["srcs"]) def _compile_upb_protos(ctx, proto_info, proto_sources, ext): srcs = [_generate_output_file(ctx, name, ext + ".c") for name in proto_sources] @@ -175,11 +177,23 @@ def _upb_proto_rule_impl(ctx): if len(ctx.attr.deps) != 1: fail("only one deps dependency allowed.") dep = ctx.attr.deps[0] - if _WrappedCcInfo not in dep or _WrappedGeneratedSrcsInfo not in dep: - fail("proto_library rule must generate _WrappedCcInfo and " + - "_WrappedGeneratedSrcsInfo (aspect should have handled this).") - cc_info = dep[_WrappedCcInfo].cc_info - srcs = dep[_WrappedGeneratedSrcsInfo].srcs + + if _WrappedDefsGeneratedSrcsInfo in dep: + srcs = dep[_WrappedDefsGeneratedSrcsInfo].srcs + elif _WrappedGeneratedSrcsInfo in dep: + srcs = dep[_WrappedGeneratedSrcsInfo].srcs + else: + fail("proto_library rule must generate _WrappedGeneratedSrcsInfo or " + + "_WrappedDefsGeneratedSrcsInfo (aspect should have handled this).") + + if _UpbDefsWrappedCcInfo in dep: + cc_info = dep[_UpbDefsWrappedCcInfo].cc_info + elif _UpbWrappedCcInfo in dep: + cc_info = dep[_UpbWrappedCcInfo].cc_info + else: + fail("proto_library rule must generate _UpbWrappedCcInfo or " + + "_UpbDefsWrappedCcInfo (aspect should have handled this).") + if type(cc_info.linking_context.libraries_to_link) == "list": lib = cc_info.linking_context.libraries_to_link[0] else: @@ -195,12 +209,19 @@ def _upb_proto_rule_impl(ctx): cc_info, ] -def _upb_proto_aspect_impl(target, ctx): +def _upb_proto_aspect_impl(target, ctx, cc_provider, file_provider): proto_info = target[ProtoInfo] files = _compile_upb_protos(ctx, proto_info, proto_info.direct_sources, ctx.attr._ext) deps = ctx.rule.attr.deps + ctx.attr._upb + if cc_provider == _UpbDefsWrappedCcInfo: + deps += ctx.attr._upb_reflection dep_ccinfos = [dep[CcInfo] for dep in deps if CcInfo in dep] - dep_ccinfos += [dep[_WrappedCcInfo].cc_info for dep in deps if _WrappedCcInfo in dep] + dep_ccinfos += [dep[_UpbWrappedCcInfo].cc_info for dep in deps if _UpbWrappedCcInfo in dep] + dep_ccinfos += [dep[_UpbDefsWrappedCcInfo].cc_info for dep in deps if _UpbDefsWrappedCcInfo in dep] + if cc_provider == _UpbDefsWrappedCcInfo: + if _UpbWrappedCcInfo not in target: + fail("Target should have _UpbDefsWrappedCcInfo provider") + dep_ccinfos += [target[_UpbWrappedCcInfo].cc_info] cc_info = _cc_library_func( ctx = ctx, name = ctx.rule.attr.name + ctx.attr._ext, @@ -208,7 +229,13 @@ def _upb_proto_aspect_impl(target, ctx): srcs = files.srcs, dep_ccinfos = dep_ccinfos, ) - return [_WrappedCcInfo(cc_info = cc_info), _WrappedGeneratedSrcsInfo(srcs = files)] + return [cc_provider(cc_info = cc_info), file_provider(srcs = files)] + +def _upb_proto_library_aspect_impl(target, ctx): + return _upb_proto_aspect_impl(target, ctx, _UpbWrappedCcInfo, _WrappedGeneratedSrcsInfo) + +def _upb_proto_reflection_library_aspect_impl(target, ctx): + return _upb_proto_aspect_impl(target, ctx, _UpbDefsWrappedCcInfo, _WrappedDefsGeneratedSrcsInfo) def _maybe_add(d): if not _is_bazel: @@ -242,7 +269,11 @@ _upb_proto_library_aspect = aspect( ]), "_ext": attr.string(default = ".upb"), }), - implementation = _upb_proto_aspect_impl, + implementation = _upb_proto_library_aspect_impl, + provides = [ + _UpbWrappedCcInfo, + _WrappedGeneratedSrcsInfo, + ], attr_aspects = ["deps"], fragments = ["cpp"], toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], @@ -277,15 +308,30 @@ _upb_proto_reflection_library_aspect = aspect( "_cc_toolchain": attr.label( default = "@bazel_tools//tools/cpp:current_cc_toolchain", ), + # For unknown reasons, this gets overwritten. "_upb": attr.label_list( default = [ "//:upb", "//:reflection", ], ), + "_upb_reflection": attr.label_list( + default = [ + "//:upb", + "//:reflection", + ], + ), "_ext": attr.string(default = ".upbdefs"), }), - implementation = _upb_proto_aspect_impl, + implementation = _upb_proto_reflection_library_aspect_impl, + provides = [ + _UpbDefsWrappedCcInfo, + _WrappedDefsGeneratedSrcsInfo, + ], + required_aspect_providers = [ + _UpbWrappedCcInfo, + _WrappedGeneratedSrcsInfo, + ], attr_aspects = ["deps"], fragments = ["cpp"], toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], @@ -296,7 +342,10 @@ upb_proto_reflection_library = rule( implementation = _upb_proto_rule_impl, attrs = { "deps": attr.label_list( - aspects = [_upb_proto_reflection_library_aspect], + aspects = [ + _upb_proto_library_aspect, + _upb_proto_reflection_library_aspect, + ], allow_rules = ["proto_library"], providers = [ProtoInfo], ), diff --git a/tests/test_table.cc b/tests/test_table.cc index 063eb68cee..e19a74a50d 100644 --- a/tests/test_table.cc +++ b/tests/test_table.cc @@ -166,7 +166,8 @@ class StrTable { std::pair operator*() const { std::pair ret; - ret.first.assign(upb_strtable_iter_key(&iter_)); + upb_strview view = upb_strtable_iter_key(&iter_); + ret.first.assign(view.data, view.size); ret.second = upb_strtable_iter_value(&iter_); return ret; } diff --git a/tools/make_cmakelists.py b/tools/make_cmakelists.py index a4923c8da0..b1b1a35e5f 100755 --- a/tools/make_cmakelists.py +++ b/tools/make_cmakelists.py @@ -38,6 +38,8 @@ class BuildFileFunctions(object): def cc_library(self, **kwargs): if kwargs["name"] == "amalgamation" or kwargs["name"] == "upbc_generator": return + if kwargs["name"] == "lupb": + return files = kwargs.get("srcs", []) + kwargs.get("hdrs", []) found_files = [] for file in files: diff --git a/upb/def.c b/upb/def.c index cc3665b842..b79d4e67a4 100644 --- a/upb/def.c +++ b/upb/def.c @@ -578,7 +578,7 @@ const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { } const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) { - return &f->containing_type->layout->fields[f->layout_index]; + return &f->msgdef->layout->fields[f->layout_index]; } bool upb_fielddef_issubmsg(const upb_fielddef *f) { @@ -845,7 +845,7 @@ static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } -static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { +static size_t upb_msgval_sizeof(upb_fieldtype_t type) { switch (type) { case UPB_TYPE_DOUBLE: case UPB_TYPE_INT64: @@ -871,7 +871,7 @@ static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { if (upb_fielddef_isseq(f)) { return sizeof(void*); } else { - return upb_msgval_sizeof2(upb_fielddef_type(f)); + return upb_msgval_sizeof(upb_fielddef_type(f)); } } diff --git a/upb/reflection.c b/upb/reflection.c index 6db68ec4aa..eee52a7eda 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -7,63 +7,134 @@ #include "upb/port_def.inc" -#define PTR_AT(msg, ofs, type) (type*)((char*)msg + ofs) - +char field_size[] = { + 0,/* 0 */ + 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE */ + 4, /* UPB_DESCRIPTOR_TYPE_FLOAT */ + 8, /* UPB_DESCRIPTOR_TYPE_INT64 */ + 8, /* UPB_DESCRIPTOR_TYPE_UINT64 */ + 4, /* UPB_DESCRIPTOR_TYPE_INT32 */ + 8, /* UPB_DESCRIPTOR_TYPE_FIXED64 */ + 4, /* UPB_DESCRIPTOR_TYPE_FIXED32 */ + 1, /* UPB_DESCRIPTOR_TYPE_BOOL */ + sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING */ + sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP */ + sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE */ + sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES */ + 4, /* UPB_DESCRIPTOR_TYPE_UINT32 */ + 4, /* UPB_DESCRIPTOR_TYPE_ENUM */ + 4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 */ + 8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 */ + 4, /* UPB_DESCRIPTOR_TYPE_SINT32 */ + 8, /* UPB_DESCRIPTOR_TYPE_SINT64 */ +}; /** upb_msg *******************************************************************/ /* If we always read/write as a consistent type to each address, this shouldn't * violate aliasing. */ -#define DEREF(msg, ofs, type) *PTR_AT(msg, ofs, type) +#define PTR_AT(msg, ofs, type) (type*)((char*)msg + ofs) upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a) { return _upb_msg_new(upb_msgdef_layout(m), a); } -static const upb_msglayout_field *upb_msg_checkfield(int field_index, - const upb_msglayout *l) { - UPB_ASSERT(field_index >= 0 && field_index < l->field_count); - return &l->fields[field_index]; -} - -static bool upb_msg_inoneof(const upb_msglayout_field *field) { +static bool in_oneof(const upb_msglayout_field *field) { return field->presence < 0; } -static uint32_t *upb_msg_oneofcase(const upb_msg *msg, int field_index, - const upb_msglayout *l) { - const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); - UPB_ASSERT(upb_msg_inoneof(field)); +static uint32_t *oneofcase(const upb_msg *msg, + const upb_msglayout_field *field) { + UPB_ASSERT(in_oneof(field)); return PTR_AT(msg, ~field->presence, uint32_t); } bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { const upb_msglayout_field *field = upb_fielddef_layout(f); - UPB_ASSERT(field->presence); - - if (upb_msg_inoneof(field)) { - /* Oneofs are set when the oneof number is set to this field. */ - return *upb_msg_oneofcase(msg, field_index, l) == field->number; + if (in_oneof(field)) { + return *oneofcase(msg, field) == field->number; } else { - /* Other fields are set when their hasbit is set. */ uint32_t hasbit = field->presence; - return DEREF(msg, hasbit / 8, char) | (1 << (hasbit % 8)); + return *PTR_AT(msg, hasbit / 8, char) | (1 << (hasbit % 8)); } } upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { const upb_msglayout_field *field = upb_fielddef_layout(f); - int size = upb_msg_fieldsize(field); - return upb_msgval_read(msg, field->offset, size); + const char *mem = PTR_AT(msg, field->offset, char); + upb_msgval val; + if (field->presence == 0 || upb_msg_has(msg, f)) { + memcpy(&val, mem, field_size[field->descriptortype]); + } else { + /* TODO(haberman): change upb_fielddef to not require this switch(). */ + 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.double_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; +} + +upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, + upb_arena *a) { + const upb_msglayout_field *field = upb_fielddef_layout(f); + upb_mutmsgval ret; + char *mem = PTR_AT(msg, field->offset, char); + memcpy(&ret, mem, sizeof(void*)); + if (!ret.msg) { + if (upb_fielddef_ismap(f)) { + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); + const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); + ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value)); + } else if (upb_fielddef_isseq(f)) { + ret.array = upb_array_new(a, upb_fielddef_type(f)); + } else { + UPB_ASSERT(upb_fielddef_issubmsg(f)); + ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a); + } + memcpy(mem, &ret, sizeof(void*)); + } + return ret; } void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, upb_arena *a) { - const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); - int size = upb_msg_fieldsize(field); - upb_msgval_write(msg, field->offset, val, size); + const upb_msglayout_field *field = upb_fielddef_layout(f); + char *mem = PTR_AT(msg, field->offset, char); + memcpy(mem, &val, field_size[field->descriptortype]); + if (in_oneof(field)) { + *oneofcase(msg, field) = field->number; + } } #undef DEREF From 88d996132e47e9e91a37c2ade71f8d757d2cdb67 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 3 Dec 2019 20:57:14 -0800 Subject: [PATCH 11/35] Added Lua main.c test driver program. --- tests/bindings/lua/main.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/bindings/lua/main.c diff --git a/tests/bindings/lua/main.c b/tests/bindings/lua/main.c new file mode 100644 index 0000000000..8a30d06d3d --- /dev/null +++ b/tests/bindings/lua/main.c @@ -0,0 +1,22 @@ + +#include +#include +#include + +#include "upb/bindings/lua/upb.h" + +int main() { + int ret = 0; + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + lua_pushcfunction(L, luaopen_lupb); + + if (luaL_dostring(L, "package.preload['lupb'] = ...[1]") || + luaL_dofile(L, "tests/bindings/lua/test_upb.lua")) { + fprintf(stderr, "error testing Lua: %s\n", lua_tostring(L, -1)); + ret = 1; + } + + lua_close(L); + return ret; +} From cc6db9fb0b1f3a3aecd2ad46ae0481b98e7ebc7b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 3 Dec 2019 20:57:41 -0800 Subject: [PATCH 12/35] Fixed crash bug. --- upb/def.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/upb/def.c b/upb/def.c index b79d4e67a4..fedd52ea90 100644 --- a/upb/def.c +++ b/upb/def.c @@ -1751,9 +1751,11 @@ static bool build_filedef( } } - for (i = 0; i < file->msg_count; i++) { - const upb_msgdef *m = &file->msgs[i]; - make_layout(ctx->symtab, m); + if (!ctx->layouts) { + for (i = 0; i < file->msg_count; i++) { + const upb_msgdef *m = &file->msgs[i]; + make_layout(ctx->symtab, m); + } } return true; From b518b06d75b56b4ec2e6fec93d79d8c3bc934130 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 3 Dec 2019 22:05:05 -0800 Subject: [PATCH 13/35] Lua test program is loaded successfully. --- tests/bindings/lua/main.c | 8 +++++++- tests/bindings/lua/test_upb.lua | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/bindings/lua/main.c b/tests/bindings/lua/main.c index 8a30d06d3d..379e6ded20 100644 --- a/tests/bindings/lua/main.c +++ b/tests/bindings/lua/main.c @@ -5,13 +5,19 @@ #include "upb/bindings/lua/upb.h" +const char *init = + "package.preload['lupb'] = ... " + "package.path = './?.lua;./third_party/lunit/?.lua'"; + int main() { int ret = 0; lua_State *L = luaL_newstate(); luaL_openlibs(L); lua_pushcfunction(L, luaopen_lupb); + ret = luaL_loadstring(L, init); + lua_pushcfunction(L, luaopen_lupb); - if (luaL_dostring(L, "package.preload['lupb'] = ...[1]") || + if (ret || lua_pcall(L, 1, LUA_MULTRET, 0) || luaL_dofile(L, "tests/bindings/lua/test_upb.lua")) { fprintf(stderr, "error testing Lua: %s\n", lua_tostring(L, -1)); ret = 1; diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index e4edda4003..0583aa9341 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -1,5 +1,5 @@ -local upb = require "upb" +local upb = require "lupb" local lunit = require "lunit" if _VERSION >= 'Lua 5.2' then From bfc86d35779c084a7765838c3f72a319e06c288b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 4 Dec 2019 16:56:40 -0800 Subject: [PATCH 14/35] Fixed many bugs, basic Lua test passes! --- BUILD | 20 ++++---- bazel/build_defs.bzl | 82 --------------------------------- tests/bindings/lua/test_upb.lua | 19 ++++++++ upb/bindings/lua/def.c | 51 ++++++++++++++------ upb/bindings/lua/msg.c | 10 ++-- upb/bindings/lua/upb.h | 2 +- upb/def.c | 23 ++++++++- 7 files changed, 94 insertions(+), 113 deletions(-) diff --git a/BUILD b/BUILD index c02c2cf887..ad45b604d1 100644 --- a/BUILD +++ b/BUILD @@ -2,10 +2,6 @@ load( "//bazel:build_defs.bzl", "generated_file_staleness_test", "licenses", # copybara:strip_for_google3 - "lua_binary", - "lua_cclibrary", - "lua_library", - "lua_test", "make_shell_script", "upb_amalgamation", ) @@ -582,21 +578,23 @@ cc_library( ], ) -cc_binary( +cc_test( name = "lua_tester", + linkstatic = 1, srcs = ["tests/bindings/lua/main.c"], + data = [ + "@com_google_protobuf//:conformance_proto", + "@com_google_protobuf//:descriptor_proto", + "tests/bindings/lua/test_upb.lua", + "third_party/lunit/console.lua", + "third_party/lunit/lunit.lua", + ], deps = [ ":lupb", "@lua//:liblua", ] ) -#lua_test( -# name = "lua/test_upb", -# luadeps = ["lua/upb"], -# luamain = "tests/bindings/lua/test_upb.lua", -#) - # Test the CMake build ######################################################### filegroup( diff --git a/bazel/build_defs.bzl b/bazel/build_defs.bzl index 67a79d482e..7544e12517 100644 --- a/bazel/build_defs.bzl +++ b/bazel/build_defs.bzl @@ -39,42 +39,6 @@ def _get_real_roots(files): roots[real_root] = True return roots.keys() -def lua_cclibrary(name, srcs, hdrs = [], deps = []): - lib_rule = name + "_lib" - so_rule = "lib" + name + ".so" - so_file = _remove_prefix(name, "lua/") + ".so" - - native.cc_library( - name = _librule(name), - hdrs = hdrs, - srcs = srcs, - deps = deps + ["@lua//:liblua_headers"], - ) - - native.cc_binary( - name = so_rule, - linkshared = True, - deps = [_librule(name)], - linkopts = select({ - ":darwin": [ - "-undefined dynamic_lookup", - ], - "//conditions:default": [], - }), - ) - - native.genrule( - name = name + "_copy", - srcs = [":" + so_rule], - outs = [so_file], - cmd = "cp $< $@", - ) - - native.filegroup( - name = name, - data = [so_file], - ) - def _remove_prefix(str, prefix): if not str.startswith(prefix): fail("%s doesn't start with %s" % (str, prefix)) @@ -85,20 +49,6 @@ def _remove_suffix(str, suffix): fail("%s doesn't end with %s" % (str, suffix)) return str[:-len(suffix)] -def lua_library(name, srcs, strip_prefix, luadeps = []): - outs = [_remove_prefix(src, strip_prefix + "/") for src in srcs] - native.genrule( - name = name + "_copy", - srcs = srcs, - outs = outs, - cmd = "cp $(SRCS) $(@D)", - ) - - native.filegroup( - name = name, - data = outs + luadeps, - ) - def make_shell_script(name, contents, out): contents = (runfiles_init + contents).replace("$", "$$") native.genrule( @@ -107,38 +57,6 @@ def make_shell_script(name, contents, out): cmd = "(cat <<'HEREDOC'\n%s\nHEREDOC\n) > $@" % contents, ) -def _lua_binary_or_test(name, luamain, luadeps, rule): - script = name + ".sh" - - make_shell_script( - name = "gen_" + name, - out = script, - contents = """ -BASE=$(dirname $(rlocation upb/upb_c.so)) -export LUA_CPATH="$BASE/?.so" -export LUA_PATH="$BASE/?.lua" -LUA=$(rlocation lua/lua) -MAIN=$(rlocation upb/%s) -$LUA $MAIN -""" % luamain, - ) - - rule( - name = name, - srcs = [script], - data = [ - "@lua//:lua", - luamain - ] + luadeps, - deps = ["@bazel_tools//tools/bash/runfiles"], - ) - -def lua_binary(name, luamain, luadeps = []): - _lua_binary_or_test(name, luamain, luadeps, native.sh_binary) - -def lua_test(name, luamain, luadeps = []): - _lua_binary_or_test(name, luamain, luadeps, native.sh_test) - def generated_file_staleness_test(name, outs, generated_pattern): """Tests that checked-in file(s) match the contents of generated file(s). diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index 0583aa9341..7830ce7a20 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -16,6 +16,8 @@ function iter_to_array(iter) return arr end +--[[ + function test_msgdef() local f2 = upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} local o = upb.OneofDef{name = "field1", fields = {f2}} @@ -743,6 +745,23 @@ function test_finalizer() collectgarbage() end +--]] + +function test_foo() + local symtab = upb.SymbolTable() + local filename = "external/com_google_protobuf/descriptor_proto-descriptor-set.proto.bin" + local file = io.open(filename, "rb") or io.open("bazel-bin/" .. filename, "rb") + assert_not_nil(file) + local descriptor = file:read("*a") + assert_true(#descriptor > 0) + symtab:add_set(descriptor) + local FileDescriptorSet = symtab:lookup_msg("google.protobuf.FileDescriptorSet") + assert_not_nil(FileDescriptorSet) + set = FileDescriptorSet() + assert_equal(#set.file, 0) + assert_error_match("lupb.array expected", function () set.file = 1 end) +end + local stats = lunit.main() if stats.failed > 0 or stats.errors > 0 then diff --git a/upb/bindings/lua/def.c b/upb/bindings/lua/def.c index 75b49762d9..5889cd518d 100644 --- a/upb/bindings/lua/def.c +++ b/upb/bindings/lua/def.c @@ -50,9 +50,17 @@ static void lupb_wrapper_pushwrapper(lua_State *L, int narg, const void *def, lua_replace(L, -2); /* Remove symtab from stack. */ } -void lupb_msgdef_pushmsgdef(lua_State *L, int narg, const upb_fielddef *f) { +/* lupb_msgdef_pushsubmsgdef() + * + * Pops the msgdef wrapper at the top of the stack and replaces it with a msgdef + * wrapper for field |f| of this msgdef. + */ +void lupb_msgdef_pushsubmsgdef(lua_State *L, const upb_fielddef *f) { + assert(luaL_testudata(L, -1, LUPB_MSGDEF)); const upb_msgdef *m = upb_fielddef_msgsubdef(f); - lupb_wrapper_pushwrapper(L, narg, m, LUPB_MSGDEF); + assert(upb_fielddef_containingtype(f) == lupb_msgdef_check(L, -1)); + lupb_wrapper_pushwrapper(L, -1, m, LUPB_MSGDEF); + lua_replace(L, -2); /* Replace msgdef with submsgdef. */ } /* lupb_fielddef **************************************************************/ @@ -611,6 +619,8 @@ upb_symtab *lupb_symtab_check(lua_State *L, int narg) { void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, const char *type) { + assert(luaL_testudata(L, narg, LUPB_SYMTAB)); + if (def == NULL) { lua_pushnil(L); return; @@ -624,7 +634,7 @@ void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, /* Stack is now: cache, cached value. */ if (lua_isnil(L, -1)) { /* Create new wrapper. */ - lupb_wrapper *w = lua_newuserdata(L, sizeof(*w)); + lupb_wrapper *w = lupb_newuserdata(L, sizeof(*w), 1, type); w->def = def; lua_replace(L, -2); /* Replace nil */ @@ -632,10 +642,6 @@ void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, lua_pushvalue(L, narg); lua_setiuservalue(L, -2, LUPB_SYMTAB_INDEX); - /* Set metatable of wrapper. */ - luaL_getmetatable(L, type); - lua_setmetatable(L, -2); - /* Add wrapper to the the cache. */ lua_pushvalue(L, -1); lua_rawsetp(L, -3, def); @@ -650,12 +656,9 @@ void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, * upb.SymbolTable() -> */ static int lupb_symtab_new(lua_State *L) { - lupb_symtab *lsymtab = lua_newuserdata(L, sizeof(*lsymtab)); + lupb_symtab *lsymtab = lupb_newuserdata(L, sizeof(*lsymtab), 1, LUPB_SYMTAB); lsymtab->symtab = upb_symtab_new(); - luaL_getmetatable(L, LUPB_SYMTAB); - lua_setmetatable(L, -2); - /* Create our object cache. */ lua_newtable(L); @@ -678,7 +681,28 @@ static int lupb_symtab_gc(lua_State *L) { return 0; } -static int lupb_symtab_add(lua_State *L) { +static int lupb_symtab_addfile(lua_State *L) { + size_t len; + upb_symtab *s = lupb_symtab_check(L, 1); + const char *str = luaL_checklstring(L, 2, &len); + upb_arena *arena = lupb_arena_pushnew(L);; + const google_protobuf_FileDescriptorProto *file; + upb_status status; + + upb_status_clear(&status); + file = google_protobuf_FileDescriptorProto_parse(str, len, arena); + + if (!file) { + luaL_argerror(L, 2, "failed to parse descriptor"); + } + + upb_symtab_addfile(s, file, &status); + lupb_checkstatus(L, &status); + + return 0; +} + +static int lupb_symtab_addset(lua_State *L) { size_t i, n, len; const google_protobuf_FileDescriptorProto *const *files; google_protobuf_FileDescriptorSet *set; @@ -718,7 +742,8 @@ static int lupb_symtab_lookupenum(lua_State *L) { } static const struct luaL_Reg lupb_symtab_m[] = { - {"add", lupb_symtab_add}, + {"add_file", lupb_symtab_addfile}, + {"add_set", lupb_symtab_addset}, {"lookup_msg", lupb_symtab_lookupmsg}, {"lookup_enum", lupb_symtab_lookupenum}, {NULL, NULL} diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index f1cd2db0db..511a2f4f2e 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -193,7 +193,7 @@ upb_arena *lupb_arena_pushnew(lua_State *L) { /* Create arena group table and add this arena to it. */ lua_createtable(L, 0, 1); lua_pushvalue(L, -2); - lua_rawseti(L, -3, 1); + lua_rawseti(L, -2, 1); /* Set arena group as this object's userval. */ lua_setiuservalue(L, -2, LUPB_ARENAGROUP_INDEX); @@ -681,7 +681,7 @@ static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val) { */ static bool lupb_msg_lazycreate(lua_State *L, int narg, const upb_fielddef *f, upb_msgval* val) { - if (val->msg_val == NULL && !upb_fielddef_isseq(f)) { + if (val->msg_val == NULL && upb_fielddef_isseq(f)) { upb_msg *msg = lupb_msg_check(L, narg); upb_arena *arena = lupb_arenaget(L, narg); upb_mutmsgval mutval = upb_msg_mutable(msg, f, arena); @@ -703,7 +703,8 @@ static void *lupb_msg_newud(lua_State *L, int narg, size_t size, if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) { /* Wrapper needs a reference to the msgdef. */ void* ud = lupb_newuserdata(L, size, 2, type); - lupb_msgdef_pushmsgdef(L, narg, f); + lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX); + lupb_msgdef_pushsubmsgdef(L, f); lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); return ud; } else { @@ -752,8 +753,7 @@ static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg, /* Typecheck this map's msgdef against this message field. */ lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX); lua_getiuservalue(L, msgarg, LUPB_MSGDEF_INDEX); - lupb_msgdef_pushmsgdef(L, -1, f); - lua_replace(L, -2); /* replace msg msgdef, leaving only map and field. */ + lupb_msgdef_pushsubmsgdef(L, f); luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch"); lua_pop(L, 2); } diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h index 4040607994..02ed341098 100644 --- a/upb/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h @@ -69,7 +69,7 @@ const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg); const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg); upb_symtab *lupb_symtab_check(lua_State *L, int narg); -void lupb_msgdef_pushmsgdef(lua_State *L, int narg, const upb_fielddef *f); +void lupb_msgdef_pushsubmsgdef(lua_State *L, const upb_fielddef *f); void lupb_def_registertypes(lua_State *L); diff --git a/upb/def.c b/upb/def.c index fedd52ea90..994d74d7df 100644 --- a/upb/def.c +++ b/upb/def.c @@ -884,6 +884,8 @@ static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { return ret; } +/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. + * It computes a dynamic layout for all of the fields in |m|. */ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { upb_msglayout *l = (upb_msglayout*)m->layout; upb_msg_field_iter it; @@ -923,13 +925,17 @@ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { for (upb_msg_field_begin(&it, m), hasbit = 0; !upb_msg_field_done(&it); upb_msg_field_next(&it)) { - const upb_fielddef* f = upb_msg_iter_field(&it); + upb_fielddef* f = upb_msg_iter_field(&it); upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; field->number = upb_fielddef_number(f); field->descriptortype = upb_fielddef_descriptortype(f); field->label = upb_fielddef_label(f); + /* TODO: we probably should sort the fields by field number to match the + * output of upbc, and to improve search speed for the table parser. */ + f->layout_index = f->index_; + if (upb_fielddef_issubmsg(f)) { const upb_msgdef *subm = upb_fielddef_msgsubdef(f); field->submsg_index = submsg_count++; @@ -1304,6 +1310,21 @@ static bool create_fielddef( field_number); return false; } + + if (ctx->layouts) { + const upb_msglayout_field *fields = m->layout->fields; + int count = m->layout->field_count; + bool found = false; + int i; + for (i = 0; i < count; i++) { + if (fields[i].number == field_number) { + f->layout_index = i; + found = true; + break; + } + } + assert(found); + } } else { /* extension field. */ f = (upb_fielddef*)&ctx->file->exts[ctx->file->ext_count]; From ae66e571d4796c49efaa24ee8a834a07bb279678 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 4 Dec 2019 18:23:06 -0800 Subject: [PATCH 15/35] Fixed some bugs and added a few more tests. --- tests/bindings/lua/test_upb.lua | 4 ++ upb/bindings/lua/msg.c | 72 ++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index 7830ce7a20..074ed57fc9 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -760,6 +760,10 @@ function test_foo() set = FileDescriptorSet() assert_equal(#set.file, 0) assert_error_match("lupb.array expected", function () set.file = 1 end) + + set = upb.decode(FileDescriptorSet, descriptor) + assert_equal(#set.file, 1) + assert_equal(set.file[1].name, "google/protobuf/descriptor.proto") end local stats = lunit.main() diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 511a2f4f2e..a64a0e0a6f 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -201,6 +201,11 @@ upb_arena *lupb_arena_pushnew(lua_State *L) { return a->arena; } +/** + * lupb_arena_merge() + * + * Merges |from| into |to| so that there is a single arena group that contains + * both, and both arenas will point at this new table. */ void lupb_arena_merge(lua_State *L, int to, int from) { int i, from_count, to_count; lua_getiuservalue(L, to, LUPB_ARENAGROUP_INDEX); @@ -226,6 +231,23 @@ void lupb_arena_merge(lua_State *L, int to, int from) { lua_setiuservalue(L, from, LUPB_ARENAGROUP_INDEX); } +/** + * lupb_arena_addobj() + * + * Creates a reference from the arena in |narg| to the object at the top of the + * stack, and pops it. This will guarantee that the object lives as long as + * the arena. + * + * This is mainly useful for pinning strings we have parsed protobuf data from. + * It will allow us to point directly to string data in the original string. */ +void lupb_arena_addobj(lua_State *L, int narg) { + lua_getiuservalue(L, narg, LUPB_ARENAGROUP_INDEX); + int n = lua_rawlen(L, -1); + lua_pushvalue(L, -2); + lua_rawseti(L, -2, n + 1); + lua_pop(L, 2); /* obj, arena group. */ +} + static int lupb_arena_gc(lua_State *L) { upb_arena *a = lupb_arena_check(L, 1); upb_arena_free(a); @@ -356,7 +378,7 @@ static void lupb_pushmsgval(lua_State *L, int container, upb_fieldtype_t type, lupb_msg_newmsgwrapper(L, container, val); lupb_cacheset(L, val.msg_val); } - break; /* Shouldn't call this function. */ + return; } LUPB_UNREACHABLE(); } @@ -865,44 +887,64 @@ static const struct luaL_Reg lupb_msg_mm[] = { /* lupb_msg toplevel **********************************************************/ -#if 0 static int lupb_decode(lua_State *L) { size_t len; - const upb_msglayout *layout; - upb_msg *msg = lupb_msg_checkmsg(L, 1); + const upb_msgdef *m = lupb_msgdef_check(L, 1); const char *pb = lua_tolstring(L, 2, &len); + const upb_msglayout *layout = upb_msgdef_layout(m); + upb_msg *msg; + upb_arena *arena; + bool ok; - upb_decode(pb, len, msg, layout, lupb_arenaget(L, 1)); - /* TODO(haberman): check for error. */ + lupb_msg_pushnew(L); + msg = lupb_msg_check(L, -1); - return 0; + lua_getiuservalue(L, -1, LUPB_ARENA_INDEX); + arena = lupb_arena_check(L, -1); + + /* Pin string data so we can reference it. */ + lua_pushvalue(L, 2); + lupb_arena_addobj(L, -2); + lua_pop(L, 1); + + ok = upb_decode(pb, len, msg, layout, arena); + + if (!ok) { + lua_pushstring(L, "Error decoding protobuf."); + return lua_error(L); + } + + return 1; } static int lupb_encode(lua_State *L) { + const upb_msg *msg = lupb_msg_check(L, 1); const upb_msglayout *layout; - const upb_msg *msg = lupb_msg_checkmsg(L, 1); - upb_arena *arena = upb_arena_new(); + upb_arena *arena = lupb_arena_pushnew(L); size_t size; char *result; + lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX); + layout = upb_msgdef_layout(lupb_msgdef_check(L, -1)); + lua_pop(L, 1); + result = upb_encode(msg, (const void*)layout, arena, &size); - /* Free resources before we potentially bail on error. */ + if (!result) { + lua_pushstring(L, "Error encoding protobuf."); + return lua_error(L); + } + lua_pushlstring(L, result, size); - upb_arena_free(arena); - /* TODO(haberman): check for error. */ return 1; } -#endif static const struct luaL_Reg lupb_msg_toplevel_m[] = { {"Array", lupb_array_new}, {"Map", lupb_map_new}, -#if 0 {"decode", lupb_decode}, {"encode", lupb_encode}, -#endif {NULL, NULL} }; From d6c3152c0bf2acfd5273976c2534b8709212093d Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 4 Dec 2019 23:15:05 -0800 Subject: [PATCH 16/35] Added more Lua tests that are passing. Also ripped out the ctype checking in upb_table, it was not helpful (didn't help catch bugs) but was causing problems. --- tests/bindings/lua/main.c | 26 ++- tests/bindings/lua/test_upb.lua | 295 +++++++++++++++++--------------- upb/bindings/lua/msg.c | 2 +- upb/msg.c | 2 +- upb/table.c | 58 ++----- upb/table.int.h | 46 +---- 6 files changed, 208 insertions(+), 221 deletions(-) diff --git a/tests/bindings/lua/main.c b/tests/bindings/lua/main.c index 379e6ded20..f8fe502e73 100644 --- a/tests/bindings/lua/main.c +++ b/tests/bindings/lua/main.c @@ -2,23 +2,43 @@ #include #include #include +#include #include "upb/bindings/lua/upb.h" +lua_State *L; + +static void interrupt(lua_State *L, lua_Debug *ar) { + (void)ar; + lua_sethook(L, NULL, 0, 0); + luaL_error(L, "SIGINT"); +} + +static void sighandler(int i) { + fprintf(stderr, "Signal!\n"); + signal(i, SIG_DFL); + lua_sethook(L, interrupt, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + const char *init = "package.preload['lupb'] = ... " "package.path = './?.lua;./third_party/lunit/?.lua'"; int main() { int ret = 0; - lua_State *L = luaL_newstate(); + L = luaL_newstate(); luaL_openlibs(L); lua_pushcfunction(L, luaopen_lupb); ret = luaL_loadstring(L, init); lua_pushcfunction(L, luaopen_lupb); - if (ret || lua_pcall(L, 1, LUA_MULTRET, 0) || - luaL_dofile(L, "tests/bindings/lua/test_upb.lua")) { + signal(SIGINT, sighandler); + ret = ret || + lua_pcall(L, 1, LUA_MULTRET, 0) || + luaL_dofile(L, "tests/bindings/lua/test_upb.lua"); + signal(SIGINT, SIG_DFL); + + if (ret) { fprintf(stderr, "error testing Lua: %s\n", lua_tostring(L, -1)); ret = 1; } diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index 074ed57fc9..0a1ef632b6 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -405,122 +405,6 @@ function test_symtab() assert_equal(msgdef3:field("field5"):subdef(), msgdef2) end -function test_numeric_array() - local function test_for_numeric_type(upb_type, val, too_big, too_small, bad3) - local array = upb.Array(upb_type) - assert_equal(0, #array) - - -- 0 is never a valid index in Lua. - assert_error_match("array index", function() return array[0] end) - -- Past the end of the array. - assert_error_match("array index", function() return array[1] end) - - array[1] = val - assert_equal(val, array[1]) - assert_equal(1, #array) - assert_equal(val, array[1]) - -- Past the end of the array. - assert_error_match("array index", function() return array[2] end) - - array[2] = 10 - assert_equal(val, array[1]) - assert_equal(10, array[2]) - assert_equal(2, #array) - -- Past the end of the array. - assert_error_match("array index", function() return array[3] end) - - local n = 1 - for i, val in upb.ipairs(array) do - assert_equal(n, i) - n = n + 1 - assert_equal(array[i], val) - end - - -- Values that are out of range. - local errmsg = "not an integer or out of range" - if too_small then - assert_error_match(errmsg, function() array[3] = too_small end) - end - if too_big then - assert_error_match(errmsg, function() array[3] = too_big end) - end - if bad3 then - assert_error_match(errmsg, function() array[3] = bad3 end) - end - - -- Can't assign other Lua types. - errmsg = "bad argument #3" - assert_error_match(errmsg, function() array[3] = "abc" end) - assert_error_match(errmsg, function() array[3] = true end) - assert_error_match(errmsg, function() array[3] = false end) - assert_error_match(errmsg, function() array[3] = nil end) - assert_error_match(errmsg, function() array[3] = {} end) - assert_error_match(errmsg, function() array[3] = print end) - assert_error_match(errmsg, function() array[3] = array end) - end - - -- in-range of 64-bit types but not exactly representable as double - local bad64 = 2^68 - 1 - - test_for_numeric_type(upb.TYPE_UINT32, 2^32 - 1, 2^32, -1, 5.1) - test_for_numeric_type(upb.TYPE_UINT64, 2^63, 2^64, -1, bad64) - test_for_numeric_type(upb.TYPE_INT32, 2^31 - 1, 2^31, -2^31 - 1, 5.1) - -- Enums don't exist at a language level in Lua, so we just represent enum - -- values as int32s. - test_for_numeric_type(upb.TYPE_ENUM, 2^31 - 1, 2^31, -2^31 - 1, 5.1) - test_for_numeric_type(upb.TYPE_INT64, 2^62, 2^63, -2^64, bad64) - test_for_numeric_type(upb.TYPE_FLOAT, 340282306073709652508363335590014353408) - test_for_numeric_type(upb.TYPE_DOUBLE, 10^101) -end - -function test_string_array() - local function test_for_string_type(upb_type) - local array = upb.Array(upb_type) - assert_equal(0, #array) - - -- 0 is never a valid index in Lua. - assert_error_match("array index", function() return array[0] end) - -- Past the end of the array. - assert_error_match("array index", function() return array[1] end) - - array[1] = "foo" - assert_equal("foo", array[1]) - assert_equal(1, #array) - -- Past the end of the array. - assert_error_match("array index", function() return array[2] end) - - local array2 = upb.Array(upb_type) - assert_equal(0, #array2) - - array[2] = "bar" - assert_equal("foo", array[1]) - assert_equal("bar", array[2]) - assert_equal(2, #array) - -- Past the end of the array. - assert_error_match("array index", function() return array[3] end) - - local n = 1 - for i, val in upb.ipairs(array) do - assert_equal(n, i) - n = n + 1 - assert_equal(array[i], val) - end - assert_equal(3, n) - - -- Can't assign other Lua types. - assert_error_match("Expected string", function() array[3] = 123 end) - assert_error_match("Expected string", function() array[3] = true end) - assert_error_match("Expected string", function() array[3] = false end) - assert_error_match("Expected string", function() array[3] = nil end) - assert_error_match("Expected string", function() array[3] = {} end) - assert_error_match("Expected string", function() array[3] = print end) - assert_error_match("Expected string", function() array[3] = array end) - end - - test_for_string_type(upb.TYPE_STRING) - test_for_string_type(upb.TYPE_BYTES) -end - function test_msg_primitives() local function test_for_numeric_type(upb_type, val, too_big, too_small, bad3) local symtab = upb.SymbolTable{ @@ -699,6 +583,8 @@ function test_msg_submsg() assert_error_match("msg expected", function() msg.submsg = print end) end +--]] + -- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer -- can be defined in Lua. if _VERSION >= 'Lua 5.2' then @@ -719,33 +605,174 @@ function test_finalizer() defer(function() assert_error_match("called into dead object", function() -- Generic def call. - t[1]:full_name() - end) - assert_error_match("called into dead object", function() - -- Specific msgdef call. - t[1]:add() - end) - assert_error_match("called into dead object", function() - t[2]:values() - end) - assert_error_match("called into dead object", function() - t[3]:number() - end) - assert_error_match("called into dead object", function() - t[4]:lookup() + t[1]:lookup_msg("abc") end) end) t = { - upb.MessageDef(), - upb.EnumDef(), - upb.FieldDef(), upb.SymbolTable(), } end collectgarbage() end ---]] +-- in-range of 64-bit types but not exactly representable as double +local bad64 = 2^68 - 1 + +local numeric_types = { + [upb.TYPE_UINT32] = { + valid_val = 2^32 - 1, + too_big = 2^32, + too_small = -1, + other_bad = 5.1 + }, + [upb.TYPE_UINT64] = { + valid_val = 2^63, + too_big = 2^64, + too_small = -1, + other_bad = bad64 + }, + [upb.TYPE_INT32] = { + valid_val = 2^31 - 1, + too_big = 2^31, + too_small = -2^31 - 1, + other_bad = 5.1 + }, + -- Enums don't exist at a language level in Lua, so we just represent enum + -- values as int32s. + [upb.TYPE_ENUM] = { + valid_val = 2^31 - 1, + too_big = 2^31, + too_small = -2^31 - 1, + other_bad = 5.1 + }, + [upb.TYPE_INT64] = { + valid_val = 2^62, + too_big = 2^63, + too_small = -2^64, + other_bad = bad64 + }, + [upb.TYPE_FLOAT] = { + valid_val = 340282306073709652508363335590014353408 + }, + [upb.TYPE_DOUBLE] = { + valid_val = 10^101 + }, +} + +function test_string_array() + local function test_for_string_type(upb_type) + local array = upb.Array(upb_type) + assert_equal(0, #array) + + -- 0 is never a valid index in Lua. + assert_error_match("array index", function() return array[0] end) + -- Past the end of the array. + assert_error_match("array index", function() return array[1] end) + + array[1] = "foo" + assert_equal("foo", array[1]) + assert_equal(1, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[2] end) + + local array2 = upb.Array(upb_type) + assert_equal(0, #array2) + + array[2] = "bar" + assert_equal("foo", array[1]) + assert_equal("bar", array[2]) + assert_equal(2, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[3] end) + + -- Can't assign other Lua types. + assert_error_match("Expected string", function() array[3] = 123 end) + assert_error_match("Expected string", function() array[3] = true end) + assert_error_match("Expected string", function() array[3] = false end) + assert_error_match("Expected string", function() array[3] = nil end) + assert_error_match("Expected string", function() array[3] = {} end) + assert_error_match("Expected string", function() array[3] = print end) + assert_error_match("Expected string", function() array[3] = array end) + end + + test_for_string_type(upb.TYPE_STRING) + test_for_string_type(upb.TYPE_BYTES) +end + +function test_numeric_array() + local function test_for_numeric_type(upb_type) + local array = upb.Array(upb_type) + local vals = numeric_types[upb_type] + assert_equal(0, #array) + + -- 0 is never a valid index in Lua. + assert_error_match("array index", function() return array[0] end) + -- Past the end of the array. + assert_error_match("array index", function() return array[1] end) + + array[1] = vals.valid_val + assert_equal(vals.valid_val, array[1]) + assert_equal(1, #array) + assert_equal(vals.valid_val, array[1]) + -- Past the end of the array. + assert_error_match("array index", function() return array[2] end) + + array[2] = 10 + assert_equal(vals.valid_val, array[1]) + assert_equal(10, array[2]) + assert_equal(2, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[3] end) + + -- Values that are out of range. + local errmsg = "not an integer or out of range" + if vals.too_small then + assert_error_match(errmsg, function() array[3] = vals.too_small end) + end + if vals.too_big then + assert_error_match(errmsg, function() array[3] = vals.too_big end) + end + if vals.other_bad then + assert_error_match(errmsg, function() array[3] = vals.other_bad end) + end + + -- Can't assign other Lua types. + errmsg = "bad argument #3" + assert_error_match(errmsg, function() array[3] = "abc" end) + assert_error_match(errmsg, function() array[3] = true end) + assert_error_match(errmsg, function() array[3] = false end) + assert_error_match(errmsg, function() array[3] = nil end) + assert_error_match(errmsg, function() array[3] = {} end) + assert_error_match(errmsg, function() array[3] = print end) + assert_error_match(errmsg, function() array[3] = array end) + end + + for k in pairs(numeric_types) do + test_for_numeric_type(k) + end +end + +function test_numeric_map() + local function test_for_numeric_types(key_type, val_type) + local map = upb.Map(key_type, val_type) + local key_vals = numeric_types[key_type] + local val_vals = numeric_types[val_type] + + assert_equal(0, #map) + + -- Unset keys return nil + assert_nil(map[key_vals.valid_val]) + + map[key_vals.valid_val] = val_vals.valid_val + assert_equal(1, #map) + end + + for k in pairs(numeric_types) do + for v in pairs(numeric_types) do + test_for_numeric_types(k, v) + end + end +end function test_foo() local symtab = upb.SymbolTable() diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index a64a0e0a6f..8fd5a2bfd3 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -510,7 +510,7 @@ typedef struct { #define MAP_MSGDEF_INDEX 1 static lupb_map *lupb_map_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, LUPB_ARRAY); + return luaL_checkudata(L, narg, LUPB_MAP); } /* lupb_map Public API */ diff --git a/upb/msg.c b/upb/msg.c index ccdf1a4863..cd33e0cca6 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -197,7 +197,7 @@ upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, return NULL; } - upb_strtable_init(&map->table, UPB_CTYPE_INT32); + upb_strtable_init2(&map->table, UPB_CTYPE_INT32, upb_arena_alloc(a)); map->key_size_lg2 = _upb_fieldtype_to_mapsizelg2[key_type]; map->val_size_lg2 = _upb_fieldtype_to_mapsizelg2[value_type]; diff --git a/upb/table.c b/upb/table.c index cf8b5c8675..63389c0144 100644 --- a/upb/table.c +++ b/upb/table.c @@ -16,12 +16,6 @@ #define ARRAY_SIZE(x) \ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) -static void upb_check_alloc(upb_table *t, upb_alloc *a) { - UPB_UNUSED(t); - UPB_UNUSED(a); - UPB_ASSERT_DEBUGVAR(t->alloc == a); -} - static const double MAX_LOAD = 0.85; /* The minimum utilization of the array part of a mixed hash/array table. This @@ -100,17 +94,12 @@ static bool isfull(upb_table *t) { } } -static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2, - upb_alloc *a) { +static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { size_t bytes; t->count = 0; - t->ctype = ctype; t->size_lg2 = size_lg2; t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; -#ifndef NDEBUG - t->alloc = a; -#endif bytes = upb_table_size(t) * sizeof(upb_tabent); if (bytes > 0) { t->entries = upb_malloc(a, bytes); @@ -123,7 +112,6 @@ static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2, } static void uninit(upb_table *t, upb_alloc *a) { - upb_check_alloc(t, a); upb_free(a, mutable_entries(t)); } @@ -159,7 +147,7 @@ static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v, const upb_tabent *e = findentry(t, key, hash, eql); if (e) { if (v) { - _upb_value_setval(v, e->val.val, t->ctype); + _upb_value_setval(v, e->val.val); } return true; } else { @@ -175,7 +163,6 @@ static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, upb_tabent *our_e; UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - UPB_ASSERT_DEBUGVAR(val.ctype == t->ctype); t->count++; mainpos_e = getentry_mutable(t, hash); @@ -221,7 +208,7 @@ static bool rm(upb_table *t, lookupkey_t key, upb_value *val, if (eql(chain->key, key)) { /* Element to remove is at the head of its chain. */ t->count--; - if (val) _upb_value_setval(val, chain->val.val, t->ctype); + if (val) _upb_value_setval(val, chain->val.val); if (removed) *removed = chain->key; if (chain->next) { upb_tabent *move = (upb_tabent*)chain->next; @@ -241,7 +228,7 @@ static bool rm(upb_table *t, lookupkey_t key, upb_value *val, /* Found element to remove. */ upb_tabent *rm = (upb_tabent*)chain->next; t->count--; - if (val) _upb_value_setval(val, chain->next->val.val, t->ctype); + if (val) _upb_value_setval(val, chain->next->val.val); if (removed) *removed = rm->key; rm->key = 0; /* Make the slot empty. */ chain->next = rm->next; @@ -294,7 +281,7 @@ static bool streql(upb_tabkey k1, lookupkey_t k2) { } bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) { - return init(&t->t, ctype, 2, a); + return init(&t->t, 2, a); } void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) { @@ -308,9 +295,7 @@ bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { upb_strtable new_table; upb_strtable_iter i; - upb_check_alloc(&t->t, a); - - if (!init(&new_table.t, t->t.ctype, size_lg2, a)) + if (!init(&new_table.t, size_lg2, a)) return false; upb_strtable_begin(&i, t); for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { @@ -330,8 +315,6 @@ bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, upb_tabkey tabkey; uint32_t hash; - upb_check_alloc(&t->t, a); - if (isfull(&t->t)) { /* Need to resize. New table of double the size, add old elements to it. */ if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { @@ -398,7 +381,7 @@ upb_strview upb_strtable_iter_key(const upb_strtable_iter *i) { upb_value upb_strtable_iter_value(const upb_strtable_iter *i) { UPB_ASSERT(!upb_strtable_done(i)); - return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype); + return _upb_value_val(str_tabent(i)->val.val); } void upb_strtable_iter_setdone(upb_strtable_iter *i) { @@ -464,11 +447,11 @@ static void check(upb_inttable *t) { #endif } -bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, - size_t asize, int hsize_lg2, upb_alloc *a) { +bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, + upb_alloc *a) { size_t array_bytes; - if (!init(&t->t, ctype, hsize_lg2, a)) return false; + if (!init(&t->t, hsize_lg2, a)) return false; /* Always make the array part at least 1 long, so that we know key 0 * won't be in the hash part, which simplifies things. */ t->array_size = UPB_MAX(1, asize); @@ -485,7 +468,7 @@ bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, } bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) { - return upb_inttable_sizedinit(t, ctype, 0, 4, a); + return upb_inttable_sizedinit(t, 0, 4, a); } void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) { @@ -499,8 +482,6 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, tabval.val = val.val; UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ - upb_check_alloc(&t->t, a); - if (key < t->array_size) { UPB_ASSERT(!upb_arrhas(t->array[key])); t->array_count++; @@ -511,7 +492,7 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, size_t i; upb_table new_table; - if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1, a)) { + if (!init(&new_table, t->t.size_lg2 + 1, a)) { return false; } @@ -520,7 +501,7 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, uint32_t hash; upb_value v; - _upb_value_setval(&v, e->val.val, t->t.ctype); + _upb_value_setval(&v, e->val.val); hash = upb_inthash(e->key); insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); } @@ -539,7 +520,7 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) { const upb_tabval *table_v = inttable_val_const(t, key); if (!table_v) return false; - if (v) _upb_value_setval(v, table_v->val, t->t.ctype); + if (v) _upb_value_setval(v, table_v->val); return true; } @@ -557,7 +538,7 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; t->array_count--; if (val) { - _upb_value_setval(val, t->array[key].val, t->t.ctype); + _upb_value_setval(val, t->array[key].val); } mutable_array(t)[key] = empty; success = true; @@ -572,7 +553,6 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { } bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) { - upb_check_alloc(&t->t, a); return upb_inttable_insert2(t, upb_inttable_count(t), val, a); } @@ -585,7 +565,6 @@ upb_value upb_inttable_pop(upb_inttable *t) { bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, upb_alloc *a) { - upb_check_alloc(&t->t, a); return upb_inttable_insert2(t, (uintptr_t)key, val, a); } @@ -610,8 +589,6 @@ void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { int size_lg2; upb_inttable new_t; - upb_check_alloc(&t->t, a); - upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t key = upb_inttable_iter_key(&i); @@ -644,7 +621,7 @@ void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; int hashsize_lg2 = log2ceil(hash_size); - upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2, a); + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t k = upb_inttable_iter_key(&i); @@ -710,8 +687,7 @@ uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) { upb_value upb_inttable_iter_value(const upb_inttable_iter *i) { UPB_ASSERT(!upb_inttable_done(i)); return _upb_value_val( - i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val, - i->t->t.ctype); + i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val); } void upb_inttable_iter_setdone(upb_inttable_iter *i) { diff --git a/upb/table.int.h b/upb/table.int.h index d3c2bc7716..d571a3498a 100644 --- a/upb/table.int.h +++ b/upb/table.int.h @@ -52,19 +52,8 @@ typedef enum { typedef struct { uint64_t val; -#ifndef NDEBUG - /* In debug mode we carry the value type around also so we can check accesses - * to be sure the right member is being read. */ - upb_ctype_t ctype; -#endif } upb_value; -#ifdef NDEBUG -#define SET_TYPE(dest, val) UPB_UNUSED(val) -#else -#define SET_TYPE(dest, val) dest = val -#endif - /* 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, @@ -75,15 +64,13 @@ UPB_INLINE char *upb_gstrdup(const char *s) { return upb_strdup(s, &upb_alloc_global); } -UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val, - upb_ctype_t ctype) { +UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val) { v->val = val; - SET_TYPE(v->ctype, ctype); } -UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) { +UPB_INLINE upb_value _upb_value_val(uint64_t val) { upb_value ret; - _upb_value_setval(&ret, val, ctype); + _upb_value_setval(&ret, val); return ret; } @@ -98,7 +85,6 @@ UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) { #define FUNCS(name, membername, type_t, converter, proto_type) \ UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \ val->val = (converter)cval; \ - SET_TYPE(val->ctype, proto_type); \ } \ UPB_INLINE upb_value upb_value_ ## name(type_t val) { \ upb_value ret; \ @@ -106,7 +92,6 @@ UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) { return ret; \ } \ UPB_INLINE type_t upb_value_get ## name(upb_value val) { \ - UPB_ASSERT_DEBUGVAR(val.ctype == proto_type); \ return (type_t)(converter)val.val; \ } @@ -124,12 +109,10 @@ FUNCS(fptr, fptr, upb_func*, uintptr_t, UPB_CTYPE_FPTR) UPB_INLINE void upb_value_setfloat(upb_value *val, float cval) { memcpy(&val->val, &cval, sizeof(cval)); - SET_TYPE(val->ctype, UPB_CTYPE_FLOAT); } UPB_INLINE void upb_value_setdouble(upb_value *val, double cval) { memcpy(&val->val, &cval, sizeof(cval)); - SET_TYPE(val->ctype, UPB_CTYPE_DOUBLE); } UPB_INLINE upb_value upb_value_float(float cval) { @@ -173,7 +156,6 @@ typedef struct { #define UPB_TABVALUE_EMPTY_INIT {-1} - /* upb_table ******************************************************************/ typedef struct _upb_tabent { @@ -190,7 +172,6 @@ typedef struct _upb_tabent { typedef struct { size_t count; /* Number of entries in the hash part. */ size_t mask; /* Mask to turn hash value -> bucket. */ - upb_ctype_t ctype; /* Type of all values. */ uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ /* Hash table entries. @@ -200,17 +181,6 @@ typedef struct { * initialize const hash tables. Then we cast away const when we have to. */ const upb_tabent *entries; - -#ifndef NDEBUG - /* This table's allocator. We make the user pass it in to every relevant - * function and only use this to check it in debug mode. We do this solely - * to keep upb_table as small as possible. This might seem slightly paranoid - * but the plan is to use upb_table for all map fields and extension sets in - * a forthcoming message representation, so there could be a lot of these. - * If this turns out to be too annoying later, we can change it (since this - * is an internal-only header file). */ - upb_alloc *alloc; -#endif } upb_table; typedef struct { @@ -224,12 +194,6 @@ typedef struct { size_t array_count; /* Array part number of elements. */ } upb_inttable; -#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \ - {UPB_TABLE_INIT(count, mask, ctype, size_lg2, ent), a, asize, acount} - -#define UPB_EMPTY_INTTABLE_INIT(ctype) \ - UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0) - #define UPB_ARRAY_EMPTYENT -1 UPB_INLINE size_t upb_table_size(const upb_table *t) { @@ -399,7 +363,7 @@ UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, if (key < t->array_size) { upb_tabval arrval = t->array[key]; if (upb_arrhas(arrval)) { - _upb_value_setval(v, arrval.val, t->t.ctype); + _upb_value_setval(v, arrval.val); return true; } else { return false; @@ -409,7 +373,7 @@ UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, 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, t->t.ctype); + _upb_value_setval(v, e->val.val); return true; } if (e->next == NULL) return false; From 4c57b1fefd9413ec02dfb7d4ea419814614b9f35 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 9 Dec 2019 10:42:48 -0800 Subject: [PATCH 17/35] More progress on Lua extension. --- BUILD | 33 +++ tests/bindings/lua/main.c | 10 +- tests/bindings/lua/test_upb.lua | 372 +++++++++----------------------- tools/make_cmakelists.py | 11 +- upb/bindings/lua/def.c | 59 ++++- upb/bindings/lua/msg.c | 57 ++++- upb/decode.c | 7 + upb/def.c | 8 + upb/encode.c | 188 +++++++++------- upb/msg.h | 6 + upb/reflection.c | 6 +- upbc/generator.cc | 4 +- 12 files changed, 396 insertions(+), 365 deletions(-) diff --git a/BUILD b/BUILD index ad45b604d1..234c487a81 100644 --- a/BUILD +++ b/BUILD @@ -10,6 +10,10 @@ load( "upb_proto_library", "upb_proto_reflection_library", ) +load( + "//:upb/bindings/lua/lua_proto_library.bzl", + "lua_proto_library", +) licenses(["notice"]) # BSD (Google-authored w/ possible external contributions) @@ -585,9 +589,12 @@ cc_test( data = [ "@com_google_protobuf//:conformance_proto", "@com_google_protobuf//:descriptor_proto", + ":descriptor_proto_lua", + ":test_messages_proto3_proto_lua", "tests/bindings/lua/test_upb.lua", "third_party/lunit/console.lua", "third_party/lunit/lunit.lua", + "upb/bindings/lua/upb.lua", ], deps = [ ":lupb", @@ -595,6 +602,32 @@ cc_test( ] ) +cc_binary( + name = "protoc-gen-lua", + srcs = ["upb/bindings/lua/upbc.cc"], + copts = select({ + ":windows": [], + "//conditions:default": CPPOPTS + }), + visibility = ["//visibility:public"], + deps = [ + "@absl//absl/strings", + "@com_google_protobuf//:protoc_lib" + ], +) + +lua_proto_library( + name = "descriptor_proto_lua", + visibility = ["//visibility:public"], + deps = ["@com_google_protobuf//:descriptor_proto"], +) + +lua_proto_library( + name = "test_messages_proto3_proto_lua", + testonly = 1, + deps = ["@com_google_protobuf//:test_messages_proto3_proto"], +) + # Test the CMake build ######################################################### filegroup( diff --git a/tests/bindings/lua/main.c b/tests/bindings/lua/main.c index f8fe502e73..5b501738c1 100644 --- a/tests/bindings/lua/main.c +++ b/tests/bindings/lua/main.c @@ -22,7 +22,15 @@ static void sighandler(int i) { const char *init = "package.preload['lupb'] = ... " - "package.path = './?.lua;./third_party/lunit/?.lua'"; + "package.path = '" + "./?.lua;" + "./third_party/lunit/?.lua;" + "external/com_google_protobuf/?.lua;" + "external/com_google_protobuf/src/?.lua;" + "bazel-bin/external/com_google_protobuf/src/?.lua;" + "bazel-bin/external/com_google_protobuf/?.lua;" + "upb/bindings/lua/?.lua" + "'"; int main() { int ret = 0; diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index 0a1ef632b6..2e404d0149 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -1,6 +1,8 @@ local upb = require "lupb" local lunit = require "lunit" +local test_messages_proto3 = require "google.protobuf.test_messages_proto3_pb" +local descriptor = require "google.protobuf.descriptor_pb" if _VERSION >= 'Lua 5.2' then _ENV = lunit.module("testupb", "seeall") @@ -16,227 +18,34 @@ function iter_to_array(iter) return arr end ---[[ - -function test_msgdef() - local f2 = upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} - local o = upb.OneofDef{name = "field1", fields = {f2}} - local f = upb.FieldDef{name = "field3", number = 2, type = upb.TYPE_INT32} - - local m = upb.MessageDef{fields = {o, f}} - - assert_equal(f, m:lookup_name("field3")) - assert_equal(o, m:lookup_name("field1")) - assert_equal(f2, m:lookup_name("field2")) -end - -function test_fielddef() - local f = upb.FieldDef() - assert_false(f:is_frozen()) - assert_nil(f:number()) - assert_nil(f:name()) - assert_nil(f:type()) +function test_def_readers() + local m = test_messages_proto3.TestAllTypesProto3 + assert_equal("TestAllTypesProto3", m:name()) + assert_equal("protobuf_test_messages.proto3.TestAllTypesProto3", m:full_name()) + + -- field + local f = m:field("optional_int32") + local f2 = m:field(1) + assert_equal(f, f2) + assert_equal(1, f:number()) + assert_equal("optional_int32", f:name()) assert_equal(upb.LABEL_OPTIONAL, f:label()) - - f:set_name("foo_field") - f:set_number(3) - f:set_label(upb.LABEL_REPEATED) - f:set_type(upb.TYPE_FLOAT) - - assert_equal("foo_field", f:name()) - assert_equal(3, f:number()) - assert_equal(upb.LABEL_REPEATED, f:label()) - assert_equal(upb.TYPE_FLOAT, f:type()) - - local f2 = upb.FieldDef{ - name = "foo", number = 5, type = upb.TYPE_DOUBLE, label = upb.LABEL_REQUIRED - } - - assert_equal("foo", f2:name()) - assert_equal(5, f2:number()) - assert_equal(upb.TYPE_DOUBLE, f2:type()) - assert_equal(upb.LABEL_REQUIRED, f2:label()) + assert_equal(upb.DESCRIPTOR_TYPE_INT32, f:descriptor_type()) + assert_equal(upb.TYPE_INT32, f:type()) + assert_nil(f:containing_oneof()) + assert_equal(m, f:containing_type()) + assert_equal(0, f:default()) + + -- enum + local e = test_messages_proto3['TestAllTypesProto3.NestedEnum'] + assert_true(#e > 3 and #e < 10) + assert_equal(2, e:value("BAZ")) end -function test_enumdef() - local e = upb.EnumDef() - assert_equal(0, #e) - assert_nil(e:value(5)) - assert_nil(e:value("NONEXISTENT_NAME")) - - for name, value in e:values() do - fail() - end - - e:add("VAL1", 1) - e:add("VAL2", 2) - - local values = {} - for name, value in e:values() do - values[name] = value - end - - assert_equal(1, values["VAL1"]) - assert_equal(2, values["VAL2"]) - - local e2 = upb.EnumDef{ - values = { - {"FOO", 1}, - {"BAR", 77}, - } - } - - assert_equal(1, e2:value("FOO")) - assert_equal(77, e2:value("BAR")) - assert_equal("FOO", e2:value(1)) - assert_equal("BAR", e2:value(77)) - - e2:freeze() - - local f = upb.FieldDef{type = upb.TYPE_ENUM} - - -- No default set and no EnumDef to get a default from. - assert_equal(f:default(), nil) - - f:set_subdef(upb.EnumDef()) - -- No default to pull in from the EnumDef. - assert_equal(f:default(), nil) - - f:set_subdef(e2) - -- First member added to e2. - assert_equal(f:default(), "FOO") - - f:set_subdef(nil) - assert_equal(f:default(), nil) - - f:set_default(1) - assert_equal(f:default(), 1) - - f:set_default("YOYOYO") - assert_equal(f:default(), "YOYOYO") - - f:set_subdef(e2) - f:set_default(1) - -- It prefers to return a string, and could resolve the explicit "1" we set - -- it to to the string value. - assert_equal(f:default(), "FOO") - - -- FieldDef can specify default value by name or number, but the value must - -- exist at freeze time. - local m1 = upb.build_defs{ - upb.MessageDef{ - full_name = "A", - fields = { - upb.FieldDef{ - name = "f1", - number = 1, - type = upb.TYPE_ENUM, - subdef = e2, - default = "BAR" - }, - upb.FieldDef{ - name = "f2", - number = 2, - type = upb.TYPE_ENUM, - subdef = e2, - default = 77 - } - } - } - } - - assert_equal(m1:field("f1"):default(), "BAR") - assert_equal(m1:field("f1"):default(), "BAR") - - assert_error_match( - "enum default for field A.f1 .DOESNT_EXIST. is not in the enum", - function() - local m1 = upb.build_defs{ - upb.MessageDef{ - full_name = "A", - fields = { - upb.FieldDef{ - name = "f1", - number = 1, - type = upb.TYPE_ENUM, - subdef = e2, - default = "DOESNT_EXIST" - } - } - } - } - end - ) - - assert_error_match( - "enum default for field A.f1 .142. is not in the enum", - function() - local m1 = upb.build_defs{ - upb.MessageDef{ - full_name = "A", - fields = { - upb.FieldDef{ - name = "f1", - number = 1, - type = upb.TYPE_ENUM, - subdef = e2, - default = 142 - } - } - } - } - end - ) -end - -function test_empty_msgdef() - local md = upb.MessageDef() - assert_nil(md:full_name()) -- Def without name is anonymous. - assert_false(md:is_frozen()) - assert_equal(0, #md) - assert_nil(md:field("nonexistent_field")) - assert_nil(md:field(3)) - for field in md:fields() do - fail() - end - - upb.freeze(md) - assert_true(md:is_frozen()) - assert_equal(0, #md) - assert_nil(md:field("nonexistent_field")) - assert_nil(md:field(3)) - for field in md:fields() do - fail() - end -end - -function test_msgdef_constructor() - local f1 = upb.FieldDef{name = "field1", number = 7, type = upb.TYPE_INT32} - local f2 = upb.FieldDef{name = "field2", number = 8, type = upb.TYPE_INT32} - local md = upb.MessageDef{ - full_name = "TestMessage", - fields = {f1, f2} - } - assert_equal("TestMessage", md:full_name()) - assert_false(md:is_frozen()) - assert_equal(2, #md) - assert_equal(f1, md:field("field1")) - assert_equal(f2, md:field("field2")) - assert_equal(f1, md:field(7)) - assert_equal(f2, md:field(8)) - local count = 0 - local found = {} - for field in md:fields() do - count = count + 1 - found[field] = true - end - assert_equal(2, count) - assert_true(found[f1]) - assert_true(found[f2]) +--[[ - upb.freeze(md) -end +function test_enumdef() function test_iteration() -- Test that we cannot crash the process even if we modify the set of fields -- during iteration. @@ -510,81 +319,85 @@ function test_msg_primitives() test_for_numeric_type(upb.TYPE_DOUBLE, 10^101) end +==]] + +function test_msg_map() + msg = test_messages_proto3.TestAllTypesProto3() + msg.map_int32_int32[5] = 10 + msg.map_int32_int32[6] = 12 + assert_equal(10, msg.map_int32_int32[5]) + assert_equal(12, msg.map_int32_int32[6]) + + local serialized = upb.encode(msg) + assert_true(#serialized > 0) + local msg2 = upb.decode(test_messages_proto3.TestAllTypesProto3, serialized) + assert_equal(10, msg2.map_int32_int32[5]) + assert_equal(12, msg2.map_int32_int32[6]) +end + function test_msg_array() - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage", fields = { - upb.FieldDef{name = "i32_array", number = 1, type = upb.TYPE_INT32, - label = upb.LABEL_REPEATED}, - } - } - } + msg = test_messages_proto3.TestAllTypesProto3() - factory = upb.MessageFactory(symtab) - TestMessage = factory:get_message_class("TestMessage") - msg = TestMessage() + assert_not_nil(msg.repeated_int32) + assert_equal(msg.repeated_int32, msg.repeated_int32) + assert_equal(0, #msg.repeated_int32) - assert_nil(msg.i32_array) + msg.repeated_int32[1] = 2 + assert_equal(1, #msg.repeated_int32); + assert_equal(2, msg.repeated_int32[1]); -- Can't assign a scalar; array is expected. - assert_error_match("lupb.array expected", function() msg.i32_array = 5 end) + assert_error_match("lupb.array expected", function() msg.repeated_int32 = 5 end) -- Can't assign array of the wrong type. local function assign_int64() - msg.i32_array = upb.Array(upb.TYPE_INT64) + msg.repeated_int32 = upb.Array(upb.TYPE_INT64) end - assert_error_match("Array had incorrect type", assign_int64) + assert_error_match("array type mismatch", assign_int64) local arr = upb.Array(upb.TYPE_INT32) - msg.i32_array = arr - assert_equal(arr, msg.i32_array) + arr[1] = 6 + assert_equal(1, #arr) + msg.repeated_int32 = arr + assert_equal(msg.repeated_int32, msg.repeated_int32) + assert_equal(arr, msg.repeated_int32) + assert_equal(1, #msg.repeated_int32) + assert_equal(6, msg.repeated_int32[1]) -- Can't assign other Lua types. - assert_error_match("array expected", function() msg.i32_array = "abc" end) - assert_error_match("array expected", function() msg.i32_array = true end) - assert_error_match("array expected", function() msg.i32_array = false end) - assert_error_match("array expected", function() msg.i32_array = nil end) - assert_error_match("array expected", function() msg.i32_array = {} end) - assert_error_match("array expected", function() msg.i32_array = print end) + assert_error_match("array expected", function() msg.repeated_int32 = "abc" end) + assert_error_match("array expected", function() msg.repeated_int32 = true end) + assert_error_match("array expected", function() msg.repeated_int32 = false end) + assert_error_match("array expected", function() msg.repeated_int32 = nil end) + assert_error_match("array expected", function() msg.repeated_int32 = {} end) + assert_error_match("array expected", function() msg.repeated_int32 = print end) end function test_msg_submsg() - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage", fields = { - upb.FieldDef{name = "submsg", number = 1, type = upb.TYPE_MESSAGE, - subdef_name = ".SubMessage"}, - } - }, - upb.MessageDef{full_name = "SubMessage"} - } - - factory = upb.MessageFactory(symtab) - TestMessage = factory:get_message_class("TestMessage") - SubMessage = factory:get_message_class("SubMessage") - msg = TestMessage() + --msg = test_messages_proto3.TestAllTypesProto3() + msg = test_messages_proto3['TestAllTypesProto3']() - assert_nil(msg.submsg) + assert_nil(msg.optional_nested_message) -- Can't assign message of the wrong type. local function assign_int64() - msg.submsg = TestMessage() + msg.optional_nested_message = test_messages_proto3.TestAllTypesProto3() end - assert_error_match("Message had incorrect type", assign_int64) + assert_error_match("message type mismatch", assign_int64) - local sub = SubMessage() - msg.submsg = sub - assert_equal(sub, msg.submsg) + local nested = test_messages_proto3['TestAllTypesProto3.NestedMessage']() + msg.optional_nested_message = nested + assert_equal(nested, msg.optional_nested_message) -- Can't assign other Lua types. - assert_error_match("msg expected", function() msg.submsg = "abc" end) - assert_error_match("msg expected", function() msg.submsg = true end) - assert_error_match("msg expected", function() msg.submsg = false end) - assert_error_match("msg expected", function() msg.submsg = nil end) - assert_error_match("msg expected", function() msg.submsg = {} end) - assert_error_match("msg expected", function() msg.submsg = print end) + assert_error_match("msg expected", function() msg.optional_nested_message = "abc" end) + assert_error_match("msg expected", function() msg.optional_nested_message = true end) + assert_error_match("msg expected", function() msg.optional_nested_message = false end) + assert_error_match("msg expected", function() msg.optional_nested_message = nil end) + assert_error_match("msg expected", function() msg.optional_nested_message = {} end) + assert_error_match("msg expected", function() msg.optional_nested_message = print end) end ---]] - -- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer -- can be defined in Lua. if _VERSION >= 'Lua 5.2' then @@ -765,6 +578,35 @@ function test_numeric_map() map[key_vals.valid_val] = val_vals.valid_val assert_equal(1, #map) + assert_equal(val_vals.valid_val, map[key_vals.valid_val]) + + i = 0 + for k, v in pairs(map) do + assert_equal(key_vals.valid_val, k) + assert_equal(val_vals.valid_val, v) + end + + -- Out of range key/val + local errmsg = "not an integer or out of range" + if key_vals.too_small then + assert_error_match(errmsg, function() map[key_vals.too_small] = 1 end) + end + if key_vals.too_big then + assert_error_match(errmsg, function() map[key_vals.too_big] = 1 end) + end + if key_vals.other_bad then + assert_error_match(errmsg, function() map[key_vals.other_bad] = 1 end) + end + + if val_vals.too_small then + assert_error_match(errmsg, function() map[1] = val_vals.too_small end) + end + if val_vals.too_big then + assert_error_match(errmsg, function() map[1] = val_vals.too_big end) + end + if val_vals.other_bad then + assert_error_match(errmsg, function() map[1] = val_vals.other_bad end) + end end for k in pairs(numeric_types) do diff --git a/tools/make_cmakelists.py b/tools/make_cmakelists.py index b1b1a35e5f..76e3ee1598 100755 --- a/tools/make_cmakelists.py +++ b/tools/make_cmakelists.py @@ -100,16 +100,7 @@ class BuildFileFunctions(object): def py_binary(self, **kwargs): pass - def lua_cclibrary(self, **kwargs): - pass - - def lua_library(self, **kwargs): - pass - - def lua_binary(self, **kwargs): - pass - - def lua_test(self, **kwargs): + def lua_proto_library(self, **kwargs): pass def sh_test(self, **kwargs): diff --git a/upb/bindings/lua/def.c b/upb/bindings/lua/def.c index 5889cd518d..6dc6b1a575 100644 --- a/upb/bindings/lua/def.c +++ b/upb/bindings/lua/def.c @@ -364,6 +364,17 @@ static int lupb_msgdef_lookupname(lua_State *L) { return 1; } +/* lupb_msgdef_name() + * + * Handles: + * msg.name() -> string + */ +static int lupb_msgdef_name(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushstring(L, upb_msgdef_name(m)); + return 1; +} + static int lupb_msgfielditer_next(lua_State *L) { upb_msg_field_iter *i = lua_touserdata(L, lua_upvalueindex(1)); const upb_fielddef *f; @@ -386,6 +397,19 @@ static int lupb_msgdef_fields(lua_State *L) { return 1; } +static int lupb_msgdef_file(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + const upb_filedef *file = upb_msgdef_file(m); + lupb_wrapper_pushwrapper(L, 1, file, LUPB_FILEDEF); + return 1; +} + +static int lupb_msgdef_fullname(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushstring(L, upb_msgdef_fullname(m)); + return 1; +} + static int lupb_msgoneofiter_next(lua_State *L) { upb_msg_oneof_iter *i = lua_touserdata(L, lua_upvalueindex(1)); const upb_oneofdef *o; @@ -419,16 +443,27 @@ static int lupb_msgdef_syntax(lua_State *L) { return 1; } +static int lupb_msgdef_tostring(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushfstring(L, "", + upb_msgdef_fullname(m), (int)upb_msgdef_numfields(m)); + return 1; +} + static const struct luaL_Reg lupb_msgdef_mm[] = { {"__call", lupb_msg_pushnew}, {"__len", lupb_msgdef_len}, + {"__tostring", lupb_msgdef_tostring}, {NULL, NULL} }; static const struct luaL_Reg lupb_msgdef_m[] = { {"field", lupb_msgdef_field}, {"fields", lupb_msgdef_fields}, + {"file", lupb_msgdef_file}, + {"full_name", lupb_msgdef_fullname}, {"lookup_name", lupb_msgdef_lookupname}, + {"name", lupb_msgdef_name}, {"oneofs", lupb_msgdef_oneofs}, {"syntax", lupb_msgdef_syntax}, {"_map_entry", lupb_msgdef_mapentry}, @@ -448,6 +483,13 @@ static int lupb_enumdef_len(lua_State *L) { return 1; } +static int lupb_enumdef_file(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + const upb_filedef *file = upb_enumdef_file(e); + lupb_wrapper_pushwrapper(L, 1, file, LUPB_FILEDEF); + return 1; +} + /* lupb_enumdef_value() * * Handles: @@ -510,6 +552,7 @@ static const struct luaL_Reg lupb_enumdef_mm[] = { }; static const struct luaL_Reg lupb_enumdef_m[] = { + {"file", lupb_enumdef_file}, {"value", lupb_enumdef_value}, {"values", lupb_enumdef_values}, {NULL, NULL} @@ -619,6 +662,7 @@ upb_symtab *lupb_symtab_check(lua_State *L, int narg) { void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def, const char *type) { + narg = lua_absindex(L, narg); assert(luaL_testudata(L, narg, LUPB_SYMTAB)); if (def == NULL) { @@ -687,6 +731,7 @@ static int lupb_symtab_addfile(lua_State *L) { const char *str = luaL_checklstring(L, 2, &len); upb_arena *arena = lupb_arena_pushnew(L);; const google_protobuf_FileDescriptorProto *file; + const upb_filedef *file_def; upb_status status; upb_status_clear(&status); @@ -696,10 +741,12 @@ static int lupb_symtab_addfile(lua_State *L) { luaL_argerror(L, 2, "failed to parse descriptor"); } - upb_symtab_addfile(s, file, &status); + file_def = upb_symtab_addfile(s, file, &status); lupb_checkstatus(L, &status); - return 0; + lupb_symtab_pushwrapper(L, 1, file_def, LUPB_FILEDEF); + + return 1; } static int lupb_symtab_addset(lua_State *L) { @@ -741,6 +788,13 @@ static int lupb_symtab_lookupenum(lua_State *L) { return 1; } +static int lupb_symtab_tostring(lua_State *L) { + const upb_symtab *s = lupb_symtab_check(L, 1); + lua_pushfstring(L, "", + (int)upb_symtab_filecount(s)); + return 1; +} + static const struct luaL_Reg lupb_symtab_m[] = { {"add_file", lupb_symtab_addfile}, {"add_set", lupb_symtab_addset}, @@ -751,6 +805,7 @@ static const struct luaL_Reg lupb_symtab_m[] = { static const struct luaL_Reg lupb_symtab_mm[] = { {"__gc", lupb_symtab_gc}, + {"__tostring", lupb_symtab_tostring}, {NULL, NULL} }; diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 8fd5a2bfd3..b611cee8e6 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -181,7 +181,7 @@ typedef struct { upb_arena *arena; } lupb_arena; -upb_arena *lupb_arena_check(lua_State *L, int narg) { +static upb_arena *lupb_arena_check(lua_State *L, int narg) { lupb_arena *a = luaL_checkudata(L, narg, LUPB_ARENA); return a->arena; } @@ -206,7 +206,7 @@ upb_arena *lupb_arena_pushnew(lua_State *L) { * * Merges |from| into |to| so that there is a single arena group that contains * both, and both arenas will point at this new table. */ -void lupb_arena_merge(lua_State *L, int to, int from) { +static void lupb_arena_merge(lua_State *L, int to, int from) { int i, from_count, to_count; lua_getiuservalue(L, to, LUPB_ARENAGROUP_INDEX); lua_getiuservalue(L, from, LUPB_ARENAGROUP_INDEX); @@ -240,7 +240,7 @@ void lupb_arena_merge(lua_State *L, int to, int from) { * * This is mainly useful for pinning strings we have parsed protobuf data from. * It will allow us to point directly to string data in the original string. */ -void lupb_arena_addobj(lua_State *L, int narg) { +static void lupb_arena_addobj(lua_State *L, int narg) { lua_getiuservalue(L, narg, LUPB_ARENAGROUP_INDEX); int n = lua_rawlen(L, -1); lua_pushvalue(L, -2); @@ -376,7 +376,6 @@ static void lupb_pushmsgval(lua_State *L, int container, upb_fieldtype_t type, assert(container); if (!lupb_cacheget(L, val.msg_val)) { lupb_msg_newmsgwrapper(L, container, val); - lupb_cacheset(L, val.msg_val); } return; } @@ -436,6 +435,7 @@ static int lupb_array_new(lua_State *L) { lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); larray->arr = upb_array_new(arena, larray->type); + lupb_cacheset(L, larray->arr); return 1; } @@ -542,6 +542,7 @@ static int lupb_map_new(lua_State *L) { lmap->key_type = lupb_checkfieldtype(L, 1); lmap->map = upb_map_new(arena, lmap->key_type, lmap->value_type); + lupb_cacheset(L, lmap->map); return 1; } @@ -669,7 +670,9 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg, lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX); m = lupb_msgdef_check(L, -1); f = upb_msgdef_ntof(m, fieldname, len); - luaL_argcheck(L, f != NULL, field, "no such field"); + if (f == NULL) { + luaL_error(L, "no such field '%s'", fieldname); + } lua_pop(L, 1); return f; @@ -684,6 +687,7 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg, static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val) { lupb_msg *lmsg = lupb_newuserdata(L, sizeof(*lmsg), 2, LUPB_MSG); lmsg->msg = (upb_msg*)val.msg_val; /* XXX: cast isn't great. */ + lupb_cacheset(L, lmsg->msg); /* Copy both arena and msgdef into the wrapper. */ lua_getiuservalue(L, narg, LUPB_ARENA_INDEX); @@ -763,6 +767,8 @@ static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f, * must be in the same group. */ lua_getiuservalue(L, narg, LUPB_ARENA_INDEX); lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); + + lupb_cacheset(L, val.msg_val); } /** @@ -787,8 +793,10 @@ static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg, * * Handles: * new_msg = MessageClass() + * new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}} */ int lupb_msg_pushnew(lua_State *L) { + int argcount = lua_gettop(L); const upb_msgdef *m = lupb_msgdef_check(L, 1); lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG); upb_arena *arena = lupb_arena_pushnew(L); @@ -798,6 +806,18 @@ int lupb_msg_pushnew(lua_State *L) { lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); lmsg->msg = upb_msg_new(m, arena); + lupb_cacheset(L, lmsg->msg); + + if (argcount > 1) { + /* Set initial fields from table. */ + int msg = lua_gettop(L); + lua_pushnil(L); + while (lua_next(L, 2) != 0) { + lua_pushvalue(L, -2); /* now stack is key, val, key */ + lua_insert(L, -3); /* now stack is key, key, val */ + lua_settable(L, msg); + } + } return 1; } @@ -819,7 +839,6 @@ static int lupb_msg_index(lua_State *L) { /* Wrapped type; get or create wrapper. */ if (lupb_msg_lazycreate(L, 1, f, &val) || !lupb_cacheget(L, val.msg_val)) { lupb_msg_newwrapper(L, 1, f, val); - lupb_cacheset(L, val.msg_val); } } else { /* Value type, just push value and return .*/ @@ -841,6 +860,7 @@ static int lupb_msg_newindex(lua_State *L) { upb_msg *msg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2); upb_msgval msgval; + bool merge_arenas = true; if (upb_fielddef_ismap(f)) { lupb_map *lmap = lupb_map_check(L, 3); @@ -869,6 +889,14 @@ static int lupb_msg_newindex(lua_State *L) { msgval.msg_val = msg; } else { msgval = lupb_tomsgval(L, upb_fielddef_type(f), 3, 1, LUPB_COPY); + merge_arenas = false; + } + + if (merge_arenas) { + lua_getiuservalue(L, 1, LUPB_ARENA_INDEX); + lua_getiuservalue(L, 3, LUPB_ARENA_INDEX); + lupb_arena_merge(L, lua_absindex(L, -2), lua_absindex(L, -1)); + lua_pop(L, 2); } upb_msg_set(msg, f, msgval, lupb_arenaget(L, 1)); @@ -887,6 +915,12 @@ static const struct luaL_Reg lupb_msg_mm[] = { /* lupb_msg toplevel **********************************************************/ +/** + * lupb_decode() + * + * Handles: + * msg = upb.decode(MessageClass, bin_string) + */ static int lupb_decode(lua_State *L) { size_t len; const upb_msgdef *m = lupb_msgdef_check(L, 1); @@ -896,7 +930,10 @@ static int lupb_decode(lua_State *L) { upb_arena *arena; bool ok; - lupb_msg_pushnew(L); + /* Create message. */ + lua_pushcfunction(L, &lupb_msg_pushnew); + lua_pushvalue(L, 1); + lua_call(L, 1, 1); msg = lupb_msg_check(L, -1); lua_getiuservalue(L, -1, LUPB_ARENA_INDEX); @@ -917,6 +954,12 @@ static int lupb_decode(lua_State *L) { return 1; } +/** + * lupb_encode() + * + * Handles: + * bin_string = upb.encode(msg) + */ static int lupb_encode(lua_State *L) { const upb_msg *msg = lupb_msg_check(L, 1); const upb_msglayout *layout; diff --git a/upb/decode.c b/upb/decode.c index 0185be4de4..10342c85ff 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -471,6 +471,13 @@ static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame, if (field->label == UPB_LABEL_REPEATED) { return upb_decode_toarray(d, frame, field, len); + } else if (field->label == UPB_LABEL_MAP) { + /* Max map entry size is string key/val. */ + char submsg[sizeof(upb_strview) * 2]; + const upb_msglayout *layout = frame->layout->submsgs[field->submsg_index]; + CHK(upb_decode_msgfield(d, &submsg, layout, len)); + /* TODO: insert into map. */ + return true; } else { switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_STRING: diff --git a/upb/def.c b/upb/def.c index 994d74d7df..559179bf97 100644 --- a/upb/def.c +++ b/upb/def.c @@ -932,6 +932,10 @@ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { field->descriptortype = upb_fielddef_descriptortype(f); field->label = upb_fielddef_label(f); + if (upb_fielddef_ismap(f)) { + field->label = UPB_LABEL_MAP; + } + /* TODO: we probably should sort the fields by field number to match the * output of upbc, and to improve search speed for the table parser. */ f->layout_index = f->index_; @@ -1897,6 +1901,10 @@ const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) : NULL; } +int upb_symtab_filecount(const upb_symtab *s) { + return upb_strtable_count(&s->files); +} + static const upb_filedef *_upb_symtab_addfile( upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, const upb_msglayout **layouts, upb_status *status) { diff --git a/upb/encode.c b/upb/encode.c index a86f67c381..f61427b47d 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -138,6 +138,82 @@ static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr, bool upb_encode_message(upb_encstate *e, const char *msg, const upb_msglayout *m, size_t *size); +static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem, + const upb_msglayout *m, + const upb_msglayout_field *f, + bool skip_zero_value) { + const char *field_mem = _field_mem; +#define CASE(ctype, type, wire_type, encodeval) do { \ + ctype val = *(ctype*)field_mem; \ + if (skip_zero_value && val == 0) { \ + return true; \ + } \ + return upb_put_ ## type(e, encodeval) && \ + upb_put_tag(e, f->number, wire_type); \ +} while(0) + + switch (f->descriptortype) { + case UPB_DESCRIPTOR_TYPE_DOUBLE: + CASE(double, double, UPB_WIRE_TYPE_64BIT, val); + case UPB_DESCRIPTOR_TYPE_FLOAT: + CASE(float, float, UPB_WIRE_TYPE_32BIT, val); + case UPB_DESCRIPTOR_TYPE_INT64: + case UPB_DESCRIPTOR_TYPE_UINT64: + CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val); + case UPB_DESCRIPTOR_TYPE_UINT32: + CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val); + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_ENUM: + CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val); + case UPB_DESCRIPTOR_TYPE_SFIXED64: + case UPB_DESCRIPTOR_TYPE_FIXED64: + CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val); + case UPB_DESCRIPTOR_TYPE_FIXED32: + case UPB_DESCRIPTOR_TYPE_SFIXED32: + CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val); + case UPB_DESCRIPTOR_TYPE_BOOL: + CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val); + case UPB_DESCRIPTOR_TYPE_SINT32: + CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val)); + case UPB_DESCRIPTOR_TYPE_SINT64: + CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val)); + case UPB_DESCRIPTOR_TYPE_STRING: + case UPB_DESCRIPTOR_TYPE_BYTES: { + upb_strview view = *(upb_strview*)field_mem; + if (skip_zero_value && view.size == 0) { + return true; + } + return upb_put_bytes(e, view.data, view.size) && + upb_put_varint(e, view.size) && + upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); + } + case UPB_DESCRIPTOR_TYPE_GROUP: { + size_t size; + void *submsg = *(void **)field_mem; + const upb_msglayout *subm = m->submsgs[f->submsg_index]; + if (submsg == NULL) { + return true; + } + return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && + upb_encode_message(e, submsg, subm, &size) && + upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP); + } + case UPB_DESCRIPTOR_TYPE_MESSAGE: { + size_t size; + void *submsg = *(void **)field_mem; + const upb_msglayout *subm = m->submsgs[f->submsg_index]; + if (submsg == NULL) { + return true; + } + return upb_encode_message(e, submsg, subm, &size) && + upb_put_varint(e, size) && + upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); + } + } +#undef CASE + UPB_UNREACHABLE(); +} + static bool upb_encode_array(upb_encstate *e, const char *field_mem, const upb_msglayout *m, const upb_msglayout_field *f) { @@ -236,81 +312,37 @@ do { ; } while(0) return true; } -static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f, - bool skip_zero_value) { -#define CASE(ctype, type, wire_type, encodeval) do { \ - ctype val = *(ctype*)field_mem; \ - if (skip_zero_value && val == 0) { \ - return true; \ - } \ - return upb_put_ ## type(e, encodeval) && \ - upb_put_tag(e, f->number, wire_type); \ -} while(0) +static bool upb_encode_map(upb_encstate *e, const char *field_mem, + const upb_msglayout *m, + const upb_msglayout_field *f) { + const upb_map *map = *(const upb_map**)field_mem; + const upb_msglayout *entry = m->submsgs[f->submsg_index]; + const upb_msglayout_field *key_field = &entry->fields[0]; + const upb_msglayout_field *val_field = &entry->fields[1]; + upb_strtable_iter i; + if (map == NULL) { + return true; + } - switch (f->descriptortype) { - case UPB_DESCRIPTOR_TYPE_DOUBLE: - CASE(double, double, UPB_WIRE_TYPE_64BIT, val); - case UPB_DESCRIPTOR_TYPE_FLOAT: - CASE(float, float, UPB_WIRE_TYPE_32BIT, val); - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_UINT64: - CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val); - case UPB_DESCRIPTOR_TYPE_UINT32: - CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val); - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_ENUM: - CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val); - case UPB_DESCRIPTOR_TYPE_SFIXED64: - case UPB_DESCRIPTOR_TYPE_FIXED64: - CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val); - case UPB_DESCRIPTOR_TYPE_FIXED32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val); - case UPB_DESCRIPTOR_TYPE_BOOL: - CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val); - case UPB_DESCRIPTOR_TYPE_SINT32: - CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val)); - case UPB_DESCRIPTOR_TYPE_SINT64: - CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val)); - case UPB_DESCRIPTOR_TYPE_STRING: - case UPB_DESCRIPTOR_TYPE_BYTES: { - upb_strview view = *(upb_strview*)field_mem; - if (skip_zero_value && view.size == 0) { - return true; - } - return upb_put_bytes(e, view.data, view.size) && - upb_put_varint(e, view.size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); - } - case UPB_DESCRIPTOR_TYPE_GROUP: { - size_t size; - void *submsg = *(void **)field_mem; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; - if (submsg == NULL) { - return true; - } - return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && - upb_encode_message(e, submsg, subm, &size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP); - } - case UPB_DESCRIPTOR_TYPE_MESSAGE: { - size_t size; - void *submsg = *(void **)field_mem; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; - if (submsg == NULL) { - return true; - } - return upb_encode_message(e, submsg, subm, &size) && - upb_put_varint(e, size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); - } + upb_strtable_begin(&i, &map->table); + for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + size_t pre_len = e->limit - e->ptr; + size_t size; + upb_strview key = upb_strtable_iter_key(&i); + const upb_value val = upb_strtable_iter_value(&i); + + /* XXX; string key/value */ + CHK(upb_encode_scalarfield(e, &val, entry, val_field, false)); + CHK(upb_encode_scalarfield(e, key.data, entry, key_field, false)); + size = (e->limit - e->ptr) - pre_len; + CHK(upb_put_varint(e, size)); + CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); } -#undef CASE - UPB_UNREACHABLE(); + + return true; } + bool upb_encode_message(upb_encstate *e, const char *msg, const upb_msglayout *m, size_t *size) { int i; @@ -318,11 +350,19 @@ bool upb_encode_message(upb_encstate *e, const char *msg, const char *unknown; size_t unknown_size; + unknown = upb_msg_getunknown(msg, &unknown_size); + + if (unknown) { + upb_put_bytes(e, unknown, unknown_size); + } + for (i = m->field_count - 1; i >= 0; i--) { const upb_msglayout_field *f = &m->fields[i]; if (f->label == UPB_LABEL_REPEATED) { CHK(upb_encode_array(e, msg + f->offset, m, f)); + } else if (f->label == UPB_LABEL_MAP) { + CHK(upb_encode_map(e, msg + f->offset, m, f)); } else { bool skip_empty = false; if (f->presence == 0) { @@ -343,12 +383,6 @@ bool upb_encode_message(upb_encstate *e, const char *msg, } } - unknown = upb_msg_getunknown(msg, &unknown_size); - - if (unknown) { - upb_put_bytes(e, unknown, unknown_size); - } - *size = (e->limit - e->ptr) - pre_len; return true; } diff --git a/upb/msg.h b/upb/msg.h index 717d05d10b..71bbac67c3 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -28,6 +28,12 @@ typedef void upb_msg; * members are public so generated code can initialize them, but users MUST NOT * read or write any of its members. */ +/* This isn't a real label according to descriptor.proto, but in the table we + * use this for map fields instead of UPB_LABEL_REPEATED. */ +enum { + UPB_LABEL_MAP = 4 +}; + typedef struct { uint32_t number; uint16_t offset; diff --git a/upb/reflection.c b/upb/reflection.c index eee52a7eda..756fd7a07a 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -66,7 +66,8 @@ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { const char *mem = PTR_AT(msg, field->offset, char); upb_msgval val; if (field->presence == 0 || upb_msg_has(msg, f)) { - memcpy(&val, mem, field_size[field->descriptortype]); + int size = upb_fielddef_isseq(f) ? sizeof(void*) : field_size[field->descriptortype]; + memcpy(&val, mem, size); } else { /* TODO(haberman): change upb_fielddef to not require this switch(). */ switch (upb_fielddef_type(f)) { @@ -131,7 +132,8 @@ void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, upb_arena *a) { const upb_msglayout_field *field = upb_fielddef_layout(f); char *mem = PTR_AT(msg, field->offset, char); - memcpy(mem, &val, field_size[field->descriptortype]); + int size = upb_fielddef_isseq(f) ? sizeof(void*) : field_size[field->descriptortype]; + memcpy(mem, &val, size); if (in_oneof(field)) { *oneofcase(msg, field) = field->number; } diff --git a/upbc/generator.cc b/upbc/generator.cc index 184a524ee0..09ed1ee7f4 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -670,6 +670,8 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) { case_offset.size64 = -case_offset.size64 - 1; presence = GetSizeInit(case_offset); } + // Sync '4' with UPB_LABEL_MAP in upb/msg.h. + int label = field->is_map() ? 4 : field->label(); output(" {$0, $1, $2, $3, $4, $5},\n", field->number(), @@ -677,7 +679,7 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) { presence, submsg_index, field->type(), - field->label()); + label); } output("};\n\n"); } From 382f92a87fb9fb87912e0af2fc8fda702a3ea0b6 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 16:36:11 -0800 Subject: [PATCH 18/35] Maps encode and decode successfully! --- tests/bindings/lua/test_upb.lua | 334 ++++++-------------------------- upb/decode.c | 68 ++++++- upb/def.c | 7 +- upb/encode.c | 9 +- upb/msg.c | 17 -- upb/msg.h | 17 +- upb/reflection.c | 1 - upb/reflection.h | 6 +- upb/upb.h | 2 - upbc/message_layout.cc | 11 +- 10 files changed, 155 insertions(+), 317 deletions(-) diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index 2e404d0149..07f7ed0f15 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -42,285 +42,6 @@ function test_def_readers() assert_equal(2, e:value("BAZ")) end ---[[ - - -function test_enumdef() -function test_iteration() - -- Test that we cannot crash the process even if we modify the set of fields - -- during iteration. - local md = upb.MessageDef{full_name = "TestMessage"} - - for i=1,10 do - md:add(upb.FieldDef{ - name = "field" .. tostring(i), - number = 1000 - i, - type = upb.TYPE_INT32 - }) - end - - local add = #md - for f in md:fields() do - if add > 0 then - add = add - 1 - for i=10000,11000 do - local field_name = "field" .. tostring(i) - -- We want to add fields to the table to trigger a table resize, - -- but we must skip it if the field name or number already exists - -- otherwise it will raise an error. - if md:field(field_name) == nil and - md:field(i) == nil then - md:add(upb.FieldDef{ - name = field_name, - number = i, - type = upb.TYPE_INT32 - }) - end - end - end - end - - -- Test that iterators don't crash the process even if the MessageDef goes - -- out of scope. - -- - -- Note: have previously verified that this can indeed crash the process if - -- we do not explicitly add a reference from the iterator to the underlying - -- MessageDef. - local iter = md:fields() - md = nil - collectgarbage() - while iter() do - end - - local ed = upb.EnumDef{ - values = { - {"FOO", 1}, - {"BAR", 77}, - } - } - iter = ed:values() - ed = nil - collectgarbage() - while iter() do - end -end - -function test_msgdef_setters() - local md = upb.MessageDef() - md:set_full_name("Message1") - assert_equal("Message1", md:full_name()) - local f = upb.FieldDef{name = "field1", number = 3, type = upb.TYPE_DOUBLE} - md:add(f) - assert_equal(1, #md) - assert_equal(f, md:field("field1")) -end - -function test_msgdef_errors() - assert_error(function() upb.MessageDef{bad_initializer_key = 5} end) - local md = upb.MessageDef() - assert_error(function() - -- Duplicate field number. - upb.MessageDef{ - fields = { - upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} - } - } - end) - assert_error(function() - -- Duplicate field name. - upb.MessageDef{ - fields = { - upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "field1", number = 2, type = upb.TYPE_INT32} - } - } - end) - - assert_error(function() - -- Duplicate field name. - upb.MessageDef{ - fields = { - upb.OneofDef{name = "field1", fields = { - upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32}, - }}, - upb.FieldDef{name = "field2", number = 2, type = upb.TYPE_INT32} - } - } - end) - - -- attempt to set a name with embedded NULLs. - assert_error_match("names cannot have embedded NULLs", function() - md:set_full_name("abc\0def") - end) - - upb.freeze(md) - -- Attempt to mutate frozen MessageDef. - assert_error_match("frozen", function() - md:add(upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}) - end) - assert_error_match("frozen", function() - md:set_full_name("abc") - end) - - -- Attempt to freeze a msgdef without freezing its subdef. - assert_error_match("is not frozen or being frozen", function() - m1 = upb.MessageDef() - upb.freeze( - upb.MessageDef{ - fields = { - upb.FieldDef{name = "f1", number = 1, type = upb.TYPE_MESSAGE, - subdef = m1} - } - } - ) - end) -end - -function test_symtab() - local empty = upb.SymbolTable() - assert_equal(0, #iter_to_array(empty:defs(upb.DEF_ANY))) - assert_equal(0, #iter_to_array(empty:defs(upb.DEF_MSG))) - assert_equal(0, #iter_to_array(empty:defs(upb.DEF_ENUM))) - - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage"}, - upb.MessageDef{full_name = "ContainingMessage", fields = { - upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "field2", number = 2, type = upb.TYPE_MESSAGE, - subdef_name = ".TestMessage"} - } - } - } - - local msgdef1 = symtab:lookup("TestMessage") - local msgdef2 = symtab:lookup("ContainingMessage") - assert_not_nil(msgdef1) - assert_not_nil(msgdef2) - assert_equal(msgdef1, msgdef2:field("field2"):subdef()) - assert_true(msgdef1:is_frozen()) - assert_true(msgdef2:is_frozen()) - - symtab:add{ - upb.MessageDef{full_name = "ContainingMessage2", fields = { - upb.FieldDef{name = "field5", number = 5, type = upb.TYPE_MESSAGE, - subdef = msgdef2} - } - } - } - - local msgdef3 = symtab:lookup("ContainingMessage2") - assert_not_nil(msgdef3) - assert_equal(msgdef3:field("field5"):subdef(), msgdef2) -end - -function test_msg_primitives() - local function test_for_numeric_type(upb_type, val, too_big, too_small, bad3) - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage", fields = { - upb.FieldDef{name = "f", number = 1, type = upb_type}, - } - } - } - - factory = upb.MessageFactory(symtab) - TestMessage = factory:get_message_class("TestMessage") - msg = TestMessage() - - -- Defaults to zero - assert_equal(0, msg.f) - - msg.f = 0 - assert_equal(0, msg.f) - - msg.f = val - assert_equal(val, msg.f) - - local errmsg = "not an integer or out of range" - if too_small then - assert_error_match(errmsg, function() msg.f = too_small end) - end - if too_big then - assert_error_match(errmsg, function() msg.f = too_big end) - end - if bad3 then - assert_error_match(errmsg, function() msg.f = bad3 end) - end - - -- Can't assign other Lua types. - errmsg = "bad argument #3" - assert_error_match(errmsg, function() msg.f = "abc" end) - assert_error_match(errmsg, function() msg.f = true end) - assert_error_match(errmsg, function() msg.f = false end) - assert_error_match(errmsg, function() msg.f = nil end) - assert_error_match(errmsg, function() msg.f = {} end) - assert_error_match(errmsg, function() msg.f = print end) - assert_error_match(errmsg, function() msg.f = array end) - end - - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage", fields = { - upb.FieldDef{ - name = "i32", number = 1, type = upb.TYPE_INT32, default = 1}, - upb.FieldDef{ - name = "u32", number = 2, type = upb.TYPE_UINT32, default = 2}, - upb.FieldDef{ - name = "i64", number = 3, type = upb.TYPE_INT64, default = 3}, - upb.FieldDef{ - name = "u64", number = 4, type = upb.TYPE_UINT64, default = 4}, - upb.FieldDef{ - name = "dbl", number = 5, type = upb.TYPE_DOUBLE, default = 5}, - upb.FieldDef{ - name = "flt", number = 6, type = upb.TYPE_FLOAT, default = 6}, - upb.FieldDef{ - name = "bool", number = 7, type = upb.TYPE_BOOL, default = true}, - } - } - } - - factory = upb.MessageFactory(symtab) - TestMessage = factory:get_message_class("TestMessage") - msg = TestMessage() - - -- Unset member returns default value. - -- TODO(haberman): re-enable these when we have descriptor-based reflection. - -- assert_equal(1, msg.i32) - -- assert_equal(2, msg.u32) - -- assert_equal(3, msg.i64) - -- assert_equal(4, msg.u64) - -- assert_equal(5, msg.dbl) - -- assert_equal(6, msg.flt) - -- assert_equal(true, msg.bool) - - -- Attempts to access non-existent fields fail. - assert_error_match("no such field", function() msg.no_such = 1 end) - - msg.i32 = 10 - msg.u32 = 20 - msg.i64 = 30 - msg.u64 = 40 - msg.dbl = 50 - msg.flt = 60 - msg.bool = true - - assert_equal(10, msg.i32) - assert_equal(20, msg.u32) - assert_equal(30, msg.i64) - assert_equal(40, msg.u64) - assert_equal(50, msg.dbl) - assert_equal(60, msg.flt) - assert_equal(true, msg.bool) - - test_for_numeric_type(upb.TYPE_UINT32, 2^32 - 1, 2^32, -1, 5.1) - test_for_numeric_type(upb.TYPE_UINT64, 2^62, 2^64, -1, bad64) - test_for_numeric_type(upb.TYPE_INT32, 2^31 - 1, 2^31, -2^31 - 1, 5.1) - test_for_numeric_type(upb.TYPE_INT64, 2^61, 2^63, -2^64, bad64) - test_for_numeric_type(upb.TYPE_FLOAT, 2^20) - test_for_numeric_type(upb.TYPE_DOUBLE, 10^101) -end - -==]] - function test_msg_map() msg = test_messages_proto3.TestAllTypesProto3() msg.map_int32_int32[5] = 10 @@ -335,6 +56,21 @@ function test_msg_map() assert_equal(12, msg2.map_int32_int32[6]) end +function test_msg_string_map() + msg = test_messages_proto3.TestAllTypesProto3() + msg.map_string_string["foo"] = "bar" + msg.map_string_string["baz"] = "quux" + assert_nil(msg.map_string_string["abc"]) + assert_equal("bar", msg.map_string_string["foo"]) + assert_equal("quux", msg.map_string_string["baz"]) + + local serialized = upb.encode(msg) + assert_true(#serialized > 0) + local msg2 = upb.decode(test_messages_proto3.TestAllTypesProto3, serialized) + assert_equal("bar", msg2.map_string_string["foo"]) + assert_equal("quux", msg2.map_string_string["baz"]) +end + function test_msg_array() msg = test_messages_proto3.TestAllTypesProto3() @@ -472,6 +208,46 @@ local numeric_types = { }, } +function test_msg_primitives() + local msg = test_messages_proto3.TestAllTypesProto3{ + optional_int32 = 10, + optional_uint32 = 20, + optional_int64 = 30, + optional_uint64 = 40, + optional_double = 50, + optional_float = 60, + optional_sint32 = 70, + optional_sint64 = 80, + optional_fixed32 = 90, + optional_fixed64 = 100, + optional_sfixed32 = 110, + optional_sfixed64 = 120, + optional_bool = true, + optional_string = "abc", + optional_nested_message = test_messages_proto3['TestAllTypesProto3.NestedMessage']{a = 123}, + } + + -- Attempts to access non-existent fields fail. + assert_error_match("no such field", function() msg.no_such = 1 end) + + assert_equal(10, msg.optional_int32) + assert_equal(20, msg.optional_uint32) + assert_equal(30, msg.optional_int64) + assert_equal(40, msg.optional_uint64) + assert_equal(50, msg.optional_double) + assert_equal(60, msg.optional_float) + assert_equal(70, msg.optional_sint32) + assert_equal(80, msg.optional_sint64) + assert_equal(90, msg.optional_fixed32) + assert_equal(100, msg.optional_fixed64) + assert_equal(110, msg.optional_sfixed32) + assert_equal(120, msg.optional_sfixed64) + assert_equal(true, msg.optional_bool) + assert_equal("abc", msg.optional_string) + assert_equal(123, msg.optional_nested_message.a) +end + + function test_string_array() local function test_for_string_type(upb_type) local array = upb.Array(upb_type) diff --git a/upb/decode.c b/upb/decode.c index 10342c85ff..0ddc29c5d2 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -6,7 +6,7 @@ #include "upb/port_def.inc" /* Maps descriptor type -> upb field type. */ -const uint8_t upb_desctype_to_fieldtype[] = { +const uint8_t desctype_to_fieldtype[] = { UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ UPB_TYPE_DOUBLE, /* DOUBLE */ UPB_TYPE_FLOAT, /* FLOAT */ @@ -198,7 +198,7 @@ static upb_array *upb_getorcreatearr(upb_decframe *frame, upb_array *arr = upb_getarr(frame, field); if (!arr) { - upb_fieldtype_t type = upb_desctype_to_fieldtype[field->descriptortype]; + upb_fieldtype_t type = desctype_to_fieldtype[field->descriptortype]; arr = upb_array_new(frame->state->arena, type); CHK(arr); *(upb_array**)&frame->msg[field->offset] = arr; @@ -463,6 +463,63 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, UPB_UNREACHABLE(); } +static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, + const upb_msglayout_field *field, int len) { + /* Max map entry size is string key/val. */ + size_t size = sizeof(upb_msg_internal) + (sizeof(upb_strview) * 2); + char submsg[size]; + char *submsg_ptr = &submsg[sizeof(upb_msg_internal)]; + upb_map *map = *(upb_map**)&frame->msg[field->offset]; + upb_alloc *alloc = upb_arena_alloc(d->arena); + const upb_msglayout *entry = frame->layout->submsgs[field->submsg_index]; + upb_value val; + const char *key; + size_t key_size; + + if (!map) { + /* Lazily create map. */ + const upb_msglayout_field *key_field = &entry->fields[0]; + const upb_msglayout_field *val_field = &entry->fields[1]; + upb_fieldtype_t key_type = desctype_to_fieldtype[key_field->descriptortype]; + upb_fieldtype_t val_type = desctype_to_fieldtype[val_field->descriptortype]; + UPB_ASSERT(key_field->number == 1); + UPB_ASSERT(val_field->number == 2); + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_strview)); + map = upb_map_new(frame->state->arena, key_type, val_type); + *(upb_map**)&frame->msg[field->offset] = map; + } + + /* Parse map entry. */ + memset(&submsg, 0, size); + CHK(upb_decode_msgfield(d, submsg_ptr, entry, len)); + + /* Insert into map. */ + if (map->key_size_lg2 == UPB_MAPTYPE_STRING) { + const upb_strview* key_view = (const upb_strview*)submsg_ptr; + key = key_view->data; + key_size = key_view->size; + } else { + key = submsg_ptr; + key_size = 1 << map->key_size_lg2; + } + + if (map->val_size_lg2 == UPB_MAPTYPE_STRING) { + upb_strview* val_view = upb_arena_malloc(d->arena, sizeof(*val_view)); + CHK(val_view); + memcpy(val_view, submsg_ptr + sizeof(upb_strview), sizeof(upb_strview)); + memset(&val, 0, sizeof(val)); + memcpy(&val, &val_view, sizeof(void*)); + } else { + memcpy(&val, submsg_ptr + sizeof(upb_strview), 8); + } + + if (!upb_strtable_lookup2(&map->table, key, key_size, NULL)) { + upb_strtable_insert3(&map->table, key, key_size, val, alloc); + } + return true; +} + static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame, const upb_msglayout_field *field) { int len; @@ -472,12 +529,7 @@ static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame, if (field->label == UPB_LABEL_REPEATED) { return upb_decode_toarray(d, frame, field, len); } else if (field->label == UPB_LABEL_MAP) { - /* Max map entry size is string key/val. */ - char submsg[sizeof(upb_strview) * 2]; - const upb_msglayout *layout = frame->layout->submsgs[field->submsg_index]; - CHK(upb_decode_msgfield(d, &submsg, layout, len)); - /* TODO: insert into map. */ - return true; + return upb_decode_mapfield(d, frame, field, len); } else { switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_STRING: diff --git a/upb/def.c b/upb/def.c index 559179bf97..a4a2200e3a 100644 --- a/upb/def.c +++ b/upb/def.c @@ -868,7 +868,12 @@ static size_t upb_msgval_sizeof(upb_fieldtype_t type) { } static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { - if (upb_fielddef_isseq(f)) { + if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) { + // Map entries aren't actually stored, they are only used during parsing. + // For parsing, it helps a lot if all map entry messages have the same + // layout. + return sizeof(upb_strview); + } else if (upb_fielddef_isseq(f)) { return sizeof(void*); } else { return upb_msgval_sizeof(upb_fielddef_type(f)); diff --git a/upb/encode.c b/upb/encode.c index f61427b47d..9314c1d500 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -330,10 +330,13 @@ static bool upb_encode_map(upb_encstate *e, const char *field_mem, size_t size; upb_strview key = upb_strtable_iter_key(&i); const upb_value val = upb_strtable_iter_value(&i); + const void* keyp = + map->key_size_lg2 == UPB_MAPTYPE_STRING ? (void*)&key : key.data; + const void* valp = + map->val_size_lg2 == UPB_MAPTYPE_STRING ? upb_value_getptr(val) : &val; - /* XXX; string key/value */ - CHK(upb_encode_scalarfield(e, &val, entry, val_field, false)); - CHK(upb_encode_scalarfield(e, key.data, entry, key_field, false)); + CHK(upb_encode_scalarfield(e, valp, entry, val_field, false)); + CHK(upb_encode_scalarfield(e, keyp, entry, key_field, false)); size = (e->limit - e->ptr) - pre_len; CHK(upb_put_varint(e, size)); CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); diff --git a/upb/msg.c b/upb/msg.c index cd33e0cca6..b27fa41a92 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -9,23 +9,6 @@ /** upb_msg *******************************************************************/ -/* Internal members of a upb_msg. We can change this without breaking binary - * compatibility. We put these before the user's data. The user's upb_msg* - * points after the upb_msg_internal. */ - -/* Used when a message is not extendable. */ -typedef struct { - char *unknown; - size_t unknown_len; - size_t unknown_size; -} upb_msg_internal; - -/* Used when a message is extendable. */ -typedef struct { - upb_inttable *extdict; - upb_msg_internal base; -} upb_msg_internal_withext; - static char _upb_fieldtype_to_sizelg2[12] = { 0, 0, /* UPB_TYPE_BOOL */ diff --git a/upb/msg.h b/upb/msg.h index 71bbac67c3..6b6dafa19e 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -55,7 +55,22 @@ typedef struct upb_msglayout { /** upb_msg *******************************************************************/ -/* Representation is in msg.c for now. */ +/* Internal members of a upb_msg. We can change this without breaking binary + * compatibility. We put these before the user's data. The user's upb_msg* + * points after the upb_msg_internal. */ + +/* Used when a message is not extendable. */ +typedef struct { + char *unknown; + size_t unknown_len; + size_t unknown_size; +} upb_msg_internal; + +/* Used when a message is extendable. */ +typedef struct { + upb_inttable *extdict; + upb_msg_internal base; +} upb_msg_internal_withext; /* Maps upb_fieldtype_t -> memory size. */ extern char _upb_fieldtype_to_size[12]; diff --git a/upb/reflection.c b/upb/reflection.c index 756fd7a07a..f1e20e59d4 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -223,7 +223,6 @@ bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { ret = upb_strtable_lookup2(&map->table, strkey.data, strkey.size, &tabval); if (ret) { *val = upb_map_fromvalue(map->val_size_lg2, tabval); - memcpy(val, &tabval, sizeof(tabval)); } return ret; diff --git a/upb/reflection.h b/upb/reflection.h index d6825dbc82..58fa7ee7a2 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -1,6 +1,6 @@ -#ifndef UPB_LEGACY_MSG_REFLECTION_H_ -#define UPB_LEGACY_MSG_REFLECTION_H_ +#ifndef UPB_REFLECTION_H_ +#define UPB_REFLECTION_H_ #include "upb/def.h" #include "upb/msg.h" @@ -134,4 +134,4 @@ bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2); #include "upb/port_undef.inc" -#endif /* UPB_LEGACY_MSG_REFLECTION_H_ */ +#endif /* UPB_REFLECTION_H_ */ diff --git a/upb/upb.h b/upb/upb.h index e4c8adea67..aec97e0611 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -358,8 +358,6 @@ typedef enum { UPB_DESCRIPTOR_TYPE_SINT64 = 18 } upb_descriptortype_t; -extern const uint8_t upb_desctype_to_fieldtype[]; - #include "upb/port_undef.inc" #endif /* UPB_H_ */ diff --git a/upbc/message_layout.cc b/upbc/message_layout.cc index f0a68725c2..bf3eb2b3bd 100644 --- a/upbc/message_layout.cc +++ b/upbc/message_layout.cc @@ -1,5 +1,6 @@ #include "upbc/message_layout.h" +#include "google/protobuf/descriptor.pb.h" namespace upbc { @@ -25,12 +26,18 @@ MessageLayout::Size MessageLayout::Place( bool MessageLayout::HasHasbit(const protobuf::FieldDescriptor* field) { return field->file()->syntax() == protobuf::FileDescriptor::SYNTAX_PROTO2 && field->label() != protobuf::FieldDescriptor::LABEL_REPEATED && - !field->containing_oneof(); + !field->containing_oneof() && + !field->containing_type()->options().map_entry(); } MessageLayout::SizeAndAlign MessageLayout::SizeOf( const protobuf::FieldDescriptor* field) { - if (field->is_repeated()) { + if (field->containing_type()->options().map_entry()) { + // Map entries aren't actually stored, they are only used during parsing. + // For parsing, it helps a lot if all map entry messages have the same + // layout. + return {{8, 16}, {4, 8}}; // upb_stringview + } else if (field->is_repeated()) { return {{4, 8}, {4, 8}}; // Pointer to array object. } else { return SizeOfUnwrapped(field); From 92509cc3b26b3d7d379e3ee81050631fe839f55d Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 16:40:11 -0800 Subject: [PATCH 19/35] Rename lua_test. --- BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD b/BUILD index 234c487a81..c12aae8425 100644 --- a/BUILD +++ b/BUILD @@ -583,7 +583,7 @@ cc_library( ) cc_test( - name = "lua_tester", + name = "test_lua", linkstatic = 1, srcs = ["tests/bindings/lua/main.c"], data = [ From e18541a9ddf4d13d114f962cd0d6adec95eeb6d9 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 16:53:23 -0800 Subject: [PATCH 20/35] Added some missing files. --- upb/bindings/lua/lua_proto_library.bzl | 116 +++++++++++++++++++++++++ upb/bindings/lua/upb.lua | 30 +++++++ upb/bindings/lua/upbc.cc | 112 ++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 upb/bindings/lua/lua_proto_library.bzl create mode 100644 upb/bindings/lua/upb.lua create mode 100644 upb/bindings/lua/upbc.cc diff --git a/upb/bindings/lua/lua_proto_library.bzl b/upb/bindings/lua/lua_proto_library.bzl new file mode 100644 index 0000000000..51c611cf31 --- /dev/null +++ b/upb/bindings/lua/lua_proto_library.bzl @@ -0,0 +1,116 @@ + +load("@bazel_skylib//lib:paths.bzl", "paths") +load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") + +# copybara:strip_for_google3_begin +load("@bazel_skylib//lib:versions.bzl", "versions") +load("@bazel_version//:bazel_version.bzl", "bazel_version") +# copybara:strip_end + +# Generic support code ######################################################### + +_is_bazel = not hasattr(native, "genmpm") + +def _get_real_short_path(file): + # For some reason, files from other archives have short paths that look like: + # ../com_google_protobuf/google/protobuf/descriptor.proto + short_path = file.short_path + if short_path.startswith("../"): + second_slash = short_path.index("/", 3) + short_path = short_path[second_slash + 1:] + # Sometimes it has another few prefixes like: + # _virtual_imports/any_proto/google/protobuf/any.proto + # We want just google/protobuf/any.proto. + if short_path.startswith("_virtual_imports"): + short_path = short_path.split("/", 2)[-1] + return short_path + +def _get_real_root(file): + real_short_path = _get_real_short_path(file) + return file.path[:-len(real_short_path) - 1] + +def _generate_output_file(ctx, src, extension): + real_short_path = _get_real_short_path(src) + real_short_path = paths.relativize(real_short_path, ctx.label.package) + output_filename = paths.replace_extension(real_short_path, extension) + ret = ctx.actions.declare_file(output_filename) + return ret + +# upb_proto_library / upb_proto_reflection_library shared code ################# + +_LuaFiles = provider(fields = ["files"]) + +def _compile_upb_protos(ctx, proto_info, proto_sources): + files = [_generate_output_file(ctx, name, "_pb.lua") for name in proto_sources] + transitive_sets = proto_info.transitive_descriptor_sets.to_list() + ctx.actions.run( + inputs = depset( + direct = [proto_info.direct_descriptor_set], + transitive = [proto_info.transitive_descriptor_sets], + ), + tools = [ctx.executable._upbc], + outputs = files, + executable = ctx.executable._protoc, + arguments = [ + "--lua_out=" + _get_real_root(files[0]), + "--plugin=protoc-gen-lua=" + ctx.executable._upbc.path, + "--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]), + ] + + [_get_real_short_path(file) for file in proto_sources], + progress_message = "Generating Lua protos for :" + ctx.label.name, + ) + return files + +def _lua_proto_rule_impl(ctx): + if len(ctx.attr.deps) != 1: + fail("only one deps dependency allowed.") + dep = ctx.attr.deps[0] + if _LuaFiles not in dep: + fail("proto_library rule must generate _LuaFiles (aspect should have handled this).") + files = dep[_LuaFiles].files + print(files) + return [ + DefaultInfo( + files = files, + data_runfiles = ctx.runfiles(files = files.to_list())), + ] + +def _lua_proto_library_aspect_impl(target, ctx): + proto_info = target[ProtoInfo] + files = _compile_upb_protos(ctx, proto_info, proto_info.direct_sources) + deps = ctx.rule.attr.deps + transitive = [dep[_LuaFiles].files for dep in deps if _LuaFiles in dep] + return [_LuaFiles(files = depset(direct = files, transitive = transitive))] + +# lua_proto_library() ########################################################## + +_lua_proto_library_aspect = aspect( + attrs = { + "_upbc": attr.label( + executable = True, + cfg = "host", + default = "//:protoc-gen-lua", + ), + "_protoc": attr.label( + executable = True, + cfg = "host", + default = "@com_google_protobuf//:protoc", + ), + }, + implementation = _lua_proto_library_aspect_impl, + provides = [_LuaFiles], + attr_aspects = ["deps"], + fragments = ["cpp"], +) + +lua_proto_library = rule( + output_to_genfiles = True, + implementation = _lua_proto_rule_impl, + attrs = { + "deps": attr.label_list( + aspects = [_lua_proto_library_aspect], + allow_rules = ["proto_library"], + providers = [ProtoInfo], + ), + }, +) diff --git a/upb/bindings/lua/upb.lua b/upb/bindings/lua/upb.lua new file mode 100644 index 0000000000..ad6184a3d3 --- /dev/null +++ b/upb/bindings/lua/upb.lua @@ -0,0 +1,30 @@ + +local upb = require("lupb") + +upb.generated_pool = upb.SymbolTable() + +local module_metatable = { + __index = function(t, k) + local package = t._filedef:package() + if package then + k = package .. "." .. k + end + local pool = upb.generated_pool + local def = pool:lookup_msg(k) or pool:lookup_enum(k) + local v = nil + if def and def:file():name() == t._filedef:name() then + v = def + t[k] = v + end + return v + end +} + +function upb._generated_module(desc_string) + local file = upb.generated_pool:add_file(desc_string) + local module = {_filedef = file} + setmetatable(module, module_metatable) + return module +end + +return upb diff --git a/upb/bindings/lua/upbc.cc b/upb/bindings/lua/upbc.cc new file mode 100644 index 0000000000..e7563bc0ba --- /dev/null +++ b/upb/bindings/lua/upbc.cc @@ -0,0 +1,112 @@ + +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "absl/strings/str_replace.h" +#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include +#include + +namespace protoc = ::google::protobuf::compiler; +namespace protobuf = ::google::protobuf; + +class LuaGenerator : public protoc::CodeGenerator { + bool Generate(const protobuf::FileDescriptor* file, + const std::string& parameter, protoc::GeneratorContext* context, + std::string* error) const override; + +}; + +static std::string StripExtension(absl::string_view fname) { + size_t lastdot = fname.find_last_of("."); + if (lastdot == std::string::npos) { + return std::string(fname); + } + return std::string(fname.substr(0, lastdot)); +} + +static std::string Filename(const protobuf::FileDescriptor* file) { + return StripExtension(file->name()) + "_pb.lua"; +} + +static std::string ModuleName(const protobuf::FileDescriptor* file) { + std::string ret = StripExtension(file->name()) + "_pb"; + return absl::StrReplaceAll(ret, {{"/", "."}}); +} + +static void PrintHexDigit(char digit, protobuf::io::Printer* printer) { + char text; + if (digit < 10) { + text = '0' + digit; + } else { + text = 'A' + (digit - 10); + } + printer->WriteRaw(&text, 1); +} + +static void PrintString(int max_cols, absl::string_view* str, + protobuf::io::Printer* printer) { + printer->Print("\'"); + while (max_cols > 0 && !str->empty()) { + char ch = (*str)[0]; + if (ch == '\\') { + printer->PrintRaw("\\\\"); + max_cols--; + } else if (ch == '\'') { + printer->PrintRaw("\\'"); + max_cols--; + } else if (isprint(ch)) { + printer->WriteRaw(&ch, 1); + max_cols--; + } else { + unsigned char byte = ch; + printer->PrintRaw("\\x"); + PrintHexDigit(byte >> 4, printer); + PrintHexDigit(byte & 15, printer); + max_cols -= 4; + } + str->remove_prefix(1); + } + printer->Print("\'"); +} + +bool LuaGenerator::Generate( + const protobuf::FileDescriptor* file, + const std::string& parameter, + protoc::GeneratorContext* context, + std::string* error) const { + std::string filename = Filename(file); + protobuf::io::ZeroCopyOutputStream* out = context->Open(filename); + protobuf::io::Printer printer(out, '$'); + + for (int i = 0; i < file->dependency_count(); i++) { + const protobuf::FileDescriptor* dep = file->dependency(i); + printer.Print("require('$name$')\n", "name", ModuleName(dep)); + } + + printer.Print("local upb = require('upb')\n"); + + protobuf::FileDescriptorProto file_proto; + file->CopyTo(&file_proto); + std::string file_data; + file_proto.SerializeToString(&file_data); + + printer.Print("local descriptor = table.concat({\n"); + absl::string_view data(file_data); + while (!data.empty()) { + printer.Print(" "); + PrintString(72, &data, &printer); + printer.Print(",\n"); + } + printer.Print("})\n"); + + printer.Print("return upb._generated_module(descriptor)\n"); + + return true; +} + +int main(int argc, char** argv) { + LuaGenerator generator; + return google::protobuf::compiler::PluginMain(argc, argv, &generator); +} From c9135e5276afc14359bdfac851ec2ee8a71887b0 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 17:02:34 -0800 Subject: [PATCH 21/35] Fixed the build. --- upb/bindings/lua/lua_proto_library.bzl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/upb/bindings/lua/lua_proto_library.bzl b/upb/bindings/lua/lua_proto_library.bzl index 51c611cf31..266208af90 100644 --- a/upb/bindings/lua/lua_proto_library.bzl +++ b/upb/bindings/lua/lua_proto_library.bzl @@ -1,11 +1,5 @@ load("@bazel_skylib//lib:paths.bzl", "paths") -load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") - -# copybara:strip_for_google3_begin -load("@bazel_skylib//lib:versions.bzl", "versions") -load("@bazel_version//:bazel_version.bzl", "bazel_version") -# copybara:strip_end # Generic support code ######################################################### From 572ba75d1cab81f6c0a3073b7de2ec1365f29446 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 17:14:48 -0800 Subject: [PATCH 22/35] Removed comma after final enumerator. --- upb/upb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upb/upb.h b/upb/upb.h index aec97e0611..b64e4b1697 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -326,7 +326,7 @@ typedef enum { UPB_TYPE_UINT64 = 9, /* Types stored as upb_strview (2 * void*) (probably 8 or 16 bytes). */ UPB_TYPE_STRING = 10, - UPB_TYPE_BYTES = 11, + UPB_TYPE_BYTES = 11 } upb_fieldtype_t; /* The repeated-ness of each field; this matches descriptor.proto. */ From 0fbae939d2fd7af60a70efb2b6813ea2992f7aff Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 17:26:36 -0800 Subject: [PATCH 23/35] Removed stray fprintf(). --- upb/decode.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/upb/decode.c b/upb/decode.c index 0ddc29c5d2..4ffaf7b763 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -45,9 +45,7 @@ typedef struct { upb_decstate *state; } upb_decframe; -#define CHK(x) if (!(x)) { \ - fprintf(stderr, "Failure at %s:%d\n", __FILE__, __LINE__); \ - return 0; } +#define CHK(x) if (!(x)) { return 0; } static bool upb_skip_unknowngroup(upb_decstate *d, int field_number); static bool upb_decode_message(upb_decstate *d, char *msg, From 090a0c33a414ea39858b980f19c9040092e3b14d Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 21:26:23 -0800 Subject: [PATCH 24/35] Fixed VLA error and rewrote the map parsing code to be clearer. --- upb/bindings/lua/lua_proto_library.bzl | 1 - upb/decode.c | 47 ++++++++++++++------------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/upb/bindings/lua/lua_proto_library.bzl b/upb/bindings/lua/lua_proto_library.bzl index 266208af90..f21655140a 100644 --- a/upb/bindings/lua/lua_proto_library.bzl +++ b/upb/bindings/lua/lua_proto_library.bzl @@ -62,7 +62,6 @@ def _lua_proto_rule_impl(ctx): if _LuaFiles not in dep: fail("proto_library rule must generate _LuaFiles (aspect should have handled this).") files = dep[_LuaFiles].files - print(files) return [ DefaultInfo( files = files, diff --git a/upb/decode.c b/upb/decode.c index 4ffaf7b763..8b9b078af3 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -463,16 +463,24 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, const upb_msglayout_field *field, int len) { - /* Max map entry size is string key/val. */ - size_t size = sizeof(upb_msg_internal) + (sizeof(upb_strview) * 2); - char submsg[size]; - char *submsg_ptr = &submsg[sizeof(upb_msg_internal)]; upb_map *map = *(upb_map**)&frame->msg[field->offset]; upb_alloc *alloc = upb_arena_alloc(d->arena); const upb_msglayout *entry = frame->layout->submsgs[field->submsg_index]; - upb_value val; - const char *key; - size_t key_size; + upb_strview key; + upb_strtable *t; + + /* The compiler ensures that all map entry messages have this layout. */ + struct map_entry { + upb_msg_internal internal; + union { + upb_strview str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } k; + union { + upb_strview str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } v; + } ent; if (!map) { /* Lazily create map. */ @@ -489,31 +497,28 @@ static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, } /* Parse map entry. */ - memset(&submsg, 0, size); - CHK(upb_decode_msgfield(d, submsg_ptr, entry, len)); + memset(&ent, 0, sizeof(ent)); + CHK(upb_decode_msgfield(d, &ent.k, entry, len)); /* Insert into map. */ + t = &map->table; + if (map->key_size_lg2 == UPB_MAPTYPE_STRING) { - const upb_strview* key_view = (const upb_strview*)submsg_ptr; - key = key_view->data; - key_size = key_view->size; + key = ent.k.str; } else { - key = submsg_ptr; - key_size = 1 << map->key_size_lg2; + key.data = (const char*)&ent.k; + key.size = 1 << map->key_size_lg2; } if (map->val_size_lg2 == UPB_MAPTYPE_STRING) { upb_strview* val_view = upb_arena_malloc(d->arena, sizeof(*val_view)); CHK(val_view); - memcpy(val_view, submsg_ptr + sizeof(upb_strview), sizeof(upb_strview)); - memset(&val, 0, sizeof(val)); - memcpy(&val, &val_view, sizeof(void*)); - } else { - memcpy(&val, submsg_ptr + sizeof(upb_strview), 8); + *val_view = ent.v.str; + ent.v.val = upb_value_ptr(val_view); } - if (!upb_strtable_lookup2(&map->table, key, key_size, NULL)) { - upb_strtable_insert3(&map->table, key, key_size, val, alloc); + if (!upb_strtable_lookup2(t, key.data, key.size, NULL)) { + upb_strtable_insert3(t, key.data, key.size, ent.v.val, alloc); } return true; } From 6c2d732082862e11aa3f30ce80858ee8000be5a9 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 21:28:58 -0800 Subject: [PATCH 25/35] Fixed upb's map parsing to overwrite existing elements. --- upb/decode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/upb/decode.c b/upb/decode.c index 8b9b078af3..dedf60c3bc 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -517,9 +517,9 @@ static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, ent.v.val = upb_value_ptr(val_view); } - if (!upb_strtable_lookup2(t, key.data, key.size, NULL)) { - upb_strtable_insert3(t, key.data, key.size, ent.v.val, alloc); - } + /* Have to remove first, since upb's table won't overwrite. */ + upb_strtable_remove3(t, key.data, key.size, NULL, alloc); + upb_strtable_insert3(t, key.data, key.size, ent.v.val, alloc); return true; } From 7f5fe52dfa70cc2c71db2a7039bf8ec25037b670 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 10 Dec 2019 22:21:45 -0800 Subject: [PATCH 26/35] Fixes for non-C89 code. --- BUILD | 1 + tests/pb/test_varint.c | 33 +++++++++++++++++++++------------ upb/def.c | 10 +++++----- upb/json/printer.c | 19 +++++++++---------- upb/pb/varint.int.h | 20 ++++++++++---------- upb/reflection.c | 4 ++-- upb/table.c | 2 +- 7 files changed, 49 insertions(+), 40 deletions(-) diff --git a/BUILD b/BUILD index c12aae8425..7c1707d1ab 100644 --- a/BUILD +++ b/BUILD @@ -32,6 +32,7 @@ CPPOPTS = [ COPTS = CPPOPTS + [ # copybara:strip_for_google3_begin "-pedantic", + "-Werror=pedantic", "-Wstrict-prototypes", # copybara:strip_end ] diff --git a/tests/pb/test_varint.c b/tests/pb/test_varint.c index 95a04ab9b8..cdae9dba47 100644 --- a/tests/pb/test_varint.c +++ b/tests/pb/test_varint.c @@ -53,6 +53,13 @@ static void test_varint_for_num(upb_decoderet (*decoder)(const char*), ASSERT(upb_zzenc_64(upb_zzdec_64(num)) == num); } +/* Making up for the lack of 64-bit constants in C89. */ +static uint64_t make_u64(uint32_t high, uint32_t low) { + uint64_t ret = high; + ret = (ret << 32) | low; + return ret; +} + static void test_varint_decoder(upb_decoderet (*decoder)(const char*)) { #define TEST(bytes, expected_val) {\ size_t n = sizeof(bytes) - 1; /* for NULL */ \ @@ -74,18 +81,20 @@ static void test_varint_decoder(upb_decoderet (*decoder)(const char*)) { upb_decoderet r = decoder(twelvebyte_buf); ASSERT(r.p == NULL); - TEST("\x00", 0ULL); - TEST("\x01", 1ULL); - TEST("\x81\x14", 0xa01ULL); - TEST("\x81\x03", 0x181ULL); - TEST("\x81\x83\x07", 0x1c181ULL); - TEST("\x81\x83\x87\x0f", 0x1e1c181ULL); - TEST("\x81\x83\x87\x8f\x1f", 0x1f1e1c181ULL); - TEST("\x81\x83\x87\x8f\x9f\x3f", 0x1f9f1e1c181ULL); - TEST("\x81\x83\x87\x8f\x9f\xbf\x7f", 0x1fdf9f1e1c181ULL); - TEST("\x81\x83\x87\x8f\x9f\xbf\xff\x01", 0x3fdf9f1e1c181ULL); - TEST("\x81\x83\x87\x8f\x9f\xbf\xff\x81\x03", 0x303fdf9f1e1c181ULL); - TEST("\x81\x83\x87\x8f\x9f\xbf\xff\x81\x83\x07", 0x8303fdf9f1e1c181ULL); + TEST("\x00", 0UL); + TEST("\x01", 1UL); + TEST("\x81\x14", 0xa01UL); + TEST("\x81\x03", 0x181UL); + TEST("\x81\x83\x07", 0x1c181UL); + TEST("\x81\x83\x87\x0f", 0x1e1c181UL); + TEST("\x81\x83\x87\x8f\x1f", make_u64(0x1, 0xf1e1c181UL)); + TEST("\x81\x83\x87\x8f\x9f\x3f", make_u64(0x1f9, 0xf1e1c181UL)); + TEST("\x81\x83\x87\x8f\x9f\xbf\x7f", make_u64(0x1fdf9, 0xf1e1c181UL)); + TEST("\x81\x83\x87\x8f\x9f\xbf\xff\x01", make_u64(0x3fdf9, 0xf1e1c181UL)); + TEST("\x81\x83\x87\x8f\x9f\xbf\xff\x81\x03", + make_u64(0x303fdf9, 0xf1e1c181UL)); + TEST("\x81\x83\x87\x8f\x9f\xbf\xff\x81\x83\x07", + make_u64(0x8303fdf9, 0xf1e1c181UL)); #undef TEST for (num = 5; num * 1.5 < UINT64_MAX; num *= 1.5) { diff --git a/upb/def.c b/upb/def.c index a4a2200e3a..12bb104bed 100644 --- a/upb/def.c +++ b/upb/def.c @@ -869,9 +869,9 @@ static size_t upb_msgval_sizeof(upb_fieldtype_t type) { static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) { - // Map entries aren't actually stored, they are only used during parsing. - // For parsing, it helps a lot if all map entry messages have the same - // layout. + /* Map entries aren't actually stored, they are only used during parsing. + * For parsing, it helps a lot if all map entry messages have the same + * layout. */ return sizeof(upb_strview); } else if (upb_fielddef_isseq(f)) { return sizeof(void*); @@ -1188,7 +1188,7 @@ static bool parse_default(const symtab_addctx *ctx, const char *str, size_t len, } case UPB_TYPE_INT64: { /* XXX: Need to write our own strtoll, since it's not available in c89. */ - long long val = strtol(str, &end, 0); + int64_t val = strtol(str, &end, 0); CHK(val <= INT64_MAX && val >= INT64_MIN && errno != ERANGE && !*end); f->defaultval.sint = val; break; @@ -1201,7 +1201,7 @@ static bool parse_default(const symtab_addctx *ctx, const char *str, size_t len, } case UPB_TYPE_UINT64: { /* XXX: Need to write our own strtoull, since it's not available in c89. */ - unsigned long long val = strtoul(str, &end, 0); + uint64_t val = strtoul(str, &end, 0); CHK(val <= UINT64_MAX && errno != ERANGE && !*end); f->defaultval.uint = val; break; diff --git a/upb/json/printer.c b/upb/json/printer.c index 38f817d4d4..a3cb9bdb01 100644 --- a/upb/json/printer.c +++ b/upb/json/printer.c @@ -6,6 +6,7 @@ #include "upb/json/printer.h" #include +#include #include #include #include @@ -208,28 +209,26 @@ static size_t fmt_bool(bool val, char* buf, size_t length) { return n; } -static size_t fmt_int64_as_number(long long val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "%lld", val); +static size_t fmt_int64_as_number(int64_t val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%" PRId64, val); CHKLENGTH(n > 0 && n < length); return n; } -static size_t fmt_uint64_as_number( - unsigned long long val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "%llu", val); +static size_t fmt_uint64_as_number(uint64_t val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%" PRIu64, val); CHKLENGTH(n > 0 && n < length); return n; } -static size_t fmt_int64_as_string(long long val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "\"%lld\"", val); +static size_t fmt_int64_as_string(int64_t val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "\"%" PRId64 "\"", val); CHKLENGTH(n > 0 && n < length); return n; } -static size_t fmt_uint64_as_string( - unsigned long long val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "\"%llu\"", val); +static size_t fmt_uint64_as_string(uint64_t val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "\"%" PRIu64 "\"", val); CHKLENGTH(n > 0 && n < length); return n; } diff --git a/upb/pb/varint.int.h b/upb/pb/varint.int.h index ff1ca66149..293067a5cb 100644 --- a/upb/pb/varint.int.h +++ b/upb/pb/varint.int.h @@ -26,16 +26,16 @@ extern "C" { * descriptor type (upb_descriptortype_t). */ extern const uint8_t upb_pb_native_wire_types[]; -UPB_INLINE uint64_t byteswap64(uint64_t val) -{ - return ((((val) & 0xff00000000000000ull) >> 56) - | (((val) & 0x00ff000000000000ull) >> 40) - | (((val) & 0x0000ff0000000000ull) >> 24) - | (((val) & 0x000000ff00000000ull) >> 8) - | (((val) & 0x00000000ff000000ull) << 8) - | (((val) & 0x0000000000ff0000ull) << 24) - | (((val) & 0x000000000000ff00ull) << 40) - | (((val) & 0x00000000000000ffull) << 56)); +UPB_INLINE uint64_t byteswap64(uint64_t val) { + uint64_t byte = 0xff; + return (val & (byte << 56) >> 56) + | (val & (byte << 48) >> 40) + | (val & (byte << 40) >> 24) + | (val & (byte << 32) >> 8) + | (val & (byte << 24) << 8) + | (val & (byte << 16) << 24) + | (val & (byte << 8) << 40) + | (val & (byte << 0) << 56); } /* Zig-zag encoding/decoding **************************************************/ diff --git a/upb/reflection.c b/upb/reflection.c index f1e20e59d4..e0a6299bb2 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -148,18 +148,18 @@ size_t upb_array_size(const upb_array *arr) { } upb_msgval upb_array_get(const upb_array *arr, size_t i) { - UPB_ASSERT(i < arr->len); upb_msgval ret; const char* data = _upb_array_constptr(arr); int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); memcpy(&ret, data + (i << lg2), 1 << lg2); return ret; } void upb_array_set(upb_array *arr, size_t i, upb_msgval val) { - UPB_ASSERT(i < arr->len); char* data = _upb_array_ptr(arr); int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); memcpy(data + (i << lg2), &val, 1 << lg2); } diff --git a/upb/table.c b/upb/table.c index 63389c0144..5b48bb7e50 100644 --- a/upb/table.c +++ b/upb/table.c @@ -371,9 +371,9 @@ bool upb_strtable_done(const upb_strtable_iter *i) { } upb_strview upb_strtable_iter_key(const upb_strtable_iter *i) { - UPB_ASSERT(!upb_strtable_done(i)); upb_strview key; uint32_t len; + UPB_ASSERT(!upb_strtable_done(i)); key.data = upb_tabstr(str_tabent(i)->key, &len); key.size = len; return key; From 2a85bef825ab5ed8df9df649d7282364267ec195 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 10:39:55 -0800 Subject: [PATCH 27/35] Generated code interface for maps is complete, though not yet tested. --- BUILD | 2 - CMakeLists.txt | 1 - .../google/protobuf/descriptor.upb.h | 1 - tests/bindings/lua/test_upb.lua | 24 ++ tests/bindings/lua/test_upb.pb.lua | 80 ------ upb/bindings/lua/msg.c | 25 +- upb/decode.c | 52 ++-- upb/encode.c | 8 +- upb/generated_util.h | 89 ------- upb/msg.c | 24 +- upb/msg.h | 252 +++++++++++++++++- upb/port_def.inc | 2 +- upb/port_undef.inc | 1 + upb/reflection.c | 147 ++++------ upb/reflection.h | 60 ++--- upb/table.c | 15 +- upb/table.int.h | 5 + upb/upb.h | 2 + upbc/generator.cc | 128 +++++++-- 19 files changed, 509 insertions(+), 409 deletions(-) delete mode 100644 tests/bindings/lua/test_upb.pb.lua delete mode 100644 upb/generated_util.h diff --git a/BUILD b/BUILD index 7c1707d1ab..ceeae4fab9 100644 --- a/BUILD +++ b/BUILD @@ -60,7 +60,6 @@ cc_library( srcs = [ "upb/decode.c", "upb/encode.c", - "upb/generated_util.h", "upb/msg.c", "upb/msg.h", "upb/port.c", @@ -91,7 +90,6 @@ cc_library( cc_library( name = "generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", hdrs = [ - "upb/generated_util.h", "upb/msg.h", ], copts = select({ diff --git a/CMakeLists.txt b/CMakeLists.txt index 1235bdb098..a88176389f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,6 @@ enable_testing() add_library(upb upb/decode.c upb/encode.c - upb/generated_util.h upb/msg.c upb/msg.h upb/port.c diff --git a/generated_for_cmake/google/protobuf/descriptor.upb.h b/generated_for_cmake/google/protobuf/descriptor.upb.h index 33e020011d..5baad08810 100644 --- a/generated_for_cmake/google/protobuf/descriptor.upb.h +++ b/generated_for_cmake/google/protobuf/descriptor.upb.h @@ -9,7 +9,6 @@ #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ #define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ -#include "upb/generated_util.h" #include "upb/msg.h" #include "upb/decode.h" #include "upb/encode.h" diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index 07f7ed0f15..25ec0c1721 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -49,6 +49,18 @@ function test_msg_map() assert_equal(10, msg.map_int32_int32[5]) assert_equal(12, msg.map_int32_int32[6]) + -- Test overwrite. + msg.map_int32_int32[5] = 20 + assert_equal(20, msg.map_int32_int32[5]) + assert_equal(12, msg.map_int32_int32[6]) + msg.map_int32_int32[5] = 10 + + -- Test delete. + msg.map_int32_int32[5] = nil + assert_nil(msg.map_int32_int32[5]) + assert_equal(12, msg.map_int32_int32[6]) + msg.map_int32_int32[5] = 10 + local serialized = upb.encode(msg) assert_true(#serialized > 0) local msg2 = upb.decode(test_messages_proto3.TestAllTypesProto3, serialized) @@ -64,6 +76,18 @@ function test_msg_string_map() assert_equal("bar", msg.map_string_string["foo"]) assert_equal("quux", msg.map_string_string["baz"]) + -- Test overwrite. + msg.map_string_string["foo"] = "123" + assert_equal("123", msg.map_string_string["foo"]) + assert_equal("quux", msg.map_string_string["baz"]) + msg.map_string_string["foo"] = "bar" + + -- Test delete + msg.map_string_string["foo"] = nil + assert_nil(msg.map_string_string["foo"]) + assert_equal("quux", msg.map_string_string["baz"]) + msg.map_string_string["foo"] = "bar" + local serialized = upb.encode(msg) assert_true(#serialized > 0) local msg2 = upb.decode(test_messages_proto3.TestAllTypesProto3, serialized) diff --git a/tests/bindings/lua/test_upb.pb.lua b/tests/bindings/lua/test_upb.pb.lua deleted file mode 100644 index ea6de09989..0000000000 --- a/tests/bindings/lua/test_upb.pb.lua +++ /dev/null @@ -1,80 +0,0 @@ - --- Require "pb" first to ensure that the transitive require of "upb" is --- handled properly by the "pb" module. -local pb = require "upb.pb" -local upb = require "upb" -local lunit = require "lunit" - -if _VERSION >= 'Lua 5.2' then - _ENV = lunit.module("testupb_pb", "seeall") -else - module("testupb_pb", lunit.testcase, package.seeall) -end - -local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage", fields = { - upb.FieldDef{name = "i32", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "u32", number = 2, type = upb.TYPE_UINT32}, - upb.FieldDef{name = "i64", number = 3, type = upb.TYPE_INT64}, - upb.FieldDef{name = "u64", number = 4, type = upb.TYPE_UINT64}, - upb.FieldDef{name = "dbl", number = 5, type = upb.TYPE_DOUBLE}, - upb.FieldDef{name = "flt", number = 6, type = upb.TYPE_FLOAT}, - upb.FieldDef{name = "bool", number = 7, type = upb.TYPE_BOOL}, - } - } -} - -local factory = upb.MessageFactory(symtab); -local TestMessage = factory:get_message_class("TestMessage") - -function test_parse_primitive() - local binary_pb = - "\008\128\128\128\128\002\016\128\128\128\128\004\024\128\128" - .. "\128\128\128\128\128\002\032\128\128\128\128\128\128\128\001\041\000" - .. "\000\000\000\000\000\248\063\053\000\000\096\064\056\001" - local msg = TestMessage() - pb.decode(msg, binary_pb) - assert_equal(536870912, msg.i32) - assert_equal(1073741824, msg.u32) - assert_equal(1125899906842624, msg.i64) - assert_equal(562949953421312, msg.u64) - assert_equal(1.5, msg.dbl) - assert_equal(3.5, msg.flt) - assert_equal(true, msg.bool) - - local encoded = pb.encode(msg) - local msg2 = TestMessage() - pb.decode(msg2, encoded) - assert_equal(536870912, msg.i32) - assert_equal(1073741824, msg.u32) - assert_equal(1125899906842624, msg.i64) - assert_equal(562949953421312, msg.u64) - assert_equal(1.5, msg.dbl) - assert_equal(3.5, msg.flt) - assert_equal(true, msg.bool) -end - -function test_parse_string() - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage", fields = { - upb.FieldDef{name = "str", number = 1, type = upb.TYPE_STRING}, - } - } - } - - local factory = upb.MessageFactory(symtab); - local TestMessage = factory:get_message_class("TestMessage") - - local binary_pb = "\010\005Hello" - msg = TestMessage() - pb.decode(msg, binary_pb) - -- TODO(haberman): re-enable when this stuff works better. - -- assert_equal("Hello", msg.str) -end - - -local stats = lunit.main() - -if stats.failed > 0 or stats.errors > 0 then - error("One or more errors in test suite") -end diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index b611cee8e6..aee9238e68 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -592,7 +592,7 @@ static int lupb_map_newindex(lua_State *L) { upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF); if (lua_isnil(L, 3)) { - upb_map_delete(map, key, lupb_arenaget(L, 1)); + upb_map_delete(map, key); } else { upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, 1, LUPB_COPY); upb_map_set(map, key, val, lupb_arenaget(L, 1)); @@ -603,18 +603,19 @@ static int lupb_map_newindex(lua_State *L) { static int lupb_mapiter_next(lua_State *L) { int map = lua_upvalueindex(2); - upb_mapiter *i = lua_touserdata(L, lua_upvalueindex(1)); + size_t *iter = lua_touserdata(L, lua_upvalueindex(1)); lupb_map *lmap = lupb_map_check(L, map); - if (upb_mapiter_done(i)) { + if (upb_mapiter_next(lmap->map, iter)) { + upb_msgval key = upb_mapiter_key(lmap->map, *iter); + upb_msgval val = upb_mapiter_value(lmap->map, *iter); + lupb_pushmsgval(L, map, lmap->key_type, key); + lupb_pushmsgval(L, map, lmap->value_type, val); + return 2; + } else { return 0; } - lupb_pushmsgval(L, map, lmap->key_type, upb_mapiter_key(i)); - lupb_pushmsgval(L, map, lmap->value_type, upb_mapiter_value(i)); - upb_mapiter_next(i); - - return 2; } /** @@ -624,13 +625,13 @@ static int lupb_mapiter_next(lua_State *L) { * pairs(map) */ static int lupb_map_pairs(lua_State *L) { - lupb_map *lmap = lupb_map_check(L, 1); - upb_mapiter *i = lua_newuserdata(L, upb_mapiter_sizeof()); + lupb_map_check(L, 1); + size_t *iter = lua_newuserdata(L, sizeof(*iter)); - upb_mapiter_begin(i, lmap->map); + *iter = UPB_MAP_BEGIN; lua_pushvalue(L, 1); - /* Upvalues are [upb_mapiter, lupb_map]. */ + /* Upvalues are [iter, lupb_map]. */ lua_pushcclosure(L, &lupb_mapiter_next, 2); return 1; diff --git a/upb/decode.c b/upb/decode.c index dedf60c3bc..042045da2d 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -28,6 +28,29 @@ const uint8_t desctype_to_fieldtype[] = { UPB_TYPE_INT64, /* SINT64 */ }; +/* Maps descriptor type -> upb map size. */ +const uint8_t desctype_to_mapsize[] = { + UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ + 8, /* DOUBLE */ + 4, /* FLOAT */ + 8, /* INT64 */ + 8, /* UINT64 */ + 4, /* INT32 */ + 8, /* FIXED64 */ + 4, /* FIXED32 */ + 1, /* BOOL */ + UPB_MAPTYPE_STRING, /* STRING */ + sizeof(void*), /* GROUP */ + sizeof(void*), /* MESSAGE */ + UPB_MAPTYPE_STRING, /* BYTES */ + 4, /* UINT32 */ + 4, /* ENUM */ + 4, /* SFIXED32 */ + 8, /* SFIXED64 */ + 4, /* SINT32 */ + 8, /* SINT64 */ +}; + /* Data pertaining to the parse. */ typedef struct { const char *ptr; /* Current parsing position. */ @@ -464,10 +487,7 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, const upb_msglayout_field *field, int len) { upb_map *map = *(upb_map**)&frame->msg[field->offset]; - upb_alloc *alloc = upb_arena_alloc(d->arena); const upb_msglayout *entry = frame->layout->submsgs[field->submsg_index]; - upb_strview key; - upb_strtable *t; /* The compiler ensures that all map entry messages have this layout. */ struct map_entry { @@ -486,13 +506,13 @@ static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, /* Lazily create map. */ const upb_msglayout_field *key_field = &entry->fields[0]; const upb_msglayout_field *val_field = &entry->fields[1]; - upb_fieldtype_t key_type = desctype_to_fieldtype[key_field->descriptortype]; - upb_fieldtype_t val_type = desctype_to_fieldtype[val_field->descriptortype]; + char key_size = desctype_to_mapsize[key_field->descriptortype]; + char val_size = desctype_to_mapsize[val_field->descriptortype]; UPB_ASSERT(key_field->number == 1); UPB_ASSERT(val_field->number == 2); UPB_ASSERT(key_field->offset == 0); UPB_ASSERT(val_field->offset == sizeof(upb_strview)); - map = upb_map_new(frame->state->arena, key_type, val_type); + map = _upb_map_new(frame->state->arena, key_size, val_size); *(upb_map**)&frame->msg[field->offset] = map; } @@ -501,25 +521,7 @@ static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, CHK(upb_decode_msgfield(d, &ent.k, entry, len)); /* Insert into map. */ - t = &map->table; - - if (map->key_size_lg2 == UPB_MAPTYPE_STRING) { - key = ent.k.str; - } else { - key.data = (const char*)&ent.k; - key.size = 1 << map->key_size_lg2; - } - - if (map->val_size_lg2 == UPB_MAPTYPE_STRING) { - upb_strview* val_view = upb_arena_malloc(d->arena, sizeof(*val_view)); - CHK(val_view); - *val_view = ent.v.str; - ent.v.val = upb_value_ptr(val_view); - } - - /* Have to remove first, since upb's table won't overwrite. */ - upb_strtable_remove3(t, key.data, key.size, NULL, alloc); - upb_strtable_insert3(t, key.data, key.size, ent.v.val, alloc); + _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, d->arena); return true; } diff --git a/upb/encode.c b/upb/encode.c index 9314c1d500..d9adbff596 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -330,10 +330,10 @@ static bool upb_encode_map(upb_encstate *e, const char *field_mem, size_t size; upb_strview key = upb_strtable_iter_key(&i); const upb_value val = upb_strtable_iter_value(&i); - const void* keyp = - map->key_size_lg2 == UPB_MAPTYPE_STRING ? (void*)&key : key.data; - const void* valp = - map->val_size_lg2 == UPB_MAPTYPE_STRING ? upb_value_getptr(val) : &val; + const void *keyp = + map->key_size == UPB_MAPTYPE_STRING ? (void *)&key : key.data; + const void *valp = + map->val_size == UPB_MAPTYPE_STRING ? upb_value_getptr(val) : &val; CHK(upb_encode_scalarfield(e, valp, entry, val_field, false)); CHK(upb_encode_scalarfield(e, keyp, entry, key_field, false)); diff --git a/upb/generated_util.h b/upb/generated_util.h deleted file mode 100644 index ac01a27b5c..0000000000 --- a/upb/generated_util.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -** Functions for use by generated code. These are not public and users must -** not call them directly. -*/ - -#ifndef UPB_GENERATED_UTIL_H_ -#define UPB_GENERATED_UTIL_H_ - -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -#define PTR_AT(msg, ofs, type) (type*)((const char*)msg + ofs) - -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*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_constptr(arr); - } else { - if (size) *size = 0; - return NULL; - } -} - -UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, - size_t *size) { - upb_array *arr = *PTR_AT(msg, ofs, upb_array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_ptr(arr); - } else { - if (size) *size = 0; - return NULL; - } -} - -UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, - upb_fieldtype_t type, - upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); - upb_array *arr = *arr_ptr; - if (!arr || arr->size < size) { - return _upb_array_resize_fallback(arr_ptr, size, type, arena); - } - arr->len = size; - return _upb_array_ptr(arr); -} - -UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, - size_t elem_size, - upb_fieldtype_t type, - const void *value, - upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); - upb_array *arr = *arr_ptr; - void* ptr; - if (!arr || arr->len == arr->size) { - return _upb_array_append_fallback(arr_ptr, value, type, arena); - } - ptr = _upb_array_ptr(arr); - memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); - arr->len++; - return true; -} - -UPB_INLINE bool _upb_has_field(const void *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; -} - -UPB_INLINE bool _upb_sethas(const void *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); -} - -UPB_INLINE bool _upb_clearhas(const void *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); -} - -UPB_INLINE bool _upb_has_oneof_field(const void *msg, size_t case_ofs, int32_t num) { - return *PTR_AT(msg, case_ofs, int32_t) == num; -} - -#undef PTR_AT - -#include "upb/port_undef.inc" - -#endif /* UPB_GENERATED_UTIL_H_ */ diff --git a/upb/msg.c b/upb/msg.c index b27fa41a92..bd3d347d58 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -24,22 +24,6 @@ static char _upb_fieldtype_to_sizelg2[12] = { UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */ }; -/* Strings/bytes are special-cased in maps. */ -static char _upb_fieldtype_to_mapsizelg2[12] = { - 0, - 0, /* UPB_TYPE_BOOL */ - 2, /* UPB_TYPE_FLOAT */ - 2, /* UPB_TYPE_INT32 */ - 2, /* UPB_TYPE_UINT32 */ - 2, /* UPB_TYPE_ENUM */ - UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */ - 3, /* UPB_TYPE_DOUBLE */ - 3, /* UPB_TYPE_INT64 */ - 3, /* UPB_TYPE_UINT64 */ - UPB_MAPTYPE_STRING, /* UPB_TYPE_STRING */ - UPB_MAPTYPE_STRING, /* UPB_TYPE_BYTES */ -}; - static uintptr_t tag_arrptr(void* ptr, int elem_size_lg2) { UPB_ASSERT(elem_size_lg2 <= 4); return (uintptr_t)ptr | elem_size_lg2; @@ -172,8 +156,7 @@ void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, /** upb_map *******************************************************************/ -upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, - upb_fieldtype_t value_type) { +upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) { upb_map *map = upb_arena_malloc(a, sizeof(upb_map)); if (!map) { @@ -181,11 +164,10 @@ upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, } upb_strtable_init2(&map->table, UPB_CTYPE_INT32, upb_arena_alloc(a)); - map->key_size_lg2 = _upb_fieldtype_to_mapsizelg2[key_type]; - map->val_size_lg2 = _upb_fieldtype_to_mapsizelg2[value_type]; + map->key_size = key_size; + map->val_size = value_size; return map; } - #undef VOIDPTR_AT diff --git a/upb/msg.h b/upb/msg.h index 6b6dafa19e..da226f917a 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -1,6 +1,6 @@ /* ** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possible reflection. +** Functions in this file are used by generated code and possibly reflection. ** ** The definitions in this file are internal to upb. **/ @@ -20,6 +20,8 @@ extern "C" { #endif +#define PTR_AT(msg, ofs, type) (type*)((const char*)msg + ofs) + typedef void upb_msg; /** upb_msglayout *************************************************************/ @@ -86,6 +88,22 @@ void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, /* Returns a reference to the message's unknown data. */ const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); +UPB_INLINE bool _upb_has_field(const void *msg, size_t idx) { + return (*PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; +} + +UPB_INLINE bool _upb_sethas(const void *msg, size_t idx) { + return (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); +} + +UPB_INLINE bool _upb_clearhas(const void *msg, size_t idx) { + return (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); +} + +UPB_INLINE bool _upb_has_oneof_field(const void *msg, size_t case_ofs, int32_t num) { + return *PTR_AT(msg, case_ofs, int32_t) == num; +} + /** upb_array *****************************************************************/ /* Our internal representation for repeated fields. */ @@ -115,21 +133,243 @@ void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, upb_fieldtype_t type, upb_arena *arena); +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*); + if (arr) { + if (size) *size = arr->len; + return _upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, + size_t *size) { + upb_array *arr = *PTR_AT(msg, ofs, upb_array*); + if (arr) { + if (size) *size = arr->len; + return _upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, + upb_fieldtype_t type, + upb_arena *arena) { + upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); + upb_array *arr = *arr_ptr; + if (!arr || arr->size < size) { + return _upb_array_resize_fallback(arr_ptr, size, type, arena); + } + arr->len = size; + return _upb_array_ptr(arr); +} + + +UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, + size_t elem_size, + upb_fieldtype_t type, + const void *value, + upb_arena *arena) { + upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); + upb_array *arr = *arr_ptr; + void* ptr; + if (!arr || arr->len == arr->size) { + return _upb_array_append_fallback(arr_ptr, value, type, arena); + } + ptr = _upb_array_ptr(arr); + memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); + arr->len++; + return true; +} + /** upb_map *******************************************************************/ /* Right now we use strmaps for everything. We'll likely want to use * integer-specific maps for integer-keyed maps.*/ typedef struct { - /* We should pack these better and move them into table to avoid padding. */ - char key_size_lg2; - char val_size_lg2; + /* Size of key and val, based on the map type. Strings are represented as '0' + * because they must be handled specially. */ + char key_size; + char val_size; upb_strtable table; } upb_map; /* Creates a new map on the given arena with this key/value type. */ -upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, - upb_fieldtype_t value_type); +upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size); + +/* Converting between internal table representation and user values. + * + * _upb_map_tokey() and _upb_map_fromkey() are inverses. + * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. + * + * These functions account for the fact that strings are treated differently + * from other types when stored in a map. + */ + +UPB_INLINE upb_strview _upb_map_tokey(const void *key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_strview*)key; + } else { + return upb_strview_make((const char*)key, size); + } +} + +UPB_INLINE void _upb_map_fromkey(upb_strview key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} + +UPB_INLINE upb_value _upb_map_tovalue(const void *val, size_t size, + upb_arena *a) { + upb_value ret = {0}; + if (size == UPB_MAPTYPE_STRING) { + upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp)); + *strp = *(upb_strview*)val; + memcpy(&ret, &strp, sizeof(strp)); + } else { + memcpy(&ret, val, size); + } + return ret; +} + +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_strview *strp = (const upb_strview*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_strview)); + } else { + memcpy(out, &val, size); + } +} + +/* Map operations, shared by reflection and generated code. */ + +UPB_INLINE size_t _upb_map_size(const upb_map *map) { + return map->table.t.count; +} + +UPB_INLINE bool _upb_map_get(const upb_map *map, const void *key, + size_t key_size, void *val, size_t val_size) { + upb_value tabval; + upb_strview k = _upb_map_tokey(key, key_size); + bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); + if (ret) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; +} + +UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) { + upb_strtable_iter it = {&map->table, *iter}; + upb_strtable_next(&it); + if (upb_strtable_done(&it)) return NULL; + *iter = it.index; + return (void*)str_tabent(&it); +} + +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) { + upb_strview strkey = _upb_map_tokey(key, key_size); + upb_value tabval = _upb_map_tovalue(val, val_size, arena); + upb_alloc *a = upb_arena_alloc(arena); + + /* 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_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); +} + +UPB_INLINE void _upb_map_clear(upb_map *map) { + upb_strtable_clear(&map->table); +} + +/* Message map operations, these get the map from the message first. */ + +UPB_INLINE size_t _upb_msg_map_size(const upb_msg *msg, size_t ofs) { + upb_map *map = UPB_FIELD_AT(msg, upb_map *, ofs); + return map ? _upb_map_size(map) : 0; +} + +UPB_INLINE bool _upb_msg_map_get(const upb_msg *msg, size_t ofs, + const void *key, size_t key_size, void *val, + size_t val_size) { + upb_map *map = UPB_FIELD_AT(msg, upb_map *, ofs); + if (!map) return false; + return _upb_map_get(map, key, key_size, val, val_size); +} + +UPB_INLINE void *_upb_msg_map_next(const upb_msg *msg, size_t ofs, + size_t *iter) { + upb_map *map = UPB_FIELD_AT(msg, upb_map *, ofs); + if (!map) return NULL; + return _upb_map_next(map, iter); +} + +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 *); + if (!*map) { + *map = _upb_map_new(arena, key_size, val_size); + } + return _upb_map_set(*map, key, key_size, val, val_size, arena); +} + +UPB_INLINE bool _upb_msg_map_delete(upb_msg *msg, size_t ofs, const void *key, + size_t key_size) { + upb_map *map = UPB_FIELD_AT(msg, upb_map *, ofs); + if (!map) return false; + return _upb_map_delete(map, key, key_size); +} + +UPB_INLINE void _upb_msg_map_clear(upb_msg *msg, size_t ofs) { + upb_map *map = UPB_FIELD_AT(msg, upb_map *, ofs); + if (!map) return; + _upb_map_clear(map); +} + +/* Accessing map key/value from a pointer, used by generated code only. */ + +UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { + const upb_tabent *ent = (const upb_tabent*)msg; + uint32_t u32len; + upb_strview k = {upb_tabstr(ent->key, &u32len)}; + k.size = u32len; + _upb_map_fromkey(k, key, 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_map_fromvalue(v, val, size); +} + +UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size) { + upb_tabent *ent = (upb_tabent*)msg; + /* This is like _upb_map_tovalue() except the entry already exists so we can + * reuse the allocated upb_strview for string fields. */ + if (size == UPB_MAPTYPE_STRING) { + upb_strview *strp = (upb_strview*)ent->val.val; + memcpy(strp, val, sizeof(*strp)); + } else { + memcpy(&ent->val.val, val, size); + } +} + +#undef PTR_AT #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/port_def.inc b/upb/port_def.inc index 138c7a0c4f..a8e5070695 100644 --- a/upb/port_def.inc +++ b/upb/port_def.inc @@ -45,7 +45,7 @@ UPB_FIELD_AT(msg, int, case_offset) = case_val; \ UPB_FIELD_AT(msg, fieldtype, offset) = value; -#define UPB_MAPTYPE_STRING 4 +#define UPB_MAPTYPE_STRING 0 /* UPB_INLINE: inline if possible, emit standalone code if required. */ #ifdef __cplusplus diff --git a/upb/port_undef.inc b/upb/port_undef.inc index 103180b7fb..6a4daa5076 100644 --- a/upb/port_undef.inc +++ b/upb/port_undef.inc @@ -1,5 +1,6 @@ /* See port_def.inc. This should #undef all macros #defined there. */ +#undef UPB_MAPTYPE_STRING #undef UPB_SIZE #undef UPB_FIELD_AT #undef UPB_READ_ONEOF diff --git a/upb/reflection.c b/upb/reflection.c index e0a6299bb2..11db23b999 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -7,7 +7,7 @@ #include "upb/port_def.inc" -char field_size[] = { +static char field_size[] = { 0,/* 0 */ 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE */ 4, /* UPB_DESCRIPTOR_TYPE_FLOAT */ @@ -29,6 +29,22 @@ char field_size[] = { 8, /* UPB_DESCRIPTOR_TYPE_SINT64 */ }; +/* Strings/bytes are special-cased in maps. */ +static char _upb_fieldtype_to_mapsize[12] = { + 0, + 1, /* UPB_TYPE_BOOL */ + 4, /* UPB_TYPE_FLOAT */ + 4, /* UPB_TYPE_INT32 */ + 4, /* UPB_TYPE_UINT32 */ + 4, /* UPB_TYPE_ENUM */ + sizeof(void*), /* UPB_TYPE_MESSAGE */ + 8, /* UPB_TYPE_DOUBLE */ + 8, /* UPB_TYPE_INT64 */ + 8, /* UPB_TYPE_UINT64 */ + 0, /* UPB_TYPE_STRING */ + 0, /* UPB_TYPE_BYTES */ +}; + /** upb_msg *******************************************************************/ /* If we always read/write as a consistent type to each address, this shouldn't @@ -66,7 +82,8 @@ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { const char *mem = PTR_AT(msg, field->offset, char); upb_msgval val; if (field->presence == 0 || upb_msg_has(msg, f)) { - int size = upb_fielddef_isseq(f) ? sizeof(void*) : field_size[field->descriptortype]; + int size = upb_fielddef_isseq(f) ? sizeof(void *) + : field_size[field->descriptortype]; memcpy(&val, mem, size); } else { /* TODO(haberman): change upb_fielddef to not require this switch(). */ @@ -132,7 +149,8 @@ void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, upb_arena *a) { const upb_msglayout_field *field = upb_fielddef_layout(f); char *mem = PTR_AT(msg, field->offset, char); - int size = upb_fielddef_isseq(f) ? sizeof(void*) : field_size[field->descriptortype]; + int size = upb_fielddef_isseq(f) ? sizeof(void *) + : field_size[field->descriptortype]; memcpy(mem, &val, size); if (in_oneof(field)) { *oneofcase(msg, field) = field->number; @@ -180,123 +198,48 @@ bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) { /** upb_map *******************************************************************/ -size_t upb_map_size(const upb_map *map) { - return upb_strtable_count(&map->table); +upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, + upb_fieldtype_t value_type) { + return _upb_map_new(a, _upb_fieldtype_to_mapsize[key_type], + _upb_fieldtype_to_mapsize[value_type]); } -static upb_strview upb_map_tokey(int size_lg2, upb_msgval *key) { - if (size_lg2 == UPB_MAPTYPE_STRING) { - return key->str_val; - } else { - return upb_strview_make((const char*)key, 1 << size_lg2); - } -} - -static upb_msgval upb_map_fromvalue(int size_lg2, upb_value val) { - upb_msgval ret; - if (size_lg2 == UPB_MAPTYPE_STRING) { - upb_strview *strp = upb_value_getptr(val); - ret.str_val = *strp; - } else { - memcpy(&ret, &val, 8); - } - return ret; -} - -static upb_value upb_map_tovalue(int size_lg2, upb_msgval val, upb_arena *a) { - upb_value ret; - if (size_lg2 == UPB_MAPTYPE_STRING) { - upb_strview *strp = upb_arena_malloc(a, sizeof(*strp)); - *strp = val.str_val; - ret = upb_value_ptr(strp); - } else { - memcpy(&ret, &val, 8); - } - return ret; +size_t upb_map_size(const upb_map *map) { + return _upb_map_size(map); } bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { - upb_strview strkey = upb_map_tokey(map->key_size_lg2, &key); - upb_value tabval; - bool ret; - - ret = upb_strtable_lookup2(&map->table, strkey.data, strkey.size, &tabval); - if (ret) { - *val = upb_map_fromvalue(map->val_size_lg2, tabval); - } - - return ret; + return _upb_map_get(map, &key, map->key_size, val, map->val_size); } bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, upb_arena *arena) { - upb_strview strkey = upb_map_tokey(map->key_size_lg2, &key); - upb_value tabval = upb_map_tovalue(map->val_size_lg2, val, arena); - upb_alloc *a = upb_arena_alloc(arena); - - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - if (upb_strtable_lookup2(&map->table, strkey.data, strkey.size, NULL)) { - upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); - } - - return upb_strtable_insert3(&map->table, strkey.data, strkey.size, tabval, a); + return _upb_map_set(map, &key, map->key_size, &val, map->val_size, arena); } -bool upb_map_delete(upb_map *map, upb_msgval key, upb_arena *arena) { - upb_strview strkey = upb_map_tokey(map->key_size_lg2, &key); - upb_alloc *a = upb_arena_alloc(arena); - return upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); +bool upb_map_delete(upb_map *map, upb_msgval key) { + return _upb_map_delete(map, &key, map->key_size); } -/** upb_mapiter ***************************************************************/ - -struct upb_mapiter { - upb_strtable_iter iter; - char key_size_lg2; - char val_size_lg2; -}; - -size_t upb_mapiter_sizeof(void) { - return sizeof(upb_mapiter); +bool upb_mapiter_next(const upb_map *map, size_t *iter) { + return _upb_map_next(map, iter); } -void upb_mapiter_begin(upb_mapiter *i, upb_map *map) { - upb_strtable_begin(&i->iter, &map->table); - i->key_size_lg2 = map->key_size_lg2; - i->val_size_lg2 = map->val_size_lg2; -} - -void upb_mapiter_free(upb_mapiter *i, upb_alloc *a) { - upb_free(a, i); -} - -void upb_mapiter_next(upb_mapiter *i) { - upb_strtable_next(&i->iter); -} - -bool upb_mapiter_done(const upb_mapiter *i) { - return upb_strtable_done(&i->iter); -} - -upb_msgval upb_mapiter_key(const upb_mapiter *i) { - upb_strview key = upb_strtable_iter_key(&i->iter); +/* Returns the key and value for this entry of the map. */ +upb_msgval upb_mapiter_key(const upb_map *map, size_t iter) { + upb_strtable_iter i = {&map->table, iter}; + upb_strview key = upb_strtable_iter_key(&i); upb_msgval ret; - if (i->key_size_lg2 == UPB_MAPTYPE_STRING) { - ret.str_val = key; - } else { - memcpy(&ret, key.data, 1 << i->key_size_lg2); - } + _upb_map_fromkey(key, &ret, map->key_size); return ret; } -upb_msgval upb_mapiter_value(const upb_mapiter *i) { - return upb_map_fromvalue(i->val_size_lg2, upb_strtable_iter_value(&i->iter)); -} - -void upb_mapiter_setdone(upb_mapiter *i) { - upb_strtable_iter_setdone(&i->iter); +upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) { + upb_strtable_iter i = {&map->table, iter}; + upb_value val = upb_strtable_iter_value(&i); + upb_msgval ret; + _upb_map_fromvalue(val, &ret, map->val_size); + return ret; } -bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) { - return upb_strtable_iter_isequal(&i1->iter, &i2->iter); -} +/* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */ diff --git a/upb/reflection.h b/upb/reflection.h index 58fa7ee7a2..f284925904 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -72,6 +72,10 @@ bool upb_array_resize(upb_array *array, size_t size, upb_arena *arena); /** upb_map *******************************************************************/ +/* Creates a new map on the given arena with the given key/value size. */ +upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, + upb_fieldtype_t value_type); + /* Returns the number of entries in the map. */ size_t upb_map_size(const upb_map *map); @@ -89,48 +93,30 @@ bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, upb_arena *arena); /* Deletes this key from the table. Returns true if the key was present. */ -/* TODO(haberman): can |arena| be removed once upb_table is arena-only and no - * longer tries to free keys? */ -bool upb_map_delete(upb_map *map, upb_msgval key, upb_arena *arena); - -/** upb_mapiter ***************************************************************/ - -/* For iterating over a map. Map iterators are invalidated by mutations to the - * map, but an invalidated iterator will never return junk or crash the process - * (this is an important property when exposing iterators to interpreted - * languages like Ruby, PHP, etc). An invalidated iterator may return entries - * that were already returned though, and if you keep invalidating the iterator - * during iteration, the program may enter an infinite loop. */ -struct upb_mapiter; -typedef struct upb_mapiter upb_mapiter; - -size_t upb_mapiter_sizeof(void); - -/* Starts iteration. If the map is mutable then we can modify entries while - * iterating. */ -void upb_mapiter_constbegin(upb_mapiter *i, const upb_map *map); -void upb_mapiter_begin(upb_mapiter *i, upb_map *map); - -/* Sets the iterator to "done" state. This will return "true" from - * upb_mapiter_done() and will compare equal to other "done" iterators. */ -void upb_mapiter_setdone(upb_mapiter *i); - -/* Advances to the next entry. The iterator must not be done. */ -void upb_mapiter_next(upb_mapiter *i); +bool upb_map_delete(upb_map *map, upb_msgval key); + +/* Map iteration: + * + * size_t iter = UPB_MAP_BEGIN; + * while (upb_mapiter_next(map, &iter)) { + * upb_msgval key = upb_mapiter_key(map, iter); + * upb_msgval val = upb_mapiter_value(map, iter); + * + * // If mutating is desired. + * upb_mapiter_setvalue(map, iter, value2); + * } + */ + +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_mapiter_next(const upb_map *map, size_t *iter); /* Returns the key and value for this entry of the map. */ -upb_msgval upb_mapiter_key(const upb_mapiter *i); -upb_msgval upb_mapiter_value(const upb_mapiter *i); +upb_msgval upb_mapiter_key(const upb_map *map, size_t iter); +upb_msgval upb_mapiter_value(const upb_map *map, size_t iter); /* Sets the value for this entry. The iterator must not be done, and the * iterator must not have been initialized const. */ -void upb_mapiter_setvalue(const upb_mapiter *i, upb_msgval value); - -/* Returns true if the iterator is done. */ -bool upb_mapiter_done(const upb_mapiter *i); - -/* Compares two iterators for equality. */ -bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2); +void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); #include "upb/port_undef.inc" diff --git a/upb/table.c b/upb/table.c index 5b48bb7e50..1d01a223d0 100644 --- a/upb/table.c +++ b/upb/table.c @@ -284,6 +284,12 @@ bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) { return init(&t->t, 2, a); } +void upb_strtable_clear(upb_strtable *t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + 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++) @@ -342,7 +348,10 @@ bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, uint32_t hash = upb_murmur_hash2(key, len, 0); upb_tabkey tabkey; if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { - upb_free(alloc, (void*)tabkey); + 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; @@ -351,10 +360,6 @@ bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, /* Iteration */ -static const upb_tabent *str_tabent(const upb_strtable_iter *i) { - return &i->t->t.entries[i->index]; -} - void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) { i->t = t; i->index = begin(&t->t); diff --git a/upb/table.int.h b/upb/table.int.h index d571a3498a..75575eb7d5 100644 --- a/upb/table.int.h +++ b/upb/table.int.h @@ -262,6 +262,7 @@ 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 * not already exist in the hash table. For string tables, the key must be @@ -451,6 +452,10 @@ typedef struct { bool array_part; } upb_inttable_iter; +UPB_INLINE const upb_tabent *str_tabent(const upb_strtable_iter *i) { + return &i->t->t.entries[i->index]; +} + void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t); void upb_inttable_next(upb_inttable_iter *i); bool upb_inttable_done(const upb_inttable_iter *i); diff --git a/upb/upb.h b/upb/upb.h index b64e4b1697..011103d949 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -358,6 +358,8 @@ typedef enum { UPB_DESCRIPTOR_TYPE_SINT64 = 18 } upb_descriptortype_t; +#define UPB_MAP_BEGIN -1 + #include "upb/port_undef.inc" #endif /* UPB_H_ */ diff --git a/upbc/generator.cc b/upbc/generator.cc index 09ed1ee7f4..50fb42d564 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -331,21 +331,24 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output output("/* $0 */\n\n", message->full_name()); std::string msgname = ToCIdent(message->full_name()); - output( - "UPB_INLINE $0 *$0_new(upb_arena *arena) {\n" - " return ($0 *)_upb_msg_new(&$1, arena);\n" - "}\n" - "UPB_INLINE $0 *$0_parse(const char *buf, size_t size,\n" - " upb_arena *arena) {\n" - " $0 *ret = $0_new(arena);\n" - " return (ret && upb_decode(buf, size, ret, &$1, arena)) ? ret : NULL;\n" - "}\n" - "UPB_INLINE char *$0_serialize(const $0 *msg, upb_arena *arena, size_t " - "*len) {\n" - " return upb_encode(msg, &$1, arena, len);\n" - "}\n" - "\n", - MessageName(message), MessageInit(message)); + + if (!message->options().map_entry()) { + output( + "UPB_INLINE $0 *$0_new(upb_arena *arena) {\n" + " return ($0 *)_upb_msg_new(&$1, arena);\n" + "}\n" + "UPB_INLINE $0 *$0_parse(const char *buf, size_t size,\n" + " upb_arena *arena) {\n" + " $0 *ret = $0_new(arena);\n" + " return (ret && upb_decode(buf, size, ret, &$1, arena)) ? ret : NULL;\n" + "}\n" + "UPB_INLINE char *$0_serialize(const $0 *msg, upb_arena *arena, size_t " + "*len) {\n" + " return upb_encode(msg, &$1, arena, len);\n" + "}\n" + "\n", + MessageName(message), MessageInit(message)); + } for (int i = 0; i < message->oneof_decl_count(); i++) { const protobuf::OneofDescriptor* oneof = message->oneof_decl(i); @@ -386,7 +389,42 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output } // Generate getter. - if (field->is_repeated()) { + if (field->is_map()) { + const protobuf::Descriptor* entry = field->message_type(); + const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1); + const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2); + output( + "UPB_INLINE size_t $0_$1_size(const $0 *msg) {" + "return _upb_msg_map_size(msg, $2); }\n", + msgname, field->name(), GetSizeInit(layout.GetFieldOffset(field))); + output( + "UPB_INLINE bool $0_$1_get(const $0 *msg, $2 key, $3 *val) { " + "return _upb_msg_map_get(msg, $4, &key, $5, val, $6); }\n", + msgname, field->name(), CType(key), CType(val), + GetSizeInit(layout.GetFieldOffset(field)), + key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(key)", + val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(*val)"); + output( + "UPB_INLINE $0 $1_$2_next(const $1 *msg, size_t* iter) { " + "return ($0)_upb_msg_map_next(msg, $3, iter); }\n", + CTypeConst(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field))); + } else if (message->options().map_entry()) { + output( + "UPB_INLINE $0 $1_$2(const $1 *msg) {\n" + " $3 ret;\n" + " _upb_msg_map_$2(msg, &ret, $4);\n" + " return ret;\n" + "}\n", + CTypeConst(field), msgname, field->name(), CType(field), + field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(ret)"); + } else if (field->is_repeated()) { output( "UPB_INLINE $0 const* $1_$2(const $1 *msg, size_t *len) { " "return ($0 const*)_upb_array_accessor(msg, $3, len); }\n", @@ -414,11 +452,39 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output // Generate mutable methods. for (auto field : FieldNumberOrder(message)) { - if (message->options().map_entry() && field->name() == "key") { - // Emit nothing, map keys cannot be changed directly. Users must use - // the mutators of the map itself. - } else if (field->is_map()) { + if (field->is_map()) { // TODO(haberman): add map-based mutators. + const protobuf::Descriptor* entry = field->message_type(); + const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1); + const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2); + output( + "UPB_INLINE void $0_$1_clear($0 *msg) { _upb_msg_map_clear(msg, $2); }\n", + msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field))); + output( + "UPB_INLINE bool $0_$1_set($0 *msg, $2 key, $3 val, upb_arena *a) { " + "return _upb_msg_map_set(msg, $4, &key, $5, &val, $6, a); }\n", + msgname, field->name(), CType(key), CType(val), + GetSizeInit(layout.GetFieldOffset(field)), + key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(key)", + val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(val)"); + output( + "UPB_INLINE bool $0_$1_delete($0 *msg, $2 key) { " + "return _upb_msg_map_delete(msg, $3, &key, $4); }\n", + msgname, field->name(), CType(key), + GetSizeInit(layout.GetFieldOffset(field)), + key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(key)"); + output( + "UPB_INLINE $0 $1_$2_nextmutable($1 *msg, size_t* iter) { " + "return ($0)_upb_msg_map_next(msg, $3, iter); }\n", + CType(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field))); } else if (field->is_repeated()) { output( "UPB_INLINE $0* $1_mutable_$2($1 *msg, size_t *len) {\n" @@ -461,9 +527,24 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output } } else { // Non-repeated field. + if (message->options().map_entry() && field->name() == "key") { + // Key cannot be mutated. + continue; + } + + // The common function signature for all setters. Varying implementations + // follow. output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) {\n", msgname, field->name(), CType(field)); - if (field->containing_oneof()) { + + if (message->options().map_entry()) { + output( + " _upb_msg_map_set_value(msg, &value, $0);\n" + "}\n", + field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING + ? "0" + : "sizeof(" + CType(field) + ")"); + } else if (field->containing_oneof()) { output( " UPB_WRITE_ONEOF(msg, $0, $1, value, $2, $3);\n" "}\n", @@ -479,7 +560,9 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output "}\n", CType(field), GetSizeInit(layout.GetFieldOffset(field))); } - if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { + + if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE && + !message->options().map_entry()) { output( "UPB_INLINE struct $0* $1_mutable_$2($1 *msg, upb_arena *arena) {\n" " struct $0* sub = (struct $0*)$1_$2(msg);\n" @@ -504,7 +587,6 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { output( "#ifndef $0_UPB_H_\n" "#define $0_UPB_H_\n\n" - "#include \"upb/generated_util.h\"\n" "#include \"upb/msg.h\"\n" "#include \"upb/decode.h\"\n" "#include \"upb/encode.h\"\n\n", From 806c8c9c6eb1adb1dea04b6bcf6372377660b115 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 13:36:24 -0800 Subject: [PATCH 28/35] Removed obsolete testing files. --- tests/bindings/googlepb/test_vs_proto2.cc | 165 ---------------------- tests/bindings/ruby/upb.rb | 62 -------- tests/google_message1.dat | Bin 228 -> 0 bytes tests/google_message2.dat | Bin 84570 -> 0 bytes tests/google_messages.proto | 149 ------------------- tests/test.proto.pb | Bin 652 -> 0 bytes 6 files changed, 376 deletions(-) delete mode 100644 tests/bindings/googlepb/test_vs_proto2.cc delete mode 100644 tests/bindings/ruby/upb.rb delete mode 100644 tests/google_message1.dat delete mode 100644 tests/google_message2.dat delete mode 100644 tests/google_messages.proto delete mode 100644 tests/test.proto.pb diff --git a/tests/bindings/googlepb/test_vs_proto2.cc b/tests/bindings/googlepb/test_vs_proto2.cc deleted file mode 100644 index ac447e1b0c..0000000000 --- a/tests/bindings/googlepb/test_vs_proto2.cc +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * A test that verifies that our results are identical to proto2 for a - * given proto type and input protobuf. - */ - -#define __STDC_LIMIT_MACROS // So we get UINT32_MAX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tests/google_messages.pb.h" -#include "tests/upb_test.h" -#include "upb/bindings/googlepb/bridge.h" -#include "upb/def.h" -#include "upb/handlers.h" -#include "upb/pb/decoder.h" -#include "upb/pb/glue.h" -#include "upb/pb/varint.int.h" - -// Pull in string data from tests/google_message{1,2}.dat -// (the .h files are generated with xxd). -const unsigned char message1_data[] = { -#include "tests/google_message1.h" -}; - -const unsigned char message2_data[] = { -#include "tests/google_message2.h" -}; - -void compare_metadata(const google::protobuf::Descriptor* d, - const upb::MessageDef *upb_md) { - ASSERT(d->field_count() == upb_md->field_count()); - for (upb::MessageDef::const_field_iterator i = upb_md->field_begin(); - i != upb_md->field_end(); ++i) { - const upb::FieldDef* upb_f = *i; - const google::protobuf::FieldDescriptor *proto2_f = - d->FindFieldByNumber(upb_f->number()); - ASSERT(upb_f); - ASSERT(proto2_f); - ASSERT(upb_f->number() == (uint32_t)proto2_f->number()); - ASSERT(std::string(upb_f->name()) == proto2_f->name()); - ASSERT(upb_f->descriptor_type() == - static_cast(proto2_f->type())); - ASSERT(upb_f->IsSequence() == proto2_f->is_repeated()); - } -} - -void print_diff(const google::protobuf::Message& msg1, - const google::protobuf::Message& msg2) { - std::string text_str1; - std::string text_str2; - google::protobuf::TextFormat::PrintToString(msg1, &text_str1); - google::protobuf::TextFormat::PrintToString(msg2, &text_str2); - fprintf(stderr, "str1: %s, str2: %s\n", text_str1.c_str(), text_str2.c_str()); -} - -void parse_and_compare(google::protobuf::Message *msg1, - google::protobuf::Message *msg2, - const upb::Handlers *protomsg_handlers, - const char *str, size_t len, bool allow_jit) { - // Parse to both proto2 and upb. - ASSERT(msg1->ParseFromArray(str, len)); - - upb::pb::CodeCache cache; - ASSERT(cache.set_allow_jit(allow_jit)); - upb::reffed_ptr decoder_method( - cache.GetDecoderMethod(upb::pb::DecoderMethodOptions(protomsg_handlers))); - - upb::Status status; - upb::Environment env; - env.ReportErrorsTo(&status); - upb::Sink protomsg_sink(protomsg_handlers, msg2); - upb::pb::Decoder* decoder = - upb::pb::Decoder::Create(&env, decoder_method.get(), &protomsg_sink); - - msg2->Clear(); - bool ok = upb::BufferSource::PutBuffer(str, len, decoder->input()); - if (!ok) { - fprintf(stderr, "error parsing: %s\n", status.error_message()); - print_diff(*msg1, *msg2); - } - ASSERT(ok); - ASSERT(status.ok()); - - // Would like to just compare the message objects themselves, but - // unfortunately MessageDifferencer is not part of the open-source release of - // proto2, so we compare their serialized strings, which we expect will be - // equivalent. - std::string str1; - std::string str2; - msg1->SerializeToString(&str1); - msg2->SerializeToString(&str2); - if (str1 != str2) { - print_diff(*msg1, *msg2); - } - ASSERT(str1 == str2); - ASSERT(std::string(str, len) == str2); -} - -void test_zig_zag() { - for (uint64_t num = 5; num * 1.5 < UINT64_MAX; num *= 1.5) { - ASSERT(upb_zzenc_64(num) == - google::protobuf::internal::WireFormatLite::ZigZagEncode64(num)); - if (num < UINT32_MAX) { - ASSERT(upb_zzenc_32(num) == - google::protobuf::internal::WireFormatLite::ZigZagEncode32(num)); - } - } - -} - -extern "C" { - -int run_tests(int argc, char *argv[]) { - UPB_UNUSED(argc); - UPB_UNUSED(argv); - UPB_UNUSED(message1_data); - UPB_UNUSED(message2_data); - size_t len = sizeof(MESSAGE_DATA_IDENT); - const char *str = (const char*)MESSAGE_DATA_IDENT; - - MESSAGE_CIDENT msg1; - MESSAGE_CIDENT msg2; - - upb::reffed_ptr h( - upb::googlepb::WriteHandlers::New(msg1)); - - compare_metadata(msg1.GetDescriptor(), h->message_def()); - - // Run twice to test proper object reuse. - parse_and_compare(&msg1, &msg2, h.get(), str, len, false); - parse_and_compare(&msg1, &msg2, h.get(), str, len, true); - parse_and_compare(&msg1, &msg2, h.get(), str, len, false); - parse_and_compare(&msg1, &msg2, h.get(), str, len, true); - - // Test with DynamicMessage. - google::protobuf::DynamicMessageFactory* factory = - new google::protobuf::DynamicMessageFactory; - const google::protobuf::Message* prototype = - factory->GetPrototype(msg1.descriptor()); - google::protobuf::Message* dyn_msg1 = prototype->New(); - google::protobuf::Message* dyn_msg2 = prototype->New(); - h = upb::googlepb::WriteHandlers::New(*dyn_msg1); - parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, false); - parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, true); - delete dyn_msg1; - delete dyn_msg2; - delete factory; - - test_zig_zag(); - - printf("All tests passed, %d assertions.\n", num_assertions); - - google::protobuf::ShutdownProtobufLibrary(); - return 0; -} - -} diff --git a/tests/bindings/ruby/upb.rb b/tests/bindings/ruby/upb.rb deleted file mode 100644 index 3e06c1798c..0000000000 --- a/tests/bindings/ruby/upb.rb +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/ruby -# -# Tests for Ruby upb extension. - -require 'test/unit' -require 'set' -require 'upb' - -def get_descriptor - File.open("upb/descriptor/descriptor.pb").read -end - -def load_descriptor - symtab = Upb::SymbolTable.new - symtab.load_descriptor(get_descriptor()) - return symtab -end - -def get_message_class(name) - return Upb.get_message_class(load_descriptor().lookup(name)) -end - -class TestRubyExtension < Test::Unit::TestCase - def test_parsedescriptor - msgdef = load_descriptor.lookup("google.protobuf.FileDescriptorSet") - assert_instance_of(Upb::MessageDef, msgdef) - - file_descriptor_set = Upb.get_message_class(msgdef) - msg = file_descriptor_set.parse(get_descriptor()) - - # A couple message types we know should exist. - names = Set.new(["DescriptorProto", "FieldDescriptorProto"]) - - msg.file.each { |file| - file.message_type.each { |message_type| - names.delete(message_type.name) - } - } - - assert_equal(0, names.size) - end - - def test_parseserialize - field_descriptor_proto = get_message_class("google.protobuf.FieldDescriptorProto") - field_options = get_message_class("google.protobuf.FieldOptions") - - field = field_descriptor_proto.new - - field.name = "MyName" - field.number = 5 - field.options = field_options.new - field.options.packed = true - - serialized = Upb::Message.serialize(field) - - field2 = field_descriptor_proto.parse(serialized) - - assert_equal("MyName", field2.name) - assert_equal(5, field2.number) - assert_equal(true, field2.options.packed) - end -end diff --git a/tests/google_message1.dat b/tests/google_message1.dat deleted file mode 100644 index bc0f064cc2ebd108e4a8ee14d94c59d2207f0f19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 228 zcmd;L5a5tF-Cw7~X6&tPrm5@|X=tEnRGJxFnjhg~7^hiQo0;t9U>Bf~WmBSDS5g&| zlWuPxtfpa;QDp8KR;->=t!|p&o}ZB%uVGuFkQ%H|TpjOepXpql=pO5%t`$&fs-adM zZ)H+l7nQ)6!BD_h70Dqfpi_4tW~D( zryZr6A6c3h9#v%GY;BsERHIew5ajHXR9aRPXq>K*t>d?nG3389$2}=7^$m<_I~W-| c7#Supa#h;~mZzoGDd$zsVCk5cxPVO_0C9jt)c^nh diff --git a/tests/google_message2.dat b/tests/google_message2.dat deleted file mode 100644 index 06c09441b9e1a3fc8577f6c36dbb583d85481b2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84570 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 diff --git a/tests/google_messages.proto b/tests/google_messages.proto deleted file mode 100644 index 489c470732..0000000000 --- a/tests/google_messages.proto +++ /dev/null @@ -1,149 +0,0 @@ - -package benchmarks; - -option optimize_for = SPEED; - -enum Foo { - FOO_VALUE = 1; - FOO_VALUE2 = 2; -} - -message Simple { - message M2 { - optional int32 f1 = 1234567; - } - optional M2 m2 = 1; -} - -message SpeedMessage1 { - required string field1 = 1; - optional string field9 = 9; - optional string field18 = 18; - optional bool field80 = 80 [default=false]; - optional bool field81 = 81 [default=true]; - required int32 field2 = 2; - required int32 field3 = 3; - optional int32 field280 = 280; - optional int32 field6 = 6 [default=0]; - optional int64 field22 = 22; - optional string field4 = 4; - repeated fixed64 field5 = 5; - optional bool field59 = 59 [default=false]; - optional string field7 = 7; - optional int32 field16 = 16; - optional int32 field130 = 130 [default=0]; - optional bool field12 = 12 [default=true]; - optional bool field17 = 17 [default=true]; - optional bool field13 = 13 [default=true]; - optional bool field14 = 14 [default=true]; - optional int32 field104 = 104 [default=0]; - optional int32 field100 = 100 [default=0]; - optional int32 field101 = 101 [default=0]; - optional string field102 = 102; - optional string field103 = 103; - optional int32 field29 = 29 [default=0]; - optional bool field30 = 30 [default=false]; - optional int32 field60 = 60 [default=-1]; - optional int32 field271 = 271 [default=-1]; - optional int32 field272 = 272 [default=-1]; - optional int32 field150 = 150; - optional int32 field23 = 23 [default=0]; - optional bool field24 = 24 [default=false]; - optional int32 field25 = 25 [default=0]; - optional SpeedMessage1SubMessage field15 = 15; - optional bool field78 = 78; - optional int32 field67 = 67 [default=0]; - optional int32 field68 = 68; - optional int32 field128 = 128 [default=0]; - optional string field129 = 129 [default="xxxxxxxxxxxxxxxxxxxxx"]; - optional int32 field131 = 131 [default=0]; - optional Foo field132 = 132 [default=FOO_VALUE]; -} - -message SpeedMessage1SubMessage { - optional int32 field1 = 1 [default=0]; - optional int32 field2 = 2 [default=0]; - optional int32 field3 = 3 [default=0]; - optional string field15 = 15 [default="FOOBAR!"]; - optional bool field12 = 12 [default=true]; - optional int64 field13 = 13; - optional int64 field14 = 14; - optional int32 field16 = 16; - optional int32 field19 = 19 [default=2]; - optional bool field20 = 20 [default=true]; - optional bool field28 = 28 [default=true]; - optional fixed64 field21 = 21; - optional int32 field22 = 22; - optional bool field23 = 23 [ default=false ]; - optional bool field206 = 206 [default=false]; - optional fixed32 field203 = 203; - optional int32 field204 = 204; - optional string field205 = 205; - optional uint64 field207 = 207; - optional uint64 field300 = 300; -} - -message SpeedMessage2 { - optional string field1 = 1; - optional int64 field3 = 3; - optional int64 field4 = 4; - optional int64 field30 = 30; - optional bool field75 = 75 [default=false]; - optional string field6 = 6; - optional bytes field2 = 2; - optional int32 field21 = 21 [default=0]; - optional int32 field71 = 71; - optional float field25 = 25; - optional int32 field109 = 109 [default=0]; - optional int32 field210 = 210 [default=0]; - optional int32 field211 = 211 [default=0]; - optional int32 field212 = 212 [default=0]; - optional int32 field213 = 213 [default=0]; - optional int32 field216 = 216 [default=0]; - optional int32 field217 = 217 [default=0]; - optional int32 field218 = 218 [default=0]; - optional int32 field220 = 220 [default=0]; - optional int32 field221 = 221 [default=0]; - optional float field222 = 222 [default=0.0]; - optional int32 field63 = 63; - - repeated group Group1 = 10 { - required float field11 = 11; - optional float field26 = 26; - optional string field12 = 12; - optional string field13 = 13; - repeated string field14 = 14; - required uint64 field15 = 15; - optional int32 field5 = 5; - optional string field27 = 27; - optional int32 field28 = 28; - optional string field29 = 29; - optional string field16 = 16; - repeated string field22 = 22; - repeated int32 field73 = 73; - optional int32 field20 = 20 [default=0]; - optional string field24 = 24; - optional SpeedMessage2GroupedMessage field31 = 31; - } - repeated string field128 = 128; - optional int64 field131 = 131; - repeated string field127 = 127; - optional int32 field129 = 129; - repeated int64 field130 = 130; - optional bool field205 = 205 [default=false]; - optional bool field206 = 206 [default=false]; -} - -message SpeedMessage2GroupedMessage { - optional float field1 = 1; - optional float field2 = 2; - optional float field3 = 3 [default=0.0]; - optional bool field4 = 4; - optional bool field5 = 5; - optional bool field6 = 6 [default=true]; - optional bool field7 = 7 [default=false]; - optional float field8 = 8; - optional bool field9 = 9; - optional float field10 = 10; - optional int64 field11 = 11; -} diff --git a/tests/test.proto.pb b/tests/test.proto.pb deleted file mode 100644 index a587fb18250872a4b66b976be4ed5efeafd5bde7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 652 zcmZ{i-Acni5QUw@^k-U24G4=@8ZY#!LMwuoOZ(JH1ds6kH;Ne=(DVa0=l_ z!XkJ?7%`q#{-K08D*nN&1s-;`YX=h#X%Dp|hhjUgw}A8&df z(ZUC2{sp#k3F-CbRkYYmn%p?E@K+A?bVM3=3cDO?t~x6Epm!lUBxzTYklAU7wI_Nq ZD&C3z@2kV3mCZmDdUQca@?(kS={LWsf1v;X From 520ddc1f11b18d9b0466c0655b59063d39daebfc Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 13:50:54 -0800 Subject: [PATCH 29/35] c89 fixes. --- upb/msg.h | 7 +++++-- upb/reflection.c | 14 ++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/upb/msg.h b/upb/msg.h index da226f917a..743625b7bd 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -268,7 +268,9 @@ UPB_INLINE bool _upb_map_get(const upb_map *map, const void *key, } UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) { - upb_strtable_iter it = {&map->table, *iter}; + upb_strtable_iter it; + it.t = &map->table; + it.index = *iter; upb_strtable_next(&it); if (upb_strtable_done(&it)) return NULL; *iter = it.index; @@ -345,7 +347,8 @@ UPB_INLINE void _upb_msg_map_clear(upb_msg *msg, size_t ofs) { UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { const upb_tabent *ent = (const upb_tabent*)msg; uint32_t u32len; - upb_strview k = {upb_tabstr(ent->key, &u32len)}; + upb_strview k; + k.data = upb_tabstr(ent->key, &u32len); k.size = u32len; _upb_map_fromkey(k, key, size); } diff --git a/upb/reflection.c b/upb/reflection.c index 11db23b999..c7242d51f9 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -227,18 +227,20 @@ bool upb_mapiter_next(const upb_map *map, size_t *iter) { /* Returns the key and value for this entry of the map. */ upb_msgval upb_mapiter_key(const upb_map *map, size_t iter) { - upb_strtable_iter i = {&map->table, iter}; - upb_strview key = upb_strtable_iter_key(&i); + upb_strtable_iter i; upb_msgval ret; - _upb_map_fromkey(key, &ret, map->key_size); + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); return ret; } upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) { - upb_strtable_iter i = {&map->table, iter}; - upb_value val = upb_strtable_iter_value(&i); + upb_strtable_iter i; upb_msgval ret; - _upb_map_fromvalue(val, &ret, map->val_size); + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); return ret; } From 059f226d414fa09e21a203edbcd74bb74a7e5e40 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 16:20:33 -0800 Subject: [PATCH 30/35] Unit tests for maps generated code. --- BUILD | 9 ++ tests/test_generated_code.c | 309 ++++++++++++++++++++++++++++++++++++ 2 files changed, 318 insertions(+) create mode 100644 tests/test_generated_code.c diff --git a/BUILD b/BUILD index ceeae4fab9..adeb5ae937 100644 --- a/BUILD +++ b/BUILD @@ -317,6 +317,15 @@ cc_test( ], ) +cc_test( + name = "test_generated_code", + srcs = ["tests/test_generated_code.c"], + deps = [ + ":test_messages_proto3_proto_upb", + ":upb_test", + ], +) + proto_library( name = "test_decoder_proto", srcs = [ diff --git a/tests/test_generated_code.c b/tests/test_generated_code.c new file mode 100644 index 0000000000..9d8be79ef2 --- /dev/null +++ b/tests/test_generated_code.c @@ -0,0 +1,309 @@ +/* Test of generated code, with a special focus on features that are not used in + * descriptor.proto or conformance.proto (since these get some testing from + * upb/def.c and tests/conformance_upb.c, respectively). + */ + +#include "src/google/protobuf/test_messages_proto3.upb.h" +#include "tests/upb_test.h" + +const char test_str[] = "abcdefg"; +const char test_str2[] = "12345678910"; +const char test_str3[] = "rstlnezxcvbnm"; +const char test_str4[] = "just another test string"; + +const upb_strview test_str_view = {test_str, sizeof(test_str) - 1}; +const upb_strview test_str_view2 = {test_str2, sizeof(test_str2) - 1}; +const upb_strview test_str_view3 = {test_str3, sizeof(test_str3) - 1}; +const upb_strview test_str_view4 = {test_str4, sizeof(test_str4) - 1}; + +const int32_t test_int32 = 10; +const int32_t test_int32_2 = -20; +const int32_t test_int32_3 = 30; +const int32_t test_int32_4 = -40; + +static void test_scalars() { + upb_arena *arena = upb_arena_new(); + protobuf_test_messages_proto3_TestAllTypesProto3 *msg = + protobuf_test_messages_proto3_TestAllTypesProto3_new(arena); + protobuf_test_messages_proto3_TestAllTypesProto3 *msg2; + upb_strview serialized; + + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_int32(msg, 10); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_int64(msg, 20); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_uint32(msg, 30); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_uint64(msg, 40); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_float(msg, 50.5); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_double(msg, 60.6); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_bool(msg, 1); + protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_string( + msg, test_str_view); + + serialized.data = protobuf_test_messages_proto3_TestAllTypesProto3_serialize( + msg, arena, &serialized.size); + + msg2 = protobuf_test_messages_proto3_TestAllTypesProto3_parse( + serialized.data, serialized.size, arena); + + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_int32( + msg2) == 10); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_int64( + msg2) == 20); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_uint32( + msg2) == 30); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_uint64( + msg2) == 40); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_float( + msg2) == 50.5); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_double( + msg2) == 60.6); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_optional_bool( + msg2) == 1); + ASSERT(upb_strview_eql( + protobuf_test_messages_proto3_TestAllTypesProto3_optional_string(msg2), + test_str_view)); + + upb_arena_free(arena); +} + +static void check_string_map_empty( + protobuf_test_messages_proto3_TestAllTypesProto3 *msg) { + size_t iter; + + ASSERT( + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_size( + msg) == 0); + ASSERT( + !protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_next( + msg, &iter)); +} + +static void check_string_map_one_entry( + protobuf_test_messages_proto3_TestAllTypesProto3 *msg) { + const protobuf_test_messages_proto3_TestAllTypesProto3_MapStringStringEntry + *const_ent; + size_t iter; + upb_strview str; + + ASSERT( + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_size( + msg) == 1); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_get( + msg, test_str_view, &str)); + ASSERT(upb_strview_eql(str, test_str_view2)); + + ASSERT( + !protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_get( + msg, test_str_view3, &str)); + + /* Test that iteration reveals a single k/v pair in the map. */ + iter = UPB_MAP_BEGIN; + const_ent = protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_next( + msg, &iter); + ASSERT(const_ent); + ASSERT(upb_strview_eql( + test_str_view, + protobuf_test_messages_proto3_TestAllTypesProto3_MapStringStringEntry_key( + const_ent))); + ASSERT(upb_strview_eql( + test_str_view2, + protobuf_test_messages_proto3_TestAllTypesProto3_MapStringStringEntry_value( + const_ent))); + + const_ent = protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_next( + msg, &iter); + ASSERT(!const_ent); +} + +static void test_string_map() { + upb_arena *arena = upb_arena_new(); + protobuf_test_messages_proto3_TestAllTypesProto3 *msg = + protobuf_test_messages_proto3_TestAllTypesProto3_new(arena); + const protobuf_test_messages_proto3_TestAllTypesProto3_MapStringStringEntry + *const_ent; + size_t iter, count; + + check_string_map_empty(msg); + + /* Set map[test_str_view] = test_str_view2 */ + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_set( + msg, test_str_view, test_str_view2, arena); + check_string_map_one_entry(msg); + + /* Deleting a non-existent key does nothing. */ + ASSERT( + !protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_delete( + msg, test_str_view3)); + check_string_map_one_entry(msg); + + /* Deleting the key sets the map back to empty. */ + ASSERT( + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_delete( + msg, test_str_view)); + check_string_map_empty(msg); + + /* Set two keys this time: + * map[test_str_view] = test_str_view2 + * map[test_str_view3] = test_str_view4 + */ + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_set( + msg, test_str_view, test_str_view2, arena); + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_set( + msg, test_str_view3, test_str_view4, arena); + + /* Test iteration */ + iter = UPB_MAP_BEGIN; + count = 0; + + while ( + (const_ent = + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_next( + msg, &iter)) != NULL) { + upb_strview key = + protobuf_test_messages_proto3_TestAllTypesProto3_MapStringStringEntry_key( + const_ent); + upb_strview val = + protobuf_test_messages_proto3_TestAllTypesProto3_MapStringStringEntry_value( + const_ent); + + count++; + if (upb_strview_eql(key, test_str_view)) { + ASSERT(upb_strview_eql(val, test_str_view2)); + } else { + ASSERT(upb_strview_eql(key, test_str_view3)); + ASSERT(upb_strview_eql(val, test_str_view4)); + } + } + + ASSERT(count == 2); + + /* Clearing the map goes back to empty. */ + protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_clear(msg); + check_string_map_empty(msg); + + upb_arena_free(arena); +} + +static void check_int32_map_empty( + protobuf_test_messages_proto3_TestAllTypesProto3 *msg) { + size_t iter; + + ASSERT( + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_size( + msg) == 0); + ASSERT( + !protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_next( + msg, &iter)); +} + +static void check_int32_map_one_entry( + protobuf_test_messages_proto3_TestAllTypesProto3 *msg) { + const protobuf_test_messages_proto3_TestAllTypesProto3_MapInt32Int32Entry + *const_ent; + size_t iter; + int32_t val; + + ASSERT( + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_size( + msg) == 1); + ASSERT(protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_get( + msg, test_int32, &val)); + ASSERT(val == test_int32_2); + + ASSERT( + !protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_get( + msg, test_int32_3, &val)); + + /* Test that iteration reveals a single k/v pair in the map. */ + iter = UPB_MAP_BEGIN; + const_ent = protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_next( + msg, &iter); + ASSERT(const_ent); + ASSERT( + test_int32 == + protobuf_test_messages_proto3_TestAllTypesProto3_MapInt32Int32Entry_key( + const_ent)); + ASSERT( + test_int32_2 == + protobuf_test_messages_proto3_TestAllTypesProto3_MapInt32Int32Entry_value( + const_ent)); + + const_ent = protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_next( + msg, &iter); + ASSERT(!const_ent); +} + +static void test_int32_map() { + upb_arena *arena = upb_arena_new(); + protobuf_test_messages_proto3_TestAllTypesProto3 *msg = + protobuf_test_messages_proto3_TestAllTypesProto3_new(arena); + const protobuf_test_messages_proto3_TestAllTypesProto3_MapInt32Int32Entry + *const_ent; + size_t iter, count; + + check_int32_map_empty(msg); + + /* Set map[test_int32] = test_int32_2 */ + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_set( + msg, test_int32, test_int32_2, arena); + check_int32_map_one_entry(msg); + + /* Deleting a non-existent key does nothing. */ + ASSERT( + !protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_delete( + msg, test_int32_3)); + check_int32_map_one_entry(msg); + + /* Deleting the key sets the map back to empty. */ + ASSERT( + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_delete( + msg, test_int32)); + check_int32_map_empty(msg); + + /* Set two keys this time: + * map[test_int32] = test_int32_2 + * map[test_int32_3] = test_int32_4 + */ + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_set( + msg, test_int32, test_int32_2, arena); + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_set( + msg, test_int32_3, test_int32_4, arena); + + /* Test iteration */ + iter = UPB_MAP_BEGIN; + count = 0; + + while ( + (const_ent = + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_next( + msg, &iter)) != NULL) { + int32_t key = + protobuf_test_messages_proto3_TestAllTypesProto3_MapInt32Int32Entry_key( + const_ent); + int32_t val = + protobuf_test_messages_proto3_TestAllTypesProto3_MapInt32Int32Entry_value( + const_ent); + + count++; + if (key == test_int32) { + ASSERT(val == test_int32_2); + } else { + ASSERT(key == test_int32_3); + ASSERT(val == test_int32_4); + } + } + + ASSERT(count == 2); + + /* Clearing the map goes back to empty. */ + protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_clear(msg); + check_int32_map_empty(msg); + + upb_arena_free(arena); +} + +int run_tests(int argc, char *argv[]) { + test_scalars(); + test_string_map(); + test_int32_map(); + return 0; +} From d541566a7bdf496f77fe9f08b74c258564216a57 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 16:49:55 -0800 Subject: [PATCH 31/35] Moved upb_array_new() to upb/reflection.h where it belongs. --- upb/decode.c | 2 +- upb/msg.c | 4 ++-- upb/msg.h | 2 +- upb/reflection.c | 4 ++++ upb/reflection.h | 3 +++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/upb/decode.c b/upb/decode.c index 042045da2d..cb3e6753f6 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -220,7 +220,7 @@ static upb_array *upb_getorcreatearr(upb_decframe *frame, if (!arr) { upb_fieldtype_t type = desctype_to_fieldtype[field->descriptortype]; - arr = upb_array_new(frame->state->arena, type); + arr = _upb_array_new(frame->state->arena, type); CHK(arr); *(upb_array**)&frame->msg[field->offset] = arr; } diff --git a/upb/msg.c b/upb/msg.c index bd3d347d58..756c6b5cac 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -101,7 +101,7 @@ const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { /** upb_array *****************************************************************/ -upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) { +upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type) { upb_array *arr = upb_arena_malloc(a, sizeof(upb_array)); if (!arr) { @@ -141,7 +141,7 @@ void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, upb_fieldtype_t type, upb_arena *arena) { upb_array *arr = *arr_ptr; if (!arr) { - arr = upb_array_new(arena, type); + arr = _upb_array_new(arena, type); if (!arr) return NULL; *arr_ptr = arr; } diff --git a/upb/msg.h b/upb/msg.h index 743625b7bd..b66730f11e 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -122,7 +122,7 @@ UPB_INLINE void *_upb_array_ptr(upb_array *arr) { } /* Creates a new array on the given arena. */ -upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type); +upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type); /* Resizes the capacity of the array to be at least min_size. */ bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena); diff --git a/upb/reflection.c b/upb/reflection.c index c7242d51f9..0b45e61776 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -161,6 +161,10 @@ void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, /** upb_array *****************************************************************/ +upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) { + return _upb_array_new(a, type); +} + size_t upb_array_size(const upb_array *arr) { return arr->len; } diff --git a/upb/reflection.h b/upb/reflection.h index f284925904..7caabcff1f 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -54,6 +54,9 @@ void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f); /** upb_array *****************************************************************/ +/* Creates a new array on the given arena that holds elements of this type. */ +upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type); + /* Returns the size of the array. */ size_t upb_array_size(const upb_array *arr); From c4b64e6a20b67b063cfe557bd7fda7d33ffb4432 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 17:23:31 -0800 Subject: [PATCH 32/35] Slight simplification: NULL arena will avoid creating a new sub-object. --- upb/bindings/lua/msg.c | 38 +++++++++----------------------------- upb/reflection.c | 2 +- upb/reflection.h | 6 +++--- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index aee9238e68..82d65e0fa6 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -697,28 +697,6 @@ static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val) { lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX); } -/** - * lupb_msg_lazycreate() - * - * For maps and repeated fields, we lazily create the map/array when the field - * is read, because we never want to return nil for these fields. Maps and - * repeated fields have no notion of presence, so we always want them to appear - * present. Messages on the other hand have presence so we return nil rather - * than lazily create them. - */ -static bool lupb_msg_lazycreate(lua_State *L, int narg, const upb_fielddef *f, - upb_msgval* val) { - if (val->msg_val == NULL && upb_fielddef_isseq(f)) { - upb_msg *msg = lupb_msg_check(L, narg); - upb_arena *arena = lupb_arenaget(L, narg); - upb_mutmsgval mutval = upb_msg_mutable(msg, f, arena); - memcpy(val, &mutval, sizeof(void*)); - return true; - } else { - return false; - } -} - /** * lupb_msg_newud() * @@ -745,7 +723,7 @@ static void *lupb_msg_newud(lua_State *L, int narg, size_t size, * Creates a new Lua wrapper object to wrap the given array, map, or message. */ static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f, - upb_msgval val) { + upb_mutmsgval val) { if (upb_fielddef_ismap(f)) { const upb_msgdef *entry = upb_fielddef_msgsubdef(f); const upb_fielddef *key_f = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); @@ -753,14 +731,14 @@ static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f, lupb_map *lmap = lupb_msg_newud(L, narg, sizeof(*lmap), LUPB_MAP, val_f); lmap->key_type = upb_fielddef_type(key_f); lmap->value_type = upb_fielddef_type(val_f); - lmap->map = (upb_map*)val.map_val; /* XXX: cast isn't great. */ + lmap->map = val.map; } else if (upb_fielddef_isseq(f)) { lupb_array *larr = lupb_msg_newud(L, narg, sizeof(*larr), LUPB_ARRAY, f); larr->type = upb_fielddef_type(f); - larr->arr = (upb_array*)val.array_val; /* XXX: cast isn't great. */ + larr->arr = val.array; } else { lupb_msg *lmsg = lupb_msg_newud(L, narg, sizeof(*lmsg), LUPB_MSG, f); - lmsg->msg = (upb_msg*)val.msg_val; /* XXX: cast isn't great. */ + lmsg->msg = val.msg; } /* Copy arena ref to new wrapper. This may be a different arena than the @@ -769,7 +747,7 @@ static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f, lua_getiuservalue(L, narg, LUPB_ARENA_INDEX); lua_setiuservalue(L, -2, LUPB_ARENA_INDEX); - lupb_cacheset(L, val.msg_val); + lupb_cacheset(L, val.msg); } /** @@ -834,15 +812,17 @@ int lupb_msg_pushnew(lua_State *L) { static int lupb_msg_index(lua_State *L) { upb_msg *msg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2); - upb_msgval val = upb_msg_get(msg, f); if (upb_fielddef_isseq(f) || upb_fielddef_issubmsg(f)) { /* Wrapped type; get or create wrapper. */ - if (lupb_msg_lazycreate(L, 1, f, &val) || !lupb_cacheget(L, val.msg_val)) { + upb_arena *arena = upb_fielddef_isseq(f) ? lupb_arenaget(L, 1) : NULL; + upb_mutmsgval val = upb_msg_mutable(msg, f, arena); + if (!lupb_cacheget(L, val.msg)) { lupb_msg_newwrapper(L, 1, f, val); } } else { /* Value type, just push value and return .*/ + upb_msgval val = upb_msg_get(msg, f); lupb_pushmsgval(L, 0, upb_fielddef_type(f), val); } diff --git a/upb/reflection.c b/upb/reflection.c index 0b45e61776..6d507233bb 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -128,7 +128,7 @@ upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_mutmsgval ret; char *mem = PTR_AT(msg, field->offset, char); memcpy(&ret, mem, sizeof(void*)); - if (!ret.msg) { + if (a && !ret.msg) { if (upb_fielddef_ismap(f)) { const upb_msgdef *entry = upb_fielddef_msgsubdef(f); const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); diff --git a/upb/reflection.h b/upb/reflection.h index 7caabcff1f..b099d345e6 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -36,9 +36,9 @@ upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a); /* Returns the value associated with this field. */ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f); -/* Returns a mutable pointer to a map, array, or submessage value, constructing - * a new object if it was not previously present. May not be called for - * primitive fields. */ +/* Returns a mutable pointer to a map, array, or submessage value. If the given + * arena is non-NULL this will construct a new object if it was not previously + * present. May not be called for primitive fields. */ upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a); /* May only be called for fields where upb_fielddef_haspresence(f) == true. */ From f9efbcd5d6798229455584843e1817ef44cb4ab0 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 13 Dec 2019 23:28:25 -0800 Subject: [PATCH 33/35] Added missing append fallback. --- tests/test_generated_code.c | 20 ++++++++++++++++++++ upb/msg.c | 31 +++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/tests/test_generated_code.c b/tests/test_generated_code.c index 9d8be79ef2..3d1f518b4c 100644 --- a/tests/test_generated_code.c +++ b/tests/test_generated_code.c @@ -301,9 +301,29 @@ static void test_int32_map() { upb_arena_free(arena); } +void test_repeated() { + upb_arena *arena = upb_arena_new(); + protobuf_test_messages_proto3_TestAllTypesProto3 *msg = + protobuf_test_messages_proto3_TestAllTypesProto3_new(arena); + size_t size; + const int *elems; + + protobuf_test_messages_proto3_TestAllTypesProto3_add_repeated_int32( + msg, 5, arena); + + elems = protobuf_test_messages_proto3_TestAllTypesProto3_repeated_int32( + msg, &size); + + ASSERT(size == 1); + ASSERT(elems[0] == 5); + + upb_arena_free(arena); +} + int run_tests(int argc, char *argv[]) { test_scalars(); test_string_map(); test_int32_map(); + test_repeated(); return 0; } diff --git a/upb/msg.c b/upb/msg.c index 756c6b5cac..db4de0983a 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -137,21 +137,44 @@ bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) { return true; } -void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, - upb_fieldtype_t type, upb_arena *arena) { +static upb_array *getorcreate_array(upb_array **arr_ptr, upb_fieldtype_t type, + upb_arena *arena) { upb_array *arr = *arr_ptr; if (!arr) { arr = _upb_array_new(arena, type); if (!arr) return NULL; *arr_ptr = arr; } + return arr; +} +static bool resize_array(upb_array *arr, size_t size, upb_arena *arena) { if (size > arr->size && !_upb_array_realloc(arr, size, arena)) { - return NULL; + return false; } arr->len = size; - return _upb_array_ptr(arr); + return true; +} + +void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, + upb_fieldtype_t type, upb_arena *arena) { + upb_array *arr = getorcreate_array(arr_ptr, type, arena); + return arr && resize_array(arr, size, arena) ? _upb_array_ptr(arr) : NULL; +} + +bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, + upb_fieldtype_t type, upb_arena *arena) { + upb_array *arr = getorcreate_array(arr_ptr, type, arena); + size_t elem = arr->len; + int lg2 = _upb_fieldtype_to_sizelg2[type]; + char *data; + + if (!arr || !resize_array(arr, elem + 1, arena)) return false; + + data = _upb_array_ptr(arr); + memcpy(data + (elem << lg2), value, 1 << lg2); + return true; } /** upb_map *******************************************************************/ From 744f8588dae4787849a94e99ed8c32f91f837572 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 18 Dec 2019 11:27:01 -0800 Subject: [PATCH 34/35] Cleanup to remove END_GROUP from descriptortype -> type tables. --- upb/decode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/upb/decode.c b/upb/decode.c index cb3e6753f6..4a991e564b 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -6,8 +6,8 @@ #include "upb/port_def.inc" /* Maps descriptor type -> upb field type. */ -const uint8_t desctype_to_fieldtype[] = { - UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ +static const uint8_t desctype_to_fieldtype[] = { + -1, /* invalid descriptor type */ UPB_TYPE_DOUBLE, /* DOUBLE */ UPB_TYPE_FLOAT, /* FLOAT */ UPB_TYPE_INT64, /* INT64 */ @@ -29,8 +29,8 @@ const uint8_t desctype_to_fieldtype[] = { }; /* Maps descriptor type -> upb map size. */ -const uint8_t desctype_to_mapsize[] = { - UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ +static const uint8_t desctype_to_mapsize[] = { + -1, /* invalid descriptor type */ 8, /* DOUBLE */ 4, /* FLOAT */ 8, /* INT64 */ From e911aae5f64aa9b47cb6f09cbc3d5ac03b535f17 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 10 Jan 2020 14:36:07 -0800 Subject: [PATCH 35/35] Factored upb_map_entry into a shared place. --- upb/decode.c | 14 +------------- upb/def.c | 7 +++---- upb/msg.h | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/upb/decode.c b/upb/decode.c index dae9b3d1aa..f1be7502c3 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -492,19 +492,7 @@ static bool upb_decode_mapfield(upb_decstate *d, upb_decframe *frame, const upb_msglayout_field *field, int len) { upb_map *map = *(upb_map**)&frame->msg[field->offset]; const upb_msglayout *entry = frame->layout->submsgs[field->submsg_index]; - - /* The compiler ensures that all map entry messages have this layout. */ - struct map_entry { - upb_msg_internal internal; - union { - upb_strview str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } k; - union { - upb_strview str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } v; - } ent; + upb_map_entry ent; if (!map) { /* Lazily create map. */ diff --git a/upb/def.c b/upb/def.c index 12bb104bed..1a83687788 100644 --- a/upb/def.c +++ b/upb/def.c @@ -869,10 +869,9 @@ static size_t upb_msgval_sizeof(upb_fieldtype_t type) { static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) { - /* Map entries aren't actually stored, they are only used during parsing. - * For parsing, it helps a lot if all map entry messages have the same - * layout. */ - return sizeof(upb_strview); + upb_map_entry ent; + UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); + return sizeof(ent.k); } else if (upb_fielddef_isseq(f)) { return sizeof(void*); } else { diff --git a/upb/msg.h b/upb/msg.h index b66730f11e..2b3274b6da 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -200,6 +200,21 @@ typedef struct { upb_strtable table; } upb_map; +/* Map entries aren't actually stored, they are only used during parsing. For + * parsing, it helps a lot if all map entry messages have the same layout. + * The compiler and def.c must ensure that all map entries have this layout. */ +typedef struct { + upb_msg_internal internal; + union { + upb_strview str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } k; + union { + upb_strview str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } v; +} upb_map_entry; + /* Creates a new map on the given arena with this key/value type. */ upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size);