diff options
Diffstat (limited to 'upb')
35 files changed, 3355 insertions, 2801 deletions
diff --git a/upb/bytestream.h b/upb/bytestream.h deleted file mode 100644 index a0c4110..0000000 --- a/upb/bytestream.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2013 Google Inc. See LICENSE for details. - * Author: Josh Haberman <jhaberman@gmail.com> - * - * This file contains the standard ByteStream msgdef and some useful routines - * surrounding it. - * - * This is a mixed C/C++ interface that offers a full API to both languages. - * See the top-level README for more information. - */ - -#ifndef UPB_BYTESTREAM_H_ -#define UPB_BYTESTREAM_H_ - -#include "upb/sink.h" -#include "upb/bytestream.upb.h" - -#define UPB_BYTESTREAM_BYTES &upb_bytestream_fields[0] - -// A convenience method that handles the start/end calls and tracks overall -// success. -UPB_INLINE bool upb_bytestream_putstr(upb_sink *s, const char *buf, size_t n) { - bool ret = - upb_sink_startmsg(s) && - upb_sink_startstr(s, UPB_BYTESTREAM_BYTES_STARTSTR, n) && - upb_sink_putstring(s, UPB_BYTESTREAM_BYTES_STRING, buf, n) == n && - upb_sink_endstr(s, UPB_BYTESTREAM_BYTES_ENDSTR); - if (ret) upb_sink_endmsg(s); - return ret; -} - -#ifdef __cplusplus - -namespace upb { - -inline bool PutStringToBytestream(Sink* s, const char* buf, size_t n) { - return upb_bytestream_putstr(s, buf, n); -} - -template <class T> bool PutStringToBytestream(Sink* s, T str) { - return upb_bytestream_putstr(s, str.c_str(), str.size()); -} - -} // namespace upb - -#endif - -#endif // UPB_BYTESTREAM_H_ diff --git a/upb/bytestream.proto b/upb/bytestream.proto deleted file mode 100644 index 1287925..0000000 --- a/upb/bytestream.proto +++ /dev/null @@ -1,14 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2013 Google Inc. See LICENSE for details. -// Author: Josh Haberman <jhaberman@gmail.com> -// -// This file contains a proto definition for use by handlers that consume a -// simple byte stream (like traditional UNIX pipes). - -package upb; - -message ByteStream { - optional bytes bytes = 1; -} diff --git a/upb/bytestream.upb.c b/upb/bytestream.upb.c deleted file mode 100644 index 2da5405..0000000 --- a/upb/bytestream.upb.c +++ /dev/null @@ -1,52 +0,0 @@ -// This file was generated by upbc (the upb compiler). -// Do not edit -- your changes will be discarded when the file is -// regenerated. - -#include "upb/def.h" - -const upb_msgdef upb_bytestream_msgs[1]; -const upb_fielddef upb_bytestream_fields[1]; -const upb_enumdef upb_bytestream_enums[0]; -const upb_tabent upb_bytestream_strentries[4]; -const upb_tabent upb_bytestream_intentries[0]; -const _upb_value upb_bytestream_arrays[2]; - -#ifdef UPB_DEBUG_REFS -static upb_inttable reftables[4]; -#endif - -const upb_msgdef upb_bytestream_msgs[1] = { - UPB_MSGDEF_INIT("upb.ByteStream", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &upb_bytestream_arrays[0], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &upb_bytestream_strentries[0]), 5, &reftables[0], &reftables[1]), -}; - -const upb_fielddef upb_bytestream_fields[1] = { - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "bytes", 1, &upb_bytestream_msgs[0], NULL, 2, {0},&reftables[2], &reftables[3]), -}; - -const upb_enumdef upb_bytestream_enums[0] = { -}; - -const upb_tabent upb_bytestream_strentries[4] = { - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("bytes"), UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]), NULL}, -}; - -const upb_tabent upb_bytestream_intentries[0] = { -}; - -const _upb_value upb_bytestream_arrays[2] = { - UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]), -}; - -#ifdef UPB_DEBUG_REFS -static upb_inttable reftables[4] = { - UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), - UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), - UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), - UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), -}; -#endif - diff --git a/upb/bytestream.upb.h b/upb/bytestream.upb.h deleted file mode 100644 index 9e18579..0000000 --- a/upb/bytestream.upb.h +++ /dev/null @@ -1,37 +0,0 @@ -// This file was generated by upbc (the upb compiler). -// Do not edit -- your changes will be discarded when the file is -// regenerated. - -#ifndef UPB_BYTESTREAM_UPB_H_ -#define UPB_BYTESTREAM_UPB_H_ - -#include "upb/def.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Enums - -// Do not refer to these forward declarations; use the constants -// below. -extern const upb_msgdef upb_bytestream_msgs[1]; -extern const upb_fielddef upb_bytestream_fields[1]; -extern const upb_enumdef upb_bytestream_enums[0]; - -// Constants for references to defs. -// We hide these behind macros to decouple users from the -// details of how we have statically defined them (ie. whether -// each def has its own symbol or lives in an array of defs). -#define UPB_BYTESTREAM &upb_bytestream_msgs[0] - -// Selector definitions. -#define UPB_BYTESTREAM_BYTES_ENDSTR 4 -#define UPB_BYTESTREAM_BYTES_STARTSTR 3 -#define UPB_BYTESTREAM_BYTES_STRING 2 - -#ifdef __cplusplus -}; // extern "C" -#endif - -#endif // UPB_BYTESTREAM_UPB_H_ @@ -138,11 +138,11 @@ static const char *msgdef_name(const upb_msgdef *m) { static bool upb_validate_field(upb_fielddef *f, upb_status *s) { if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { - upb_status_seterrliteral(s, "fielddef must have name and number set"); + upb_status_seterrmsg(s, "fielddef must have name and number set"); return false; } if (!f->type_is_set_) { - upb_status_seterrliteral(s, "fielddef type was not initialized"); + upb_status_seterrmsg(s, "fielddef type was not initialized"); return false; } if (upb_fielddef_hassubdef(f)) { @@ -173,6 +173,61 @@ static bool upb_validate_field(upb_fielddef *f, upb_status *s) { return true; } +// All submessage fields are lower than all other fields. +// Secondly, fields are increasing in order. +uint32_t field_rank(const upb_fielddef *f) { + uint32_t ret = upb_fielddef_number(f); + const uint32_t high_bit = 1 << 30; + assert(ret < high_bit); + if (!upb_fielddef_issubmsg(f)) + ret |= high_bit; + return ret; +} + +int cmp_fields(const void *p1, const void *p2) { + const upb_fielddef *f1 = *(upb_fielddef*const*)p1; + const upb_fielddef *f2 = *(upb_fielddef*const*)p2; + return field_rank(f1) - field_rank(f2); +} + +static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { + // Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the + // lowest indexes, but we do not publicly guarantee this. + int n = upb_msgdef_numfields(m); + upb_fielddef **fields = malloc(n * sizeof(*fields)); + if (!fields) return false; + + upb_msg_iter j; + int i; + m->submsg_field_count = 0; + for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) { + upb_fielddef *f = upb_msg_iter_field(&j); + assert(f->msgdef == m); + if (!upb_validate_field(f, s)) { + free(fields); + return false; + } + if (upb_fielddef_issubmsg(f)) { + m->submsg_field_count++; + } + fields[i] = f; + } + + qsort(fields, n, sizeof(*fields), cmp_fields); + + uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; + for (i = 0; i < n; i++) { + upb_fielddef *f = fields[i]; + f->index_ = i; + f->selector_base = selector + upb_handlers_selectorbaseoffset(f); + selector += upb_handlers_selectorcount(f); + } + m->selector_count = selector; + + free(fields); + return false; +} + bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { // First perform validation, in two passes so we can check that we have a // transitive closure without needing to search. @@ -180,10 +235,10 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { // Could relax this requirement if it's annoying. - upb_status_seterrliteral(s, "def is already frozen"); + upb_status_seterrmsg(s, "def is already frozen"); goto err; } else if (def->type == UPB_DEF_FIELD) { - upb_status_seterrliteral(s, "standalone fielddefs can not be frozen"); + upb_status_seterrmsg(s, "standalone fielddefs can not be frozen"); goto err; } else { // Set now to detect transitive closure in the second pass. @@ -191,22 +246,14 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { } } - // Second pass of validation. Also assign selectors, compact tables. + // Second pass of validation. Also assign selector bases and indexes, and + // compact tables. for (int i = 0; i < n; i++) { upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]); upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]); if (m) { upb_inttable_compact(&m->itof); - upb_msg_iter j; - uint32_t selector = UPB_STATIC_SELECTOR_COUNT; - for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) { - upb_fielddef *f = upb_msg_iter_field(&j); - assert(f->msgdef == m); - if (!upb_validate_field(f, s)) goto err; - f->selector_base = selector + upb_handlers_selectorbaseoffset(f); - selector += upb_handlers_selectorcount(f); - } - m->selector_count = selector; + assign_msg_indices(m, s); } else if (e) { upb_inttable_compact(&e->iton); } @@ -314,12 +361,12 @@ bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, return false; } if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) { - upb_status_seterrliteral(status, "out of memory"); + upb_status_seterrmsg(status, "out of memory"); return false; } if (!upb_inttable_lookup(&e->iton, num, NULL) && !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) { - upb_status_seterrliteral(status, "out of memory"); + upb_status_seterrmsg(status, "out of memory"); upb_strtable_remove(&e->ntoi, name, NULL); return false; } @@ -492,6 +539,10 @@ upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) { return f->type_; } +uint32_t upb_fielddef_index(const upb_fielddef *f) { + return f->index_; +} + upb_label_t upb_fielddef_label(const upb_fielddef *f) { return f->label_; } @@ -628,7 +679,7 @@ const char *upb_fielddef_subdefname(const upb_fielddef *f) { bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) { if (f->msgdef) { - upb_status_seterrliteral( + upb_status_seterrmsg( s, "cannot change field number after adding to a message"); return false; } @@ -880,16 +931,14 @@ static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef, upb_status *s) { if (f->type_ == UPB_TYPE_MESSAGE) { if (upb_dyncast_msgdef(subdef)) return true; - upb_status_seterrliteral(s, - "invalid subdef type for this submessage field"); + upb_status_seterrmsg(s, "invalid subdef type for this submessage field"); return false; } else if (f->type_ == UPB_TYPE_ENUM) { if (upb_dyncast_enumdef(subdef)) return true; - upb_status_seterrliteral(s, "invalid subdef type for this enum field"); + upb_status_seterrmsg(s, "invalid subdef type for this enum field"); return false; } else { - upb_status_seterrliteral(s, - "only message and enum fields can have a subdef"); + upb_status_seterrmsg(s, "only message and enum fields can have a subdef"); return false; } } @@ -928,7 +977,7 @@ bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status *s) { assert(!upb_fielddef_isfrozen(f)); if (!upb_fielddef_hassubdef(f)) { - upb_status_seterrliteral(s, "field type does not accept a subdef"); + upb_status_seterrmsg(s, "field type does not accept a subdef"); return false; } release_subdef(f); @@ -1061,14 +1110,14 @@ bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n, // TODO(haberman): handle the case where two fields of the input duplicate // name or number. if (f->msgdef != NULL) { - upb_status_seterrliteral(s, "fielddef already belongs to a message"); + upb_status_seterrmsg(s, "fielddef already belongs to a message"); return false; } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { - upb_status_seterrliteral(s, "field name or number were not set"); + upb_status_seterrmsg(s, "field name or number were not set"); return false; } else if(upb_msgdef_itof(m, upb_fielddef_number(f)) || upb_msgdef_ntof(m, upb_fielddef_name(f))) { - upb_status_seterrliteral(s, "duplicate field name or number"); + upb_status_seterrmsg(s, "duplicate field name or number"); return false; } } @@ -80,17 +80,14 @@ typedef enum { #ifdef __cplusplus -class upb::Def { +// The base class of all defs. Its base is upb::RefCounted (use upb::upcast() +// to convert). +class upb::Def /* : public upb::Refcounted */ { public: typedef upb_deftype_t Type; Def* Dup(const void *owner) const; - // Though not declared as such in C++, upb::RefCounted is the base of - // Def and we can upcast to it. - RefCounted* Upcast(); - const RefCounted* Upcast() const; - // Functionality from upb::RefCounted. bool IsFrozen() const; void Ref(const void* owner) const; @@ -125,7 +122,7 @@ class upb::Def { static bool Freeze(const std::vector<Def*>& defs, Status* status); private: - UPB_DISALLOW_POD_OPS(Def); + UPB_DISALLOW_POD_OPS(Def, upb::Def); #else struct upb_def { @@ -226,7 +223,9 @@ typedef enum { // A upb_fielddef describes a single field in a message. It is most often // found as a part of a upb_msgdef, but can also stand alone to represent // an extension. -class upb::FieldDef { +// +// Its base class is upb::Def (use upb::upcast() to convert). +class upb::FieldDef /* : public upb::Def */ { public: typedef upb_fieldtype_t Type; typedef upb_label_t Label; @@ -247,7 +246,7 @@ class upb::FieldDef { static IntegerFormat ConvertIntegerFormat(int32_t val); // Returns NULL if memory allocation failed. - static FieldDef* New(const void* owner); + static reffed_ptr<FieldDef> New(); // Duplicates the given field, returning NULL if memory allocation failed. // When a fielddef is duplicated, the subdef (if any) is made symbolic if it @@ -256,11 +255,6 @@ class upb::FieldDef { // will be unset. FieldDef* Dup(const void* owner) const; - // Though not declared as such in C++, upb::Def is the base of FieldDef and - // we can upcast to it. - Def* Upcast(); - const Def* Upcast() const; - // Functionality from upb::RefCounted. bool IsFrozen() const; void Ref(const void* owner) const; @@ -279,6 +273,12 @@ class upb::FieldDef { const char* name() const; // NULL if uninitialized. uint32_t number() const; // Returns 0 if uninitialized. + // An integer that can be used as an index into an array of fields for + // whatever message this field belongs to. Guaranteed to be less than + // f->containing_type()->field_count(). May only be accessed once the def has + // been finalized. + int index() const; + // The MessageDef to which this field belongs, or NULL if none. const MessageDef* containing_type() const; @@ -410,7 +410,7 @@ class upb::FieldDef { bool set_subdef_name(const std::string &name, Status* s); private: - UPB_DISALLOW_POD_OPS(FieldDef); + UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef); #else struct upb_fielddef { @@ -437,14 +437,16 @@ struct upb_fielddef { upb_label_t label_; uint32_t number_; uint32_t selector_base; // Used to index into a upb::Handlers table. + uint32_t index_; }; #define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, \ - subdef, selector_base, defaultval, refs, ref2s) \ + subdef, selector_base, index, defaultval, refs, \ + ref2s) \ { \ UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, msgdef, \ {subdef}, false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \ - true, intfmt, tagdelim, type, label, num, selector_base \ + true, intfmt, tagdelim, type, label, num, selector_base, index \ } // Native C API. @@ -476,6 +478,7 @@ const char *upb_fielddef_name(const upb_fielddef *f); const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f); upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f); +uint32_t upb_fielddef_index(const upb_fielddef *f); bool upb_fielddef_istagdelim(const upb_fielddef *f); bool upb_fielddef_issubmsg(const upb_fielddef *f); bool upb_fielddef_isstring(const upb_fielddef *f); @@ -541,15 +544,12 @@ typedef upb_inttable_iter upb_msg_iter; #ifdef __cplusplus // Structure that describes a single .proto message type. -class upb::MessageDef { +// +// Its base class is upb::Def (use upb::upcast() to convert). +class upb::MessageDef /* : public upb::Def */ { public: // Returns NULL if memory allocation failed. - static MessageDef* New(const void* owner); - - // Though not declared as such in C++, upb::Def is the base of MessageDef and - // we can upcast to it. - Def* Upcast(); - const Def* Upcast() const; + static reffed_ptr<MessageDef> New(); // Functionality from upb::RefCounted. bool IsFrozen() const; @@ -563,6 +563,10 @@ class upb::MessageDef { bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); + // Call to freeze this MessageDef. + // WARNING: this will fail if this message has any unfrozen submessages! + bool Freeze(Status* s); + // The number of fields that belong to the MessageDef. int field_count() const; @@ -570,9 +574,9 @@ class upb::MessageDef { // and the fielddefs are mutable. The fielddef's name and number must be // set, and the message may not already contain any field with this name or // number, and this fielddef may not be part of another message. In error - // cases false is returned and the msgdef is unchanged. On success, the - // caller donates a ref from ref_donor (if non-NULL). - bool AddField(FieldDef* f, const void* ref_donor, Status* s); + // cases false is returned and the msgdef is unchanged. + bool AddField(FieldDef* f, Status* s); + bool AddField(const reffed_ptr<FieldDef>& f, Status* s); // These return NULL if the field is not found. FieldDef* FindFieldByNumber(uint32_t number); @@ -628,13 +632,14 @@ class upb::MessageDef { const_iterator end() const; private: - UPB_DISALLOW_POD_OPS(MessageDef); + UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef); #else struct upb_msgdef { #endif upb_def base; size_t selector_count; + uint32_t submsg_field_count; // Tables for looking up fields by number and name. upb_inttable itof; // int to field @@ -643,8 +648,12 @@ struct upb_msgdef { // TODO(haberman): proper extension ranges (there can be multiple). }; -#define UPB_MSGDEF_INIT(name, itof, ntof, selector_count, refs, ref2s) \ - { UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, itof, ntof } +#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \ + refs, ref2s) \ + { \ + UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \ + submsg_field_count, itof, ntof \ + } #ifdef __cplusplus extern "C" { @@ -700,15 +709,12 @@ typedef upb_strtable_iter upb_enum_iter; #ifdef __cplusplus -class upb::EnumDef { +// Class that represents an enum. Its base class is upb::Def (convert with +// upb::upcast()). +class upb::EnumDef /* : public upb::Def */ { public: // Returns NULL if memory allocation failed. - static EnumDef* New(const void* owner); - - // Though not declared as such in C++, upb::Def is the base of EnumDef and we - // can upcast to it. - Def* Upcast(); - const Def* Upcast() const; + static reffed_ptr<EnumDef> New(); // Functionality from upb::RefCounted. bool IsFrozen() const; @@ -722,6 +728,9 @@ class upb::EnumDef { bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); + // Call to freeze this EnumDef. + bool Freeze(Status* s); + // The value that is used as the default when no field default is specified. int32_t default_value() const; void set_default_value(int32_t val); @@ -764,7 +773,7 @@ class upb::EnumDef { }; private: - UPB_DISALLOW_POD_OPS(EnumDef); + UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef); #else struct upb_enumdef { @@ -824,9 +833,55 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter); #ifdef __cplusplus +namespace upb { + +template<> +class Pointer<Def> { + public: + explicit Pointer(Def* ptr) : ptr_(ptr) {} + operator Def*() { return ptr_; } + operator RefCounted*() { return UPB_UPCAST(ptr_); } + private: + Def* ptr_; +}; + +template<> +class Pointer<const Def> { + public: + explicit Pointer(const Def* ptr) : ptr_(ptr) {} + operator const Def*() { return ptr_; } + operator const RefCounted*() { return UPB_UPCAST(ptr_); } + private: + const Def* ptr_; +}; + +} // namespace upb + #define UPB_CPP_CASTS(cname, cpptype) \ namespace upb { \ template <> \ + class Pointer<cpptype> { \ + public: \ + explicit Pointer(cpptype* ptr) : ptr_(ptr) {} \ + operator cpptype*() { return ptr_; } \ + operator Def*() { return UPB_UPCAST(ptr_); } \ + operator RefCounted*() { return Pointer<Def>(UPB_UPCAST(ptr_)); } \ + private: \ + cpptype* ptr_; \ + }; \ + template <> \ + class Pointer<const cpptype> { \ + public: \ + explicit Pointer(const cpptype* ptr) : ptr_(ptr) {} \ + operator const cpptype*() { return ptr_; } \ + operator const Def*() { return UPB_UPCAST(ptr_); } \ + operator const RefCounted*() { \ + return Pointer<const Def>(UPB_UPCAST(ptr_)); \ + } \ + private: \ + const cpptype* ptr_; \ + }; \ + template <> \ inline cpptype *down_cast<cpptype*, Def>(Def *def) { \ return upb_downcast_##cname##_mutable(def); \ } \ @@ -894,8 +949,6 @@ namespace upb { inline Def* Def::Dup(const void* owner) const { return upb_def_dup(this, owner); } -inline RefCounted* Def::Upcast() { return UPB_UPCAST(this); } -inline const RefCounted* Def::Upcast() const { return UPB_UPCAST(this); } inline bool Def::IsFrozen() const { return upb_def_isfrozen(this); } inline void Def::Ref(const void* owner) const { upb_def_ref(this, owner); } inline void Def::Unref(const void* owner) const { upb_def_unref(this, owner); } @@ -949,14 +1002,13 @@ inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) { return static_cast<FieldDef::IntegerFormat>(val); } -inline FieldDef* FieldDef::New(const void* owner) { - return upb_fielddef_new(owner); +inline reffed_ptr<FieldDef> FieldDef::New() { + upb_fielddef *f = upb_fielddef_new(&f); + return reffed_ptr<FieldDef>(f, &f); } inline FieldDef* FieldDef::Dup(const void* owner) const { return upb_fielddef_dup(this, owner); } -inline Def* FieldDef::Upcast() { return UPB_UPCAST(this); } -inline const Def* FieldDef::Upcast() const { return UPB_UPCAST(this); } inline bool FieldDef::IsFrozen() const { return upb_fielddef_isfrozen(this); } inline void FieldDef::Ref(const void* owner) const { upb_fielddef_ref(this, owner); @@ -1105,11 +1157,10 @@ inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) { return upb_fielddef_setsubdefname(this, upb_safecstr(name), s); } -inline MessageDef* MessageDef::New(const void* owner) { - return upb_msgdef_new(owner); +inline reffed_ptr<MessageDef> MessageDef::New() { + upb_msgdef *m = upb_msgdef_new(&m); + return reffed_ptr<MessageDef>(m, &m); } -inline Def* MessageDef::Upcast() { return UPB_UPCAST(this); } -inline const Def* MessageDef::Upcast() const { return UPB_UPCAST(this); } inline bool MessageDef::IsFrozen() const { return upb_msgdef_isfrozen(this); } inline void MessageDef::Ref(const void* owner) const { return upb_msgdef_ref(this, owner); @@ -1132,12 +1183,18 @@ inline bool MessageDef::set_full_name(const char* fullname, Status* s) { inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) { return upb_msgdef_setfullname(this, upb_safecstr(fullname), s); } +inline bool MessageDef::Freeze(Status* status) { + upb::Def* e = upb::upcast(this); + return upb_def_freeze(&e, 1, status); +} inline int MessageDef::field_count() const { return upb_msgdef_numfields(this); } -inline bool MessageDef::AddField(upb_fielddef* f, const void* ref_donor, - Status* s) { - return upb_msgdef_addfield(this, f, ref_donor, s); +inline bool MessageDef::AddField(upb_fielddef* f, Status* s) { + return upb_msgdef_addfield(this, f, NULL, s); +} +inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) { + return upb_msgdef_addfield(this, f.get(), NULL, s); } inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) { return upb_msgdef_itof_mutable(this, number); @@ -1201,11 +1258,10 @@ inline bool MessageDef::const_iterator::operator!=( return !(*this == other); } -inline EnumDef* EnumDef::New(const void *owner) { - return upb_enumdef_new(owner); +inline reffed_ptr<EnumDef> EnumDef::New() { + upb_enumdef *e = upb_enumdef_new(&e); + return reffed_ptr<EnumDef>(e, &e); } -inline Def* EnumDef::Upcast() { return UPB_UPCAST(this); } -inline const Def* EnumDef::Upcast() const { return UPB_UPCAST(this); } inline bool EnumDef::IsFrozen() const { return upb_enumdef_isfrozen(this); } inline void EnumDef::Ref(const void* owner) const { return upb_enumdef_ref(this, owner); @@ -1228,6 +1284,10 @@ inline bool EnumDef::set_full_name(const char* fullname, Status* s) { inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) { return upb_enumdef_setfullname(this, upb_safecstr(fullname), s); } +inline bool EnumDef::Freeze(Status* status) { + upb::Def* e = upb::upcast(this); + return upb_def_freeze(&e, 1, status); +} inline int32_t EnumDef::default_value() const { return upb_enumdef_default(this); } diff --git a/upb/descriptor/descriptor.upb.c b/upb/descriptor/descriptor.upb.c index 32273ba..f183285 100755 --- a/upb/descriptor/descriptor.upb.c +++ b/upb/descriptor/descriptor.upb.c @@ -16,102 +16,102 @@ static upb_inttable reftables[194]; #endif const upb_msgdef google_protobuf_msgs[20] = { - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]), 33, &reftables[0], &reftables[1]), - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]), 4, &reftables[2], &reftables[3]), - UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]), 13, &reftables[4], &reftables[5]), - UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]), 7, &reftables[6], &reftables[7]), - UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]), 9, &reftables[8], &reftables[9]), - UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]), 7, &reftables[10], &reftables[11]), - UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]), 20, &reftables[12], &reftables[13]), - UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]), 13, &reftables[14], &reftables[15]), - UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]), 39, &reftables[16], &reftables[17]), - UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]), 7, &reftables[18], &reftables[19]), - UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]), 19, &reftables[20], &reftables[21]), - UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]), 9, &reftables[22], &reftables[23]), - UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]), 14, &reftables[24], &reftables[25]), - UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]), 7, &reftables[26], &reftables[27]), - UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]), 13, &reftables[28], &reftables[29]), - UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]), 7, &reftables[30], &reftables[31]), - UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]), 7, &reftables[32], &reftables[33]), - UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]), 8, &reftables[34], &reftables[35]), - UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]), 19, &reftables[36], &reftables[37]), - UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]), 6, &reftables[38], &reftables[39]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 27, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]),&reftables[0], &reftables[1]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]),&reftables[2], &reftables[3]), + UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]),&reftables[4], &reftables[5]), + UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]),&reftables[6], &reftables[7]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]),&reftables[8], &reftables[9]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]),&reftables[10], &reftables[11]), + UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]),&reftables[12], &reftables[13]), + UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]),&reftables[14], &reftables[15]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 33, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]),&reftables[16], &reftables[17]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]),&reftables[18], &reftables[19]), + UPB_MSGDEF_INIT("google.protobuf.FileOptions", 18, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]),&reftables[20], &reftables[21]), + UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]),&reftables[22], &reftables[23]), + UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 13, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]),&reftables[24], &reftables[25]), + UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]),&reftables[26], &reftables[27]), + UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]),&reftables[28], &reftables[29]), + UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]),&reftables[30], &reftables[31]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]),&reftables[32], &reftables[33]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 8, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]),&reftables[34], &reftables[35]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]),&reftables[36], &reftables[37]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]),&reftables[38], &reftables[39]), }; const upb_fielddef google_protobuf_fields[73] = { - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 16, {0},&reftables[40], &reftables[41]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 10, {0},&reftables[42], &reftables[43]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 2, {0},&reftables[44], &reftables[45]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 14, {0},&reftables[46], &reftables[47]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 10, {0},&reftables[48], &reftables[49]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 4, {0},&reftables[50], &reftables[51]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 12, {0},&reftables[52], &reftables[53]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, {0},&reftables[54], &reftables[55]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 17, {0},&reftables[56], &reftables[57]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 20, {0},&reftables[58], &reftables[59]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 5, {0},&reftables[60], &reftables[61]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 5, {0},&reftables[62], &reftables[63]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 30, {0},&reftables[64], &reftables[65]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 27, {0},&reftables[66], &reftables[67]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 22, {0},&reftables[68], &reftables[69]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 7, {0},&reftables[70], &reftables[71]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 4, {0},&reftables[72], &reftables[73]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 7, {0},&reftables[74], &reftables[75]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 5, {0},&reftables[76], &reftables[77]), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, {0},&reftables[78], &reftables[79]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 13, {0},&reftables[80], &reftables[81]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 11, {0},&reftables[82], &reftables[83]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 9, {0},&reftables[84], &reftables[85]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 5, {0},&reftables[86], &reftables[87]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 2, {0},&reftables[88], &reftables[89]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 9, {0},&reftables[90], &reftables[91]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 4, {0},&reftables[92], &reftables[93]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 2, {0},&reftables[94], &reftables[95]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 15, {0},&reftables[96], &reftables[97]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 7, {0},&reftables[98], &reftables[99]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 4, {0},&reftables[100], &reftables[101]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 2, {0},&reftables[102], &reftables[103]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 2, {0},&reftables[104], &reftables[105]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 2, {0},&reftables[106], &reftables[107]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 2, {0},&reftables[108], &reftables[109]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 2, {0},&reftables[110], &reftables[111]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 2, {0},&reftables[112], &reftables[113]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 2, {0},&reftables[114], &reftables[115]), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, {0},&reftables[116], &reftables[117]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 11, {0},&reftables[118], &reftables[119]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 12, {0},&reftables[120], &reftables[121]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 3, {0},&reftables[122], &reftables[123]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 5, {0},&reftables[124], &reftables[125]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 8, {0},&reftables[126], &reftables[127]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 8, {0},&reftables[128], &reftables[129]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 10, {0},&reftables[130], &reftables[131]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 33, {0},&reftables[132], &reftables[133]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 10, {0},&reftables[134], &reftables[135]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 30, {0},&reftables[136], &reftables[137]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 11, {0},&reftables[138], &reftables[139]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 6, {0},&reftables[140], &reftables[141]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 17, {0},&reftables[142], &reftables[143]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 8, {0},&reftables[144], &reftables[145]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 5, {0},&reftables[146], &reftables[147]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 3, {0},&reftables[148], &reftables[149]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, {0},&reftables[150], &reftables[151]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 10, {0},&reftables[152], &reftables[153]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 12, {0},&reftables[154], &reftables[155]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 25, {0},&reftables[156], &reftables[157]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 36, {0},&reftables[158], &reftables[159]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, {0},&reftables[160], &reftables[161]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, {0},&reftables[162], &reftables[163]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 13, {0},&reftables[164], &reftables[165]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 10, {0},&reftables[166], &reftables[167]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 11, {0},&reftables[168], &reftables[169]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[170], &reftables[171]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[172], &reftables[173]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 6, {0},&reftables[174], &reftables[175]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 16, {0},&reftables[176], &reftables[177]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 10, {0},&reftables[178], &reftables[179]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[180], &reftables[181]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[182], &reftables[183]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 7, {0},&reftables[184], &reftables[185]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]), }; const upb_enumdef google_protobuf_enums[4] = { diff --git a/upb/descriptor/descriptor.upb.h b/upb/descriptor/descriptor.upb.h index 15fa383..9f0bee0 100755 --- a/upb/descriptor/descriptor.upb.h +++ b/upb/descriptor/descriptor.upb.h @@ -84,169 +84,169 @@ extern const upb_enumdef google_protobuf_enums[4]; #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART &google_protobuf_msgs[19] // Selector definitions. -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 16 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 18 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 15 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 17 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 15 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 16 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 14 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 4 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 26 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 28 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 21 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 23 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 20 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 22 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 25 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 27 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 6 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 8 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 5 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 7 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 11 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 21 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 22 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 18 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 19 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 17 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 5 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 20 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 6 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 9 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 10 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 8 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 26 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 25 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 24 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 12 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 10 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 12 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 31 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 30 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 6 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 8 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 5 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 7 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 11 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 3 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 23 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 10 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 9 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 8 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 5 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 4 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 #define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 5 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 6 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 5 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 4 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 7 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 #define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 16 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 15 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 14 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 7 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 6 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 5 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 9 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 8 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 18 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 17 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 10 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 13 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 12 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 11 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 2 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 4 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 7 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 6 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 5 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 3 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 9 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 11 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 8 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 10 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 9 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 12 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 8 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 11 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 10 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 19 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 21 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 18 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 20 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 29 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 31 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 28 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 30 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 14 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 16 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 13 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 15 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 34 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 33 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 7 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 6 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 5 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 24 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 26 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 23 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 25 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 37 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 36 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 3 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 18 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 17 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 16 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 9 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 8 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 7 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 11 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 6 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 5 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 4 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 10 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 12 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 15 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 14 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 13 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 6 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 8 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 11 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 10 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 9 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 7 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 29 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 32 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 28 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 31 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 30 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 13 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 3 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 18 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 19 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 17 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 5 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 9 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 10 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 8 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 24 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 23 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 22 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 27 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 26 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 25 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 15 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 16 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 14 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 21 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 7 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 4 #define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 2 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 10 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 13 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 11 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 9 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 7 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 6 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 5 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 4 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 3 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 2 -#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 8 -#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 12 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 15 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 17 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 14 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 16 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 2 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 3 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 5 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 7 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 4 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 6 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 7 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 6 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 5 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 12 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 11 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 10 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 9 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 8 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 3 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 14 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 17 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 15 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 13 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 11 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 10 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 9 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 8 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 7 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 6 +#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 12 +#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 16 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 6 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 7 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 9 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 8 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 7 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 6 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 5 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 4 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 12 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 11 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 10 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 #define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 6 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 8 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 5 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 7 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 5 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 4 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 10 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 9 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 8 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 #define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 4 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4 @@ -254,28 +254,28 @@ extern const upb_enumdef google_protobuf_enums[4]; #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 18 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 17 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 16 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 12 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 9 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 8 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 7 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 3 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 17 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 16 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 15 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 11 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 8 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 7 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 6 #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5 #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4 #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3 #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 3 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 4 #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 2 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 11 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 10 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 15 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 14 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 13 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 3 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 10 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 9 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 14 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 13 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 12 #ifdef __cplusplus }; // extern "C" diff --git a/upb/descriptor/reader.c b/upb/descriptor/reader.c index 8deaa35..9dff6e9 100644 --- a/upb/descriptor/reader.c +++ b/upb/descriptor/reader.c @@ -49,18 +49,7 @@ static char *upb_join(const char *base, const char *name) { /* upb_deflist ****************************************************************/ -// upb_deflist is an internal-only dynamic array for storing a growing list of -// upb_defs. -typedef struct { - upb_pipeline *pipeline; - upb_def **defs; - size_t len; - size_t size; - bool owned; -} upb_deflist; - -void upb_deflist_init(upb_deflist *l, upb_pipeline *pipeline) { - l->pipeline = pipeline; +void upb_deflist_init(upb_deflist *l) { l->size = 0; l->defs = NULL; l->len = 0; @@ -71,15 +60,14 @@ void upb_deflist_uninit(upb_deflist *l) { if (l->owned) for(size_t i = 0; i < l->len; i++) upb_def_unref(l->defs[i], l); + free(l->defs); } bool upb_deflist_push(upb_deflist *l, upb_def *d) { if(++l->len >= l->size) { size_t new_size = UPB_MAX(l->size, 4); new_size *= 2; - l->defs = upb_pipeline_realloc( - l->pipeline, l->defs, - l->size * sizeof(void*), new_size * sizeof(void*)); + l->defs = realloc(l->defs, new_size * sizeof(void *)); if (!l->defs) return false; l->size = new_size; } @@ -111,63 +99,16 @@ static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) { /* upb_descreader ************************************************************/ -// We keep a stack of all the messages scopes we are currently in, as well as -// the top-level file scope. This is necessary to correctly qualify the -// definitions that are contained inside. "name" tracks the name of the -// message or package (a bare name -- not qualified by any enclosing scopes). -typedef struct { - char *name; - // Index of the first def that is under this scope. For msgdefs, the - // msgdef itself is at start-1. - int start; -} upb_descreader_frame; - -struct upb_descreader { - upb_deflist defs; - upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; - int stack_len; - - uint32_t number; - char *name; - bool saw_number; - bool saw_name; - - char *default_string; - - upb_fielddef *f; -}; - -void upb_descreader_init(void *self, upb_pipeline *p); -void upb_descreader_uninit(void *self); - -const upb_frametype upb_descreader_frametype = { - sizeof(upb_descreader), - upb_descreader_init, - upb_descreader_uninit, - NULL, -}; - -const upb_frametype *upb_descreader_getframetype() { - return &upb_descreader_frametype; -} - -// Registers handlers that will build the defs. Pass the descreader as the -// closure. -const upb_handlers *upb_descreader_gethandlers(const void *owner); - - -/* upb_descreader ************************************************************/ - -void upb_descreader_init(void *self, upb_pipeline *pipeline) { - upb_descreader *r = self; - upb_deflist_init(&r->defs, pipeline); +void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers, + upb_status *status) { + upb_deflist_init(&r->defs); + upb_sink_reset(upb_descreader_input(r), handlers, r); r->stack_len = 0; r->name = NULL; r->default_string = NULL; } -void upb_descreader_uninit(void *self) { - upb_descreader *r = self; +void upb_descreader_uninit(upb_descreader *r) { free(r->name); upb_deflist_uninit(&r->defs); free(r->default_string); @@ -183,6 +124,10 @@ upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) { return r->defs.defs; } +upb_sink *upb_descreader_input(upb_descreader *r) { + return (upb_sink*)r->sink; +} + static upb_msgdef *upb_descreader_top(upb_descreader *r) { assert(r->stack_len > 1); int index = r->stack[r->stack_len-1].start - 1; @@ -271,7 +216,7 @@ static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { UPB_UNUSED(hd); upb_descreader *r = closure; if(!r->saw_number || !r->saw_name) { - upb_status_seterrliteral(status, "Enum value missing name or number."); + upb_status_seterrmsg(status, "Enum value missing name or number."); return false; } upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); @@ -300,11 +245,11 @@ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); if (upb_def_fullname(upb_descreader_last(r)) == NULL) { - upb_status_seterrliteral(status, "Enum had no name."); + upb_status_seterrmsg(status, "Enum had no name."); return false; } if (upb_enumdef_numvals(e) == 0) { - upb_status_seterrliteral(status, "Enum had no values."); + upb_status_seterrmsg(status, "Enum had no values."); return false; } return true; @@ -409,7 +354,7 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) { if (r->default_string) { if (upb_fielddef_issubmsg(f)) { - upb_status_seterrliteral(status, "Submessages cannot have defaults."); + upb_status_seterrmsg(status, "Submessages cannot have defaults."); return false; } if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) { @@ -418,7 +363,7 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) { if (r->default_string && !parse_default(r->default_string, f)) { // We don't worry too much about giving a great error message since the // compiler should have ensured this was correct. - upb_status_seterrliteral(status, "Error converting default value."); + upb_status_seterrmsg(status, "Error converting default value."); return false; } } @@ -495,7 +440,7 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); if(!upb_def_fullname(UPB_UPCAST(m))) { - upb_status_seterrliteral(status, "Encountered message with no name."); + upb_status_seterrmsg(status, "Encountered message with no name."); return false; } upb_descreader_endcontainer(r); @@ -543,42 +488,40 @@ static void reghandlers(void *closure, upb_handlers *h) { const upb_msgdef *m = upb_handlers_msgdef(h); if (m == GOOGLE_PROTOBUF_DESCRIPTORPROTO) { - upb_handlers_setstartmsg(h, &msg_startmsg, NULL, NULL); - upb_handlers_setendmsg(h, &msg_endmsg, NULL, NULL); - upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL, NULL); - upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL, NULL); + upb_handlers_setstartmsg(h, &msg_startmsg, NULL); + upb_handlers_setendmsg(h, &msg_endmsg, NULL); + upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL); + upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL); // TODO: support extensions - upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL, NULL); + upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL); } else if (m == GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO) { - upb_handlers_setstartmsg(h, &file_startmsg, NULL, NULL); - upb_handlers_setendmsg(h, &file_endmsg, NULL, NULL); - upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL, NULL); + upb_handlers_setstartmsg(h, &file_startmsg, NULL); + upb_handlers_setendmsg(h, &file_endmsg, NULL); + upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL); // TODO: support extensions - upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL, NULL); + upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL); } else if (m == GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO) { - upb_handlers_setstartmsg(h, &enumval_startmsg, NULL, NULL); - upb_handlers_setendmsg(h, &enumval_endmsg, NULL, NULL); - upb_handlers_setstring(h, f(h, "name"), &enumval_onname, NULL, NULL); - upb_handlers_setint32(h, f(h, "number"), &enumval_onnumber, NULL, NULL); + upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); + upb_handlers_setendmsg(h, &enumval_endmsg, NULL); + upb_handlers_setstring(h, f(h, "name"), &enumval_onname, NULL); + upb_handlers_setint32(h, f(h, "number"), &enumval_onnumber, NULL); } else if (m == GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO) { - upb_handlers_setstartmsg(h, &enum_startmsg, NULL, NULL); - upb_handlers_setendmsg(h, &enum_endmsg, NULL, NULL); - upb_handlers_setstring(h, f(h, "name"), &enum_onname, NULL, NULL); + upb_handlers_setstartmsg(h, &enum_startmsg, NULL); + upb_handlers_setendmsg(h, &enum_endmsg, NULL); + upb_handlers_setstring(h, f(h, "name"), &enum_onname, NULL); } else if (m == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO) { - upb_handlers_setstartmsg(h, &field_startmsg, NULL, NULL); - upb_handlers_setendmsg(h, &field_endmsg, NULL, NULL); - upb_handlers_setint32 (h, f(h, "type"), &field_ontype, NULL, NULL); - upb_handlers_setint32 (h, f(h, "label"), &field_onlabel, NULL, NULL); - upb_handlers_setint32 (h, f(h, "number"), &field_onnumber, NULL, NULL); - upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL, NULL); - upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL, NULL); - upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL, - NULL); + upb_handlers_setstartmsg(h, &field_startmsg, NULL); + upb_handlers_setendmsg(h, &field_endmsg, NULL); + upb_handlers_setint32(h, f(h, "type"), &field_ontype, NULL); + upb_handlers_setint32(h, f(h, "label"), &field_onlabel, NULL); + upb_handlers_setint32(h, f(h, "number"), &field_onnumber, NULL); + upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL); + upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL); + upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL); } } -const upb_handlers *upb_descreader_gethandlers(const void *owner) { +const upb_handlers *upb_descreader_newhandlers(const void *owner) { return upb_handlers_newfrozen( - GOOGLE_PROTOBUF_FILEDESCRIPTORSET, &upb_descreader_frametype, - owner, reghandlers, NULL); + GOOGLE_PROTOBUF_FILEDESCRIPTORSET, owner, reghandlers, NULL); } diff --git a/upb/descriptor/reader.h b/upb/descriptor/reader.h index d00830b..f9d0046 100644 --- a/upb/descriptor/reader.h +++ b/upb/descriptor/reader.h @@ -11,7 +11,44 @@ #ifndef UPB_DESCRIPTOR_H #define UPB_DESCRIPTOR_H -#include "upb/handlers.h" +#include "upb/sink.h" + +#ifdef __cplusplus +namespace upb { +namespace descriptor { +class Reader; +} // namespace descriptor +} // namespace upb + +typedef upb::descriptor::Reader upb_descreader; +#else +struct upb_descreader; +typedef struct upb_descreader upb_descreader; +#endif + +// Internal-only structs used by Reader. + +// upb_deflist is an internal-only dynamic array for storing a growing list of +// upb_defs. +typedef struct { + UPB_PRIVATE_FOR_CPP + upb_def **defs; + size_t len; + size_t size; + bool owned; +} upb_deflist; + +// We keep a stack of all the messages scopes we are currently in, as well as +// the top-level file scope. This is necessary to correctly qualify the +// definitions that are contained inside. "name" tracks the name of the +// message or package (a bare name -- not qualified by any enclosing scopes). +typedef struct { + UPB_PRIVATE_FOR_CPP + char *name; + // Index of the first def that is under this scope. For msgdefs, the + // msgdef itself is at start-1. + int start; +} upb_descreader_frame; // The maximum number of nested declarations that are allowed, ie. // message Foo { @@ -26,55 +63,87 @@ #define UPB_MAX_MESSAGE_NESTING 64 #ifdef __cplusplus -namespace upb { -namespace descriptor { -// Frame type that accumulates defs as they are being built from a descriptor -// according to the descriptor.proto schema. -class Reader; - -// Gets the array of defs that have been parsed and removes them from the -// descreader. Ownership of the defs is passed to the caller using the given -// owner), but the ownership of the returned array is retained and is -// invalidated by any other call into the descreader. The defs will not have -// been resolved, and are ready to be added to a symtab. -inline upb::Def** GetDefs(Reader* r, void* owner, int* n); +// Class that receives descriptor data according to the descriptor.proto schema +// and use it to build upb::Defs corresponding to that schema. +class upb::descriptor::Reader { + public: + // These handlers must have come from NewHandlers() and must outlive the + // Reader. + // + // TODO: generate the handlers statically (like we do with the + // descriptor.proto defs) so that there is no need to pass this parameter (or + // to build/memory-manage the handlers at runtime at all). Unfortunately this + // is a bit tricky to implement for Handlers, but necessary to simplify this + // interface. + Reader(const Handlers* handlers, Status* status); + ~Reader(); + + // Resets the reader's state and discards any defs it may have built. + void Reset(); + + // The reader's input; this is where descriptor.proto data should be sent. + Sink* input(); + + // Returns an array of all defs that have been parsed, and transfers ownership + // of them to "owner". The number of defs is stored in *n. Ownership of the + // returned array is retained and is invalidated by any other call into + // Reader. + // + // These defs are not frozen or resolved; they are ready to be added to a + // symtab. + upb::Def** GetDefs(void* owner, int* n); + + // Builds and returns handlers for the reader, owned by "owner." + static Handlers* NewHandlers(const void* owner); + + private: +#else +struct upb_descreader { +#endif + char sink[sizeof(upb_sink)]; + upb_deflist defs; + upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; + int stack_len; -// Gets the handlers for reading a FileDescriptorSet, which builds defs and -// accumulates them in a Reader object (which the handlers use as their -// FrameType). -inline const upb::Handlers* GetReaderHandlers(const void* owner); + uint32_t number; + char *name; + bool saw_number; + bool saw_name; -} // namespace descriptor -} // namespace upb + char *default_string; -typedef upb::descriptor::Reader upb_descreader; + upb_fielddef *f; +}; +#ifdef __cplusplus extern "C" { -#else -struct upb_descreader; -typedef struct upb_descreader upb_descreader; #endif // C API. -const upb_frametype *upb_descreader_getframetype(); +void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers, + upb_status *status); +void upb_descreader_uninit(upb_descreader *r); +void upb_descreader_reset(upb_descreader *r); +upb_sink *upb_descreader_input(upb_descreader *r); upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n); -const upb_handlers *upb_descreader_gethandlers(const void *owner); - - -// C++ implementation details. ///////////////////////////////////////////////// +const upb_handlers *upb_descreader_newhandlers(const void *owner); #ifdef __cplusplus } // extern "C" -namespace upb { +// C++ implementation details. ///////////////////////////////////////////////// +namespace upb { namespace descriptor { -inline upb::Def** GetDefs(Reader* r, void* owner, int* n) { - return upb_descreader_getdefs(r, owner, n); +inline Reader::Reader(const Handlers *h, Status *s) { + upb_descreader_init(this, h, s); } -inline const upb::Handlers* GetReaderHandlers(const void* owner) { - return upb_descreader_gethandlers(owner); +inline Reader::~Reader() { upb_descreader_uninit(this); } +inline void Reader::Reset() { upb_descreader_reset(this); } +inline Sink* Reader::input() { return upb_descreader_input(this); } +inline upb::Def** Reader::GetDefs(void* owner, int* n) { + return upb_descreader_getdefs(this, owner, n); } } // namespace descriptor } // namespace upb diff --git a/upb/google/bridge.cc b/upb/google/bridge.cc index caf4935..bb5c631 100644 --- a/upb/google/bridge.cc +++ b/upb/google/bridge.cc @@ -4,10 +4,11 @@ // Copyright (c) 2011-2012 Google Inc. See LICENSE for details. // Author: Josh Haberman <jhaberman@gmail.com> // -// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined -// and once without! This allows us to provide functionality against proto2 -// and protobuf opensource both in a single binary without the two conflicting. -// However we must be careful not to violate the ODR. +// IMPORTANT NOTE! Inside Google, This file is compiled TWICE, once with +// UPB_GOOGLE3 defined and once without! This allows us to provide +// functionality against proto2 and protobuf opensource both in a single binary +// without the two conflicting. However we must be careful not to violate the +// ODR. #include "upb/google/bridge.h" @@ -21,204 +22,84 @@ #define ASSERT_STATUS(status) do { \ if (!upb_ok(status)) { \ - fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \ + fprintf(stderr, "upb status failure: %s\n", upb_status_errmsg(status)); \ assert(upb_ok(status)); \ } \ } while (0) - -namespace upb { -namespace proto2_bridge_google3 { class Defs; } -namespace proto2_bridge_opensource { class Defs; } -} // namespace upb - #ifdef UPB_GOOGLE3 #include "net/proto2/public/descriptor.h" #include "net/proto2/public/message.h" #include "net/proto2/proto/descriptor.pb.h" namespace goog = ::proto2; -namespace me = ::upb::proto2_bridge_google3; #else #include "google/protobuf/descriptor.h" #include "google/protobuf/message.h" #include "google/protobuf/descriptor.pb.h" namespace goog = ::google::protobuf; -namespace me = ::upb::proto2_bridge_opensource; #endif -class me::Defs { - public: - void OnMessage(Handlers* h) { - const upb::MessageDef* md = h->message_def(); - const goog::Message& m = *message_map_[md]; - const goog::Descriptor* d = m.GetDescriptor(); - for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) { - const upb::FieldDef* upb_f = *i; - const goog::FieldDescriptor* proto2_f = - d->FindFieldByNumber(upb_f->number()); - if (!proto2_f) { - proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number()); - } - assert(proto2_f); - if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h) +namespace { + +const goog::Message* GetPrototype(const goog::Message& m, + const goog::FieldDescriptor* f) { + const goog::Message* ret = NULL; #ifdef UPB_GOOGLE3 - && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h) + ret = upb::google::GetProto1WeakPrototype(m, f); + if (ret) return ret; #endif - ) { - // Unsupported reflection class. - // - // Should we fall back to using the public Reflection interface in this - // case? It's unclear whether it's supported behavior for users to - // create their own Reflection classes. - assert(false); - } - } - } - - static void StaticOnMessage(void* closure, upb::Handlers* handlers) { - me::Defs* defs = static_cast<me::Defs*>(closure); - defs->OnMessage(handlers); - } - - void AddSymbol(const std::string& name, upb::Def* def) { - assert(symbol_map_.find(name) == symbol_map_.end()); - symbol_map_[name] = def; - } - void AddMessage(const goog::Message* m, upb::MessageDef* md) { - assert(message_map_.find(md) == message_map_.end()); - message_map_[md] = m; - AddSymbol(m->GetDescriptor()->full_name(), md->Upcast()); - } - - upb::Def* FindSymbol(const std::string& name) { - SymbolMap::iterator iter = symbol_map_.find(name); - return iter != symbol_map_.end() ? iter->second : NULL; - } - - void Flatten(std::vector<upb::Def*>* defs) { - SymbolMap::iterator iter; - for (iter = symbol_map_.begin(); iter != symbol_map_.end(); ++iter) { - defs->push_back(iter->second); - } + if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { + ret = upb::google::GetFieldPrototype(m, f); +#ifdef UPB_GOOGLE3 + if (!ret) ret = upb::google::GetProto1FieldPrototype(m, f); +#endif + assert(ret); } + return ret; +} - private: - // Maps a new upb::MessageDef* to a corresponding proto2 Message* whose - // derived class is of the correct type according to the message the user - // gave us. - typedef std::map<const upb::MessageDef*, const goog::Message*> MessageMap; - MessageMap message_map_; - - // Maps a type name to a upb Def we have constructed to represent it. - typedef std::map<std::string, upb::Def*> SymbolMap; - SymbolMap symbol_map_; -}; +} // namespace namespace upb { namespace google { -// For submessage fields, stores a pointer to an instance of the submessage in -// *subm (but it is *not* guaranteed to be a prototype). -FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f, - upb::MessageDef* md, const goog::Message** subm) { - // To parse weak submessages effectively, we need to represent them in the - // upb::Def schema even though they are not reflected in the proto2 - // descriptors (weak fields are represented as FieldDescriptor::TYPE_BYTES). - const goog::Message* weak_prototype = NULL; -#ifdef UPB_GOOGLE3 - weak_prototype = upb::google::GetProto1WeakPrototype(m, f); -#endif - - upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f); - upb::Status status; - upb_f->set_number(f->number(), &status); - upb_f->set_name(f->name(), &status); - upb_f->set_label(upb::FieldDef::ConvertLabel(f->label())); - upb_f->set_descriptor_type( - weak_prototype ? UPB_DESCRIPTOR_TYPE_MESSAGE - : upb::FieldDef::ConvertDescriptorType(f->type())); - - if (weak_prototype) { - upb_f->set_subdef_name( - weak_prototype->GetDescriptor()->full_name(), &status); - } else { - switch (upb_f->type()) { - case UPB_TYPE_INT32: - upb_f->set_default_int32(f->default_value_int32()); - break; - case UPB_TYPE_INT64: - upb_f->set_default_int64(f->default_value_int64()); - break; - case UPB_TYPE_UINT32: - upb_f->set_default_uint32(f->default_value_uint32()); - break; - case UPB_TYPE_UINT64: - upb_f->set_default_uint64(f->default_value_uint64()); - break; - case UPB_TYPE_DOUBLE: - upb_f->set_default_double(f->default_value_double()); - break; - case UPB_TYPE_FLOAT: - upb_f->set_default_float(f->default_value_float()); - break; - case UPB_TYPE_BOOL: - upb_f->set_default_bool(f->default_value_bool()); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - upb_f->set_default_string(f->default_value_string(), &status); - break; - case UPB_TYPE_MESSAGE: - upb_f->set_subdef_name(f->message_type()->full_name(), &status); - break; - case UPB_TYPE_ENUM: - // We set the enum default numerically. - upb_f->set_default_int32(f->default_value_enum()->number()); - upb_f->set_subdef_name(f->enum_type()->full_name(), &status); - break; - } - } - md->AddField(upb_f, &upb_f, &status); - ASSERT_STATUS(&status); +/* DefBuilder ****************************************************************/ - if (weak_prototype) { - *subm = weak_prototype; - } else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { - *subm = upb::google::GetFieldPrototype(m, f); -#ifdef UPB_GOOGLE3 - if (!*subm) *subm = upb::google::GetProto1FieldPrototype(m, f); -#endif - assert(*subm); - } +const EnumDef* DefBuilder::GetOrCreateEnumDef(const goog::EnumDescriptor* ed) { + const EnumDef* cached = FindInCache<EnumDef>(ed); + if (cached) return cached; - return upb_f; -} + EnumDef* e = AddToCache(ed, EnumDef::New()); -upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, const void* owner) { - upb::EnumDef* e = upb::EnumDef::New(owner); - upb::Status status; - e->set_full_name(desc->full_name(), &status); - for (int i = 0; i < desc->value_count(); i++) { - const goog::EnumValueDescriptor* val = desc->value(i); + Status status; + e->set_full_name(ed->full_name(), &status); + for (int i = 0; i < ed->value_count(); i++) { + const goog::EnumValueDescriptor* val = ed->value(i); bool success = e->AddValue(val->name(), val->number(), &status); UPB_ASSERT_VAR(success, success); } + + e->Freeze(&status); + ASSERT_STATUS(&status); return e; } -static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner, - me::Defs* defs) { - upb::MessageDef* md = upb::MessageDef::New(owner); - const goog::Descriptor* d = m.GetDescriptor(); - upb::Status status; - md->set_full_name(m.GetDescriptor()->full_name(), &status); +const MessageDef* DefBuilder::GetOrCreateMaybeUnfrozenMessageDef( + const goog::Descriptor* d, const goog::Message* m) { + const MessageDef* cached = FindInCache<MessageDef>(d); + if (cached) return cached; - // Must do this before processing submessages to prevent infinite recursion. - defs->AddMessage(&m, md); + MessageDef* md = AddToCache(d, MessageDef::New()); + to_freeze_.push_back(upb::upcast(md)); + Status status; + md->set_full_name(d->full_name(), &status); + ASSERT_STATUS(&status); + + // Find all regular fields and extensions for this message. std::vector<const goog::FieldDescriptor*> fields; d->file()->pool()->FindAllExtensions(d, &fields); for (int i = 0; i < d->field_count(); i++) { @@ -232,49 +113,161 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner, // Skip lazy fields for now since we can't properly handle them. if (proto2_f->options().lazy()) continue; #endif - const goog::Message* subm_prototype; - upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype); - - if (!f->HasSubDef()) continue; - - upb::Def* subdef = defs->FindSymbol(f->subdef_name()); - if (!subdef) { - if (f->type() == UPB_TYPE_ENUM) { - subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast(); - defs->AddSymbol(subdef->full_name(), subdef); - } else { - assert(f->IsSubMessage()); - assert(subm_prototype); - subdef = NewMessageDef(*subm_prototype, owner, defs)->Upcast(); - } - } - f->set_subdef(subdef, &status); + md->AddField(NewFieldDef(proto2_f, m), &status); } ASSERT_STATUS(&status); return md; } -const upb::Handlers* NewWriteHandlers(const goog::Message& m, - const void* owner) { - me::Defs defs; - const upb::MessageDef* md = NewMessageDef(m, owner, &defs); +reffed_ptr<FieldDef> DefBuilder::NewFieldDef(const goog::FieldDescriptor* f, + const goog::Message* m) { + const goog::Message* subm = NULL; + const goog::Message* weak_prototype = NULL; - std::vector<upb::Def*> defs_vec; - defs.Flatten(&defs_vec); + if (m) { +#ifdef UPB_GOOGLE3 + weak_prototype = upb::google::GetProto1WeakPrototype(*m, f); +#endif + subm = GetPrototype(*m, f); + } + + reffed_ptr<FieldDef> upb_f(FieldDef::New()); Status status; - bool success = Def::Freeze(defs_vec, &status); - UPB_ASSERT_VAR(success, success); + upb_f->set_number(f->number(), &status); + upb_f->set_name(f->name(), &status); + upb_f->set_label(FieldDef::ConvertLabel(f->label())); + + // For weak fields, weak_prototype will be non-NULL even though the proto2 + // descriptor does not indicate a submessage field. + upb_f->set_descriptor_type(weak_prototype + ? UPB_DESCRIPTOR_TYPE_MESSAGE + : FieldDef::ConvertDescriptorType(f->type())); + + switch (upb_f->type()) { + case UPB_TYPE_INT32: + upb_f->set_default_int32(f->default_value_int32()); + break; + case UPB_TYPE_INT64: + upb_f->set_default_int64(f->default_value_int64()); + break; + case UPB_TYPE_UINT32: + upb_f->set_default_uint32(f->default_value_uint32()); + break; + case UPB_TYPE_UINT64: + upb_f->set_default_uint64(f->default_value_uint64()); + break; + case UPB_TYPE_DOUBLE: + upb_f->set_default_double(f->default_value_double()); + break; + case UPB_TYPE_FLOAT: + upb_f->set_default_float(f->default_value_float()); + break; + case UPB_TYPE_BOOL: + upb_f->set_default_bool(f->default_value_bool()); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + upb_f->set_default_string(f->default_value_string(), &status); + break; + case UPB_TYPE_MESSAGE: + upb_f->set_message_subdef( + GetOrCreateMaybeUnfrozenMessageDef(subm->GetDescriptor(), subm), + &status); + break; + case UPB_TYPE_ENUM: + // We set the enum default numerically. + upb_f->set_default_int32(f->default_value_enum()->number()); + upb_f->set_enum_subdef(GetOrCreateEnumDef(f->enum_type()), &status); + break; + } + + ASSERT_STATUS(&status); + return upb_f; +} - const upb::Handlers* ret = upb::Handlers::NewFrozen( - md, NULL, owner, me::Defs::StaticOnMessage, &defs); +void DefBuilder::Freeze() { + upb::Status status; + upb::Def::Freeze(to_freeze_, &status); + ASSERT_STATUS(&status); + to_freeze_.clear(); +} - // Unref all defs, since they're now ref'd by the handlers. - for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) { - defs_vec[i]->Unref(owner); +const MessageDef* DefBuilder::GetOrCreateMessageDef(const goog::Descriptor* d) { + const MessageDef* ret = GetOrCreateMaybeUnfrozenMessageDef(d, NULL); + Freeze(); + return ret; +} + +const MessageDef* DefBuilder::GetOrCreateMessageDefExpandWeak( + const goog::Message& m) { + const MessageDef* ret = + GetOrCreateMaybeUnfrozenMessageDef(m.GetDescriptor(), &m); + Freeze(); + return ret; +} + + +/* CodeCache *****************************************************************/ + +const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers( + const MessageDef* md, const goog::Message& m) { + const Handlers* cached = FindInCache(md); + if (cached) return cached; + + Handlers* h = AddToCache(md, upb::Handlers::New(md)); + to_freeze_.push_back(h); + const goog::Descriptor* d = m.GetDescriptor(); + + for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) { + const FieldDef* upb_f = *i; + + const goog::FieldDescriptor* proto2_f = + d->FindFieldByNumber(upb_f->number()); + if (!proto2_f) { + proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number()); + } + assert(proto2_f); + + if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h) +#ifdef UPB_GOOGLE3 + && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h) +#endif + ) { + // Unsupported reflection class. + // + // Should we fall back to using the public Reflection interface in this + // case? It's unclear whether it's supported behavior for users to + // create their own Reflection classes. + assert(false); + } + + if (upb_f->type() == UPB_TYPE_MESSAGE) { + const goog::Message* prototype = GetPrototype(m, proto2_f); + assert(prototype); + const upb::Handlers* sub_handlers = GetOrCreateMaybeUnfrozenWriteHandlers( + upb_f->message_subdef(), *prototype); + h->SetSubHandlers(upb_f, sub_handlers); + } } + return h; +} + +const Handlers* CodeCache::GetOrCreateWriteHandlers(const goog::Message& m) { + const MessageDef* md = def_builder_.GetOrCreateMessageDefExpandWeak(m); + const Handlers* ret = GetOrCreateMaybeUnfrozenWriteHandlers(md, m); + upb::Status status; + upb::Handlers::Freeze(to_freeze_, &status); + ASSERT_STATUS(&status); + to_freeze_.clear(); return ret; } +upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const goog::Message& m) { + CodeCache cache; + return upb::reffed_ptr<const upb::Handlers>( + cache.GetOrCreateWriteHandlers(m)); +} + } // namespace google } // namespace upb diff --git a/upb/google/bridge.h b/upb/google/bridge.h index 5091e23..c8bdd47 100644 --- a/upb/google/bridge.h +++ b/upb/google/bridge.h @@ -11,33 +11,22 @@ // read/write only a subset of the fields for higher performance when only some // fields are needed. // -// Example usage (FIX XXX): -// -// // Build a def that will have all fields and parse just like proto2 would. -// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto()); +// Example usage: // // // JIT the parser; should only be done once ahead-of-time. -// upb::Handlers* handlers = upb::NewHandlersForMessage(md); -// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers); -// handlers->Unref(); +// upb::reffed_ptr<const upb::Handlers> write_myproto( +// upb::google::NewWriteHandlers(MyProto())); +// upb::reffed_ptr<const upb::Handlers> parse_myproto( +// upb::Decoder::NewDecoderHandlers(write_myproto.get(), true)); // // // The actual parsing. // MyProto proto; -// upb::Decoder decoder; -// upb::StringSource source(buf, len); -// decoder.ResetPlan(plan, 0); -// decoder.ResetInput(source.AllBytes(), &proto); -// CHECK(decoder.Decode() == UPB_OK) << decoder.status(); -// -// To parse only one field and skip all others: -// -// const upb::MessageDef* md = -// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype()); -// upb::proto2_bridge::AddFieldDef( -// MyProto::descriptor()->FindFieldByName("my_field"), md); -// upb::Freeze(md); -// -// // Now continue with "JIT the parser" from above. +// upb::SeededPipeline<8192> pipeline(upb_realloc, NULL); +// upb::Sink* write_sink = pipeline.NewSink(write_myproto.get()); +// upb::Sink* parse_sink = pipeline.NewSink(parse_myproto.get()); +// upb::pb::Decoder* decoder = decoder_sink->GetObject<upb::pb::Decoder>(); +// upb::pb::ResetDecoderSink(decoder, write_sink); +// write_sink->Reset(&proto); // // Note that there is currently no support for // CodedInputStream::SetExtensionRegistry(), which allows specifying a separate @@ -49,27 +38,167 @@ #ifndef UPB_GOOGLE_BRIDGE_H_ #define UPB_GOOGLE_BRIDGE_H_ +#include <map> +#include <vector> +#include "upb/upb.h" + namespace google { -namespace protobuf { class Message; } +namespace protobuf { +class FieldDescriptor; +class Descriptor; +class EnumDescriptor; +class Message; +} // namespace protobuf } // namespace google -namespace proto2 { class Message; } +namespace proto2 { +class FieldDescriptor; +class Descriptor; +class EnumDescriptor; +class Message; +} namespace upb { +class Def; +class EnumDef; +class FieldDef; +class MessageDef; class Handlers; namespace google { // Returns a upb::Handlers object that can be used to populate a proto2::Message -// object of the same type as "m." +// object of the same type as "m." For more control over handler caching and +// reuse, instantiate a CodeCache object below. +upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const proto2::Message& m); +upb::reffed_ptr<const upb::Handlers> NewWriteHandlers( + const ::google::protobuf::Message& m); + +// Builds upb::Defs from proto2::Descriptors, and caches all built Defs for +// reuse. CodeCache (below) uses this internally; there is no need to use this +// class directly unless you only want Defs without corresponding Handlers. +// +// This class is NOT thread-safe. +class DefBuilder { + public: + // Functions to get or create a Def from a corresponding proto2 Descriptor. + // The returned def will be frozen. + // + // The caller must take a ref on the returned value if it needs it long-term. + // The DefBuilder will retain a ref so it can keep the Def cached, but + // garbage-collection functionality may be added to DefBuilder later that + // could unref the returned pointer. + const EnumDef* GetOrCreateEnumDef(const proto2::EnumDescriptor* d); + const EnumDef* GetOrCreateEnumDef( + const ::google::protobuf::EnumDescriptor* d); + const MessageDef* GetOrCreateMessageDef(const proto2::Descriptor* d); + const MessageDef* GetOrCreateMessageDef( + const ::google::protobuf::Descriptor* d); + + // Gets or creates a frozen MessageDef, properly expanding weak fields. + // + // Weak fields are only represented as BYTES fields in the Descriptor (unless + // you construct your descriptors in a somewhat complicated way; see + // https://goto.google.com/weak-field-descriptor), but we can get their true + // definitions relatively easily from the proto Message class. + const MessageDef* GetOrCreateMessageDefExpandWeak(const proto2::Message& m); + const MessageDef* GetOrCreateMessageDefExpandWeak( + const ::google::protobuf::Message& m); + + private: + // Like GetOrCreateMessageDef*(), except the returned def might not be frozen. + // We need this function because circular graphs of MessageDefs need to all + // be frozen together, to we have to create the graphs of defs in an unfrozen + // state first. + // + // If m is non-NULL, expands weak message fields. + const MessageDef* GetOrCreateMaybeUnfrozenMessageDef( + const proto2::Descriptor* d, const proto2::Message* m); + const MessageDef* GetOrCreateMaybeUnfrozenMessageDef( + const ::google::protobuf::Descriptor* d, + const ::google::protobuf::Message* m); + + // Returns a new-unfrozen FieldDef corresponding to this FieldDescriptor. + // The return value is always newly created (never cached) and the returned + // pointer is the only owner of it. + // + // If "m" is non-NULL, expands the weak field if it is one, and populates + // *subm_prototype with a prototype of the submessage if this is a weak or + // non-weak MESSAGE or GROUP field. + reffed_ptr<FieldDef> NewFieldDef(const proto2::FieldDescriptor* f, + const proto2::Message* m); + reffed_ptr<FieldDef> NewFieldDef(const ::google::protobuf::FieldDescriptor* f, + const ::google::protobuf::Message* m); + + // Freeze all defs that haven't been frozen yet. + void Freeze(); + + template <class T> + T* AddToCache(const void *proto2_descriptor, reffed_ptr<T> def) { + assert(def_cache_.find(proto2_descriptor) == def_cache_.end()); + def_cache_[proto2_descriptor] = def; + return def.get(); // Continued lifetime is guaranteed by cache. + } + + template <class T> + const T* FindInCache(const void *proto2_descriptor) { + DefCache::iterator iter = def_cache_.find(proto2_descriptor); + return iter == def_cache_.end() ? NULL : + upb::down_cast<const T*>(iter->second.get()); + } + + private: + // Maps a proto2 descriptor to the corresponding upb Def we have constructed. + // The proto2 descriptor is void* because the proto2 descriptor types do not + // share a common base. + typedef std::map<const void*, reffed_ptr<upb::Def> > DefCache; + DefCache def_cache_; + + // Defs that have not been frozen yet. + vector<Def*> to_freeze_; +}; + +// Builds and caches upb::Handlers for populating proto2 generated classes. // -// TODO(haberman): Add handler caching functionality so that we don't use -// O(n^2) memory in the worst case when incrementally building handlers. -const upb::Handlers* NewWriteHandlers(const proto2::Message& m, - const void* owner); -const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m, - const void* owner); +// This class is NOT thread-safe. +class CodeCache { + public: + // Gets or creates handlers for populating messages of the given message type. + // + // The caller must take a ref on the returned value if it needs it long-term. + // The CodeCache will retain a ref so it can keep the Def cached, but + // garbage-collection functionality may be added to CodeCache later that could + // unref the returned pointer. + const Handlers* GetOrCreateWriteHandlers(const proto2::Message& m); + const Handlers* GetOrCreateWriteHandlers( + const ::google::protobuf::Message& m); + + private: + const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers( + const MessageDef* md, const proto2::Message& m); + const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers( + const MessageDef* md, const ::google::protobuf::Message& m); + + Handlers* AddToCache(const MessageDef* md, reffed_ptr<Handlers> handlers) { + assert(handlers_cache_.find(md) == handlers_cache_.end()); + handlers_cache_[md] = handlers; + return handlers.get(); // Continue lifetime is guaranteed by the cache. + } + + const Handlers* FindInCache(const MessageDef* md) { + HandlersCache::iterator iter = handlers_cache_.find(md); + return iter == handlers_cache_.end() ? NULL : iter->second.get(); + } + + DefBuilder def_builder_; + + typedef std::map<const MessageDef*, upb::reffed_ptr<const Handlers> > + HandlersCache; + HandlersCache handlers_cache_; + + vector<Handlers*> to_freeze_; +}; } // namespace google } // namespace upb diff --git a/upb/google/proto1.cc b/upb/google/proto1.cc index 51b221a..80a44d8 100644 --- a/upb/google/proto1.cc +++ b/upb/google/proto1.cc @@ -18,6 +18,8 @@ #include "upb/google/proto1.h" +#include <memory> + #include "net/proto2/public/repeated_field.h" #include "net/proto/internal_layout.h" #include "net/proto/proto2_reflection.h" @@ -226,10 +228,9 @@ class P2R_Handlers { } template <typename T> - static bool Append(proto2::RepeatedField<T>* r, T val) { + static void Append(proto2::RepeatedField<T>* r, T val) { // Proto1's ProtoArray class derives from proto2::RepeatedField. r->Add(val); - return true; } // String //////////////////////////////////////////////////////////////////// @@ -316,9 +317,8 @@ class P2R_Handlers { return field; } - static size_t OnCordBuf(Cord* c, const char* buf, size_t n) { + static void OnCordBuf(Cord* c, const char* buf, size_t n) { c->Append(StringPiece(buf, n)); - return true; } static Cord* StartRepeatedCord(proto2::RepeatedField<Cord>* r, @@ -370,7 +370,7 @@ class P2R_Handlers { const proto2::Message& m, const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) { - scoped_ptr<SubMessageHandlerData> data( + std::unique_ptr<SubMessageHandlerData> data( new SubMessageHandlerData(m, proto2_f, r)); if (f->IsSequence()) { SetStartSequenceHandler(proto2_f, r, f, h); @@ -385,7 +385,7 @@ class P2R_Handlers { const proto2::Message& m, const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) { - scoped_ptr<SubMessageHandlerData> data( + std::unique_ptr<SubMessageHandlerData> data( new SubMessageHandlerData(m, proto2_f, r)); if (f->IsSequence()) { SetStartSequenceHandler(proto2_f, r, f, h); diff --git a/upb/google/proto2.cc b/upb/google/proto2.cc index e878a65..d138123 100644 --- a/upb/google/proto2.cc +++ b/upb/google/proto2.cc @@ -314,28 +314,23 @@ case goog::FieldDescriptor::cpptype: \ } template <typename T> - static bool AppendPrimitive(goog::RepeatedField<T>* r, T val) { - r->Add(val); - return true; - } + static void AppendPrimitive(goog::RepeatedField<T>* r, T val) { r->Add(val); } template <typename T> - static bool AppendPrimitiveExtension(goog::Message* m, + static void AppendPrimitiveExtension(goog::Message* m, const ExtensionFieldData* data, T val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); // TODO(haberman): give an accurate value for "packed" goog::internal::RepeatedPrimitiveTypeTraits<T>::Add( data->number(), data->type(), true, val, set); - return true; } template <typename T> - static bool SetPrimitiveExtension(goog::Message* m, + static void SetPrimitiveExtension(goog::Message* m, const ExtensionFieldData* data, T val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); goog::internal::PrimitiveTypeTraits<T>::Set(data->number(), data->type(), val, set); - return true; } // Enum ////////////////////////////////////////////////////////////////////// @@ -379,7 +374,7 @@ case goog::FieldDescriptor::cpptype: \ } } - static bool SetEnum(goog::Message* m, const EnumHandlerData* data, + static void SetEnum(goog::Message* m, const EnumHandlerData* data, int32_t val) { if (data->IsValidValue(val)) { int32_t* message_val = data->GetFieldPointer<int32_t>(m); @@ -388,10 +383,9 @@ case goog::FieldDescriptor::cpptype: \ } else { data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val); } - return true; } - static bool AppendEnum(goog::Message* m, const EnumHandlerData* data, + static void AppendEnum(goog::Message* m, const EnumHandlerData* data, int32_t val) { // Closure is the enclosing message. We can't use the RepeatedField<> as // the closure because we need to go back to the message for unrecognized @@ -403,7 +397,6 @@ case goog::FieldDescriptor::cpptype: \ } else { data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val); } - return true; } // EnumExtension ///////////////////////////////////////////////////////////// @@ -421,19 +414,17 @@ case goog::FieldDescriptor::cpptype: \ } } - static bool SetEnumExtension(goog::Message* m, const ExtensionFieldData* data, + static void SetEnumExtension(goog::Message* m, const ExtensionFieldData* data, int32_t val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); set->SetEnum(data->number(), data->type(), val, NULL); - return true; } - static bool AppendEnumExtension(goog::Message* m, + static void AppendEnumExtension(goog::Message* m, const ExtensionFieldData* data, int32_t val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); // TODO(haberman): give an accurate value for "packed" set->AddEnum(data->number(), data->type(), true, val, NULL); - return true; } // String //////////////////////////////////////////////////////////////////// diff --git a/upb/handlers-inl.h b/upb/handlers-inl.h index d5ed940..a101da6 100644 --- a/upb/handlers-inl.h +++ b/upb/handlers-inl.h @@ -95,284 +95,497 @@ namespace upb { -// Deleter: class for constructing a function that deletes a pointer type. -template <class T> struct Deleter { - static void Delete(void* p) { delete static_cast<T*>(p); } +template<> +class Pointer<Handlers> { + public: + explicit Pointer(Handlers* ptr) : ptr_(ptr) {} + operator Handlers*() { return ptr_; } + operator RefCounted*() { return UPB_UPCAST(ptr_); } + private: + Handlers* ptr_; }; -template <class T> Deleter<T> MatchDeleter(T* data) { - UPB_UNUSED(data); - return Deleter<T>(); -} +template<> +class Pointer<const Handlers> { + public: + explicit Pointer(const Handlers* ptr) : ptr_(ptr) {} + operator const Handlers*() { return ptr_; } + operator const RefCounted*() { return UPB_UPCAST(ptr_); } + private: + const Handlers* ptr_; +}; + +typedef void CleanupFunc(void *ptr); + +// Template to remove "const" from "const T*" and just return "T*". +// +// We define a nonsense default because otherwise it will fail to instantiate as +// a function parameter type even in cases where we don't expect any caller to +// actually match the overload. +class NonsenseType {}; +template <class T> struct remove_constptr { typedef NonsenseType type; }; +template <class T> struct remove_constptr<const T *> { typedef T *type; }; + +// Template that we use below to remove a template specialization from +// consideration if it matches a specific type. +template <class T, class U> struct disable_if_same { typedef void Type; }; +template <class T> struct disable_if_same<T, T> {}; + +template <class T> void DeletePointer(void *p) { delete static_cast<T *>(p); } + +// Func //////////////////////////////////////////////////////////////////////// + +// Func1, Func2, Func3: Template classes representing a function and its +// signature. +// +// Since the function is a template parameter, calling the function can be +// inlined at compile-time and does not require a function pointer at runtime. +// These functions are not bound to a handler data so have no data or cleanup +// handler. +struct UnboundFunc { + CleanupFunc *GetCleanup() { return NULL; } + void *GetData() { return NULL; } +}; + +template <class R, class P1, R F(P1)> +struct Func1 : public UnboundFunc { + typedef R Return; + static R Call(P1 p1) { return F(p1); } +}; + +template <class R, class P1, class P2, R F(P1, P2)> +struct Func2 : public UnboundFunc { + typedef R Return; + static R Call(P1 p1, P2 p2) { return F(p1, p2); } +}; + +template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +struct Func3 : public UnboundFunc { + typedef R Return; + static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } +}; + +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +struct Func4 : public UnboundFunc { + typedef R Return; + static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } +}; + +// BoundFunc /////////////////////////////////////////////////////////////////// + +// BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that +// shall be bound to the function's second parameter. +// +// Note that the second parameter is a const pointer, but our stored bound value +// is non-const so we can free it when the handlers are destroyed. +template <class T> +struct BoundFunc { + typedef typename remove_constptr<T>::type MutableP2; + explicit BoundFunc(MutableP2 data_) : data(data_) {} + CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; } + MutableP2 GetData() { return data; } + MutableP2 data; +}; + +template <class R, class P1, class P2, R F(P1, P2)> +struct BoundFunc2 : public BoundFunc<P2> { + typedef BoundFunc<P2> Base; + explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} +}; + +template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +struct BoundFunc3 : public BoundFunc<P2> { + typedef BoundFunc<P2> Base; + explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} +}; + +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +struct BoundFunc4 : public BoundFunc<P2> { + typedef BoundFunc<P2> Base; + explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} +}; -// Template magic for creating type-safe wrappers around the user's actual -// function. These convert between the void*'s of the C API and the C++ -// user's types. These also handle conversion between multiple types with -// the same witdh; ie "long long" and "long" are both 64 bits on LP64. +// FuncSig ///////////////////////////////////////////////////////////////////// -// EndMessageHandler -template <class C> struct EndMessageHandlerWrapper2 { - template <bool F(C *, Status *)> - static bool Wrapper(void *closure, const void *hd, Status* s) { - UPB_UNUSED(hd); - return F(static_cast<C *>(closure), s); +// FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function +// *signature*, but without a specific function attached. +// +// These classes contain member functions that can be invoked with a +// specific function to return a Func/BoundFunc class. +template <class R, class P1> +struct FuncSig1 { + template <R F(P1)> + Func1<R, P1, F> GetFunc() { + return Func1<R, P1, F>(); } }; -template <class C, class D> struct EndMessageHandlerWrapper3 { - template <bool F(C *, const D *, Status*)> - inline static bool Wrapper(void *closure, const void *hd, Status* s) { - return F(static_cast<C *>(closure), static_cast<const D *>(hd), s); +template <class R, class P1, class P2> +struct FuncSig2 { + template <R F(P1, P2)> + Func2<R, P1, P2, F> GetFunc() { + return Func2<R, P1, P2, F>(); + } + + template <R F(P1, P2)> + BoundFunc2<R, P1, P2, F> GetFunc(typename remove_constptr<P2>::type param2) { + return BoundFunc2<R, P1, P2, F>(param2); } }; -template <class C> -inline EndMessageHandlerWrapper2<C> MatchWrapper(bool (*f)(C *, Status *)) { - UPB_UNUSED(f); - return EndMessageHandlerWrapper2<C>(); -} +template <class R, class P1, class P2, class P3> +struct FuncSig3 { + template <R F(P1, P2, P3)> + Func3<R, P1, P2, P3, F> GetFunc() { + return Func3<R, P1, P2, P3, F>(); + } + + template <R F(P1, P2, P3)> + BoundFunc3<R, P1, P2, P3, F> GetFunc( + typename remove_constptr<P2>::type param2) { + return BoundFunc3<R, P1, P2, P3, F>(param2); + } +}; -template <class C, class D> -inline EndMessageHandlerWrapper3<C, D> MatchWrapper(bool (*f)(C *, const D *, - Status *)) { - UPB_UNUSED(f); - return EndMessageHandlerWrapper3<C, D>(); +template <class R, class P1, class P2, class P3, class P4> +struct FuncSig4 { + template <R F(P1, P2, P3, P4)> + Func4<R, P1, P2, P3, P4, F> GetFunc() { + return Func4<R, P1, P2, P3, P4, F>(); + } + + template <R F(P1, P2, P3, P4)> + BoundFunc4<R, P1, P2, P3, P4, F> GetFunc( + typename remove_constptr<P2>::type param2) { + return BoundFunc4<R, P1, P2, P3, P4, F>(param2); + } +}; + +// Overloaded template function that can construct the appropriate FuncSig* +// class given a function pointer by deducing the template parameters. +template <class R, class P1> +inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return FuncSig1<R, P1>(); } -inline Handlers::EndMessageHandler MakeHandler(bool (*wrapper)(void *, - const void *, - Status *)) { - return Handlers::EndMessageHandler::Make(wrapper, NULL, NULL); +template <class R, class P1, class P2> +inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return FuncSig2<R, P1, P2>(); } -template <class C, class D> -inline Handlers::EndMessageHandler BindHandler( - bool (*wrapper)(void *, const void *, Status *), - bool (*h)(C *, const D *, Status *), D *data) { - UPB_UNUSED(h); // Only for making sure function matches "D". - return Handlers::EndMessageHandler::Make(wrapper, data, - MatchDeleter(data).Delete); +template <class R, class P1, class P2, class P3> +inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return FuncSig3<R, P1, P2, P3>(); } -// ValueHandler -template <class C, class T1, class T2 = typename CanonicalType<T1>::Type> -struct ValueHandlerWrapper2 { - template <bool F(C *, T1)> - inline static bool Wrapper(void *closure, const void *hd, T2 val) { - UPB_UNUSED(hd); - return F(static_cast<C *>(closure), val); - } -}; +template <class R, class P1, class P2, class P3, class P4> +inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return FuncSig4<R, P1, P2, P3, P4>(); +} -template <class C, class D, class T1, - class T2 = typename CanonicalType<T1>::Type> -struct ValueHandlerWrapper3 { - template <bool F(C *, const D *, T1)> - inline static bool Wrapper(void *closure, const void *hd, T2 val) { - return F(static_cast<C *>(closure), static_cast<const D *>(hd), val); - } -}; +// MethodSig /////////////////////////////////////////////////////////////////// -template <class C, class T> -inline ValueHandlerWrapper2<C, T> MatchWrapper(bool (*f)(C *, T)) { - UPB_UNUSED(f); - return ValueHandlerWrapper2<C, T>(); +// CallMethod*: a function template that calls a given method. +template <class R, class C, R (C::*F)()> +R CallMethod0(C *obj) { + return ((*obj).*F)(); } -template <class C, class D, class T> -inline ValueHandlerWrapper3<C, D, T> MatchWrapper(bool (*f)(C *, const D *, - T)) { - UPB_UNUSED(f); - return ValueHandlerWrapper3<C, D, T>(); +template <class R, class C, class P1, R (C::*F)(P1)> +R CallMethod1(C *obj, P1 arg1) { + return ((*obj).*F)(arg1); } -template <class T> -inline typename Handlers::ValueHandler<T>::H MakeHandler( - bool (*wrapper)(void *, const void *, T)) { - return Handlers::ValueHandler<T>::H::Make(wrapper, NULL, NULL); +template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)> +R CallMethod2(C *obj, P1 arg1, P2 arg2) { + return ((*obj).*F)(arg1, arg2); } -template <class C, class D, class T1, class T2> -inline typename Handlers::ValueHandler<T1>::H BindHandler( - bool (*wrapper)(void *, const void *, T1), bool (*h)(C *, const D *, T2), - D *data) { - UPB_UNUSED(h); // Only for making sure function matches "D". - return Handlers::ValueHandler<T1>::H::Make(wrapper, data, - MatchDeleter(data).Delete); +template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)> +R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { + return ((*obj).*F)(arg1, arg2, arg3); } -// StartFieldHandler -template <class R, class C> struct StartFieldHandlerWrapper2 { - template <R *F(C *)> static void *Wrapper(void *closure, const void *hd) { - UPB_UNUSED(hd); - return F(static_cast<C *>(closure)); +// MethodSig: like FuncSig, but for member functions. +// +// GetFunc() returns a normal FuncN object, so after calling GetFunc() no +// more logic is required to special-case methods. +template <class R, class C> +struct MethodSig0 { + template <R (C::*F)()> + Func1<R, C *, CallMethod0<R, C, F> > GetFunc() { + return Func1<R, C *, CallMethod0<R, C, F> >(); } }; -template <class R, class C, class D> struct StartFieldHandlerWrapper3 { - template <R *F(C *, const D *)> - inline static void *Wrapper(void *closure, const void *hd) { - return F(static_cast<C *>(closure), static_cast<const D *>(hd)); +template <class R, class C, class P1> +struct MethodSig1 { + template <R (C::*F)(P1)> + Func2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc() { + return Func2<R, C *, P1, CallMethod1<R, C, P1, F> >(); + } + + template <R (C::*F)(P1)> + BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc( + typename remove_constptr<P1>::type param1) { + return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> >(param1); + } +}; + +template <class R, class C, class P1, class P2> +struct MethodSig2 { + template <R (C::*F)(P1, P2)> + Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc() { + return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(); + } + + template <R (C::*F)(P1, P2)> + BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc( + typename remove_constptr<P1>::type param1) { + return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(param1); + } +}; + +template <class R, class C, class P1, class P2, class P3> +struct MethodSig3 { + template <R (C::*F)(P1, P2, P3)> + Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc() { + return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >(); + } + + template <R (C::*F)(P1, P2, P3)> + BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc( + typename remove_constptr<P1>::type param1) { + return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >( + param1); } }; template <class R, class C> -inline StartFieldHandlerWrapper2<R, C> MatchWrapper(R *(*f)(C *)) { - UPB_UNUSED(f); - return StartFieldHandlerWrapper2<R, C>(); +inline MethodSig0<R, C> MatchFunc(R (C::*f)()) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return MethodSig0<R, C>(); } -template <class R, class C, class D> -inline StartFieldHandlerWrapper3<R, C, D> MatchWrapper(R *(*f)(C *, - const D *)) { - UPB_UNUSED(f); - return StartFieldHandlerWrapper3<R, C, D>(); +template <class R, class C, class P1> +inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return MethodSig1<R, C, P1>(); } -inline Handlers::StartFieldHandler MakeHandler(void *(*wrapper)(void *, - const void *)) { - return Handlers::StartFieldHandler::Make(wrapper, NULL, NULL); +template <class R, class C, class P1, class P2> +inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return MethodSig2<R, C, P1, P2>(); } -template <class R, class C, class D> -inline Handlers::StartFieldHandler BindHandler( - void *(*wrapper)(void *, const void *), R *(*h)(C *, const D *), D *data) { - UPB_UNUSED(h); // Only for making sure function matches "D". - return Handlers::StartFieldHandler::Make(wrapper, data, - MatchDeleter(data).Delete); +template <class R, class C, class P1, class P2, class P3> +inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return MethodSig3<R, C, P1, P2, P3>(); } -// EndFieldHandler -template <class C> struct EndFieldHandlerWrapper2 { - template <bool F(C *)> - inline static bool Wrapper(void *closure, const void *hd) { - UPB_UNUSED(hd); - return F(static_cast<C *>(closure)); - } -}; +// MaybeWrapReturn ///////////////////////////////////////////////////////////// -template <class C, class D> struct EndFieldHandlerWrapper3 { - template <bool F(C *, const D *)> - inline static bool Wrapper(void *closure, const void *hd) { - return F(static_cast<C *>(closure), static_cast<const D *>(hd)); - } +// Template class that attempts to wrap the return value of the function so it +// matches the expected type. There are two main adjustments it may make: +// +// 1. If the function returns void, make it return the expected type and with +// a value that always indicates success. +// 2. If the function is expected to return void* but doesn't, wrap it so it +// does (either by returning the closure param if the wrapped function +// returns void or by casting a different pointer type to void* for +// return). + +// Template parameters are FuncN type and desired return type. +template <class F, class R, class Enable = void> +struct MaybeWrapReturn; + +// If the return type matches, return the given function unwrapped. +template <class F> +struct MaybeWrapReturn<F, typename F::Return> { + typedef F Func; }; -template <class C> -inline EndFieldHandlerWrapper2<C> MatchWrapper(bool (*f)(C *)) { - UPB_UNUSED(f); - return EndFieldHandlerWrapper2<C>(); +// Function wrapper that munges the return value from void to (bool)true. +template <class P1, class P2, void F(P1, P2)> +bool ReturnTrue2(P1 p1, P2 p2) { + F(p1, p2); + return true; } -template <class C, class D> -inline EndFieldHandlerWrapper3<C, D> MatchWrapper(bool (*f)(C *, const D *)) { - UPB_UNUSED(f); - return EndFieldHandlerWrapper3<C, D>(); +template <class P1, class P2, class P3, void F(P1, P2, P3)> +bool ReturnTrue3(P1 p1, P2 p2, P3 p3) { + F(p1, p2, p3); + return true; } -inline Handlers::EndFieldHandler MakeHandler(bool (*wrapper)(void *, - const void *)) { - return Handlers::EndFieldHandler::Make(wrapper, NULL, NULL); +// Function wrapper that munges the return value from void to (void*)arg1 +template <class P1, class P2, void F(P1, P2)> +void *ReturnClosure2(P1 p1, P2 p2) { + F(p1, p2); + return p1; } -template <class C, class D> -inline Handlers::EndFieldHandler BindHandler( - bool (*wrapper)(void *, const void *), bool (*h)(C *, const D *), D *data) { - UPB_UNUSED(h); // Only for making sure function matches "D". - return Handlers::EndFieldHandler::Make(wrapper, data, - MatchDeleter(data).Delete); +template <class P1, class P2, class P3, void F(P1, P2, P3)> +void *ReturnClosure3(P1 p1, P2 p2, P3 p3) { + F(p1, p2, p3); + return p1; } -// StartStringHandler -template <class R, class C> struct StartStringHandlerWrapper2 { - template <R *F(C *, size_t)> - inline static void *Wrapper(void *closure, const void *hd, size_t hint) { - UPB_UNUSED(hd); - return F(static_cast<C *>(closure), hint); - } +// Function wrapper that munges the return value from R to void*. +template <class R, class P1, class P2, R F(P1, P2)> +void *CastReturnToVoidPtr2(P1 p1, P2 p2) { + return F(p1, p2); +} + +template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { + return F(p1, p2, p3); +} + +// For the string callback, which takes four params, returns the last param +// which is the size of the entire string. +template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)> +size_t ReturnStringLen(P1 p1, P2 p2, P3 p3, size_t p4) { + F(p1, p2, p3, p4); + return p4; +} + +// If we have a function returning void but want a function returning bool, wrap +// it in a function that returns true. +template <class P1, class P2, void F(P1, P2)> +struct MaybeWrapReturn<Func2<void, P1, P2, F>, bool> { + typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F> > Func; }; -template <class R, class C, class D> struct StartStringHandlerWrapper3 { - template <R *F(C *, const D *, size_t)> - inline static void *Wrapper(void *closure, const void *hd, size_t hint) { - return F(static_cast<C *>(closure), static_cast<const D *>(hd), hint); - } +template <class P1, class P2, class P3, void F(P1, P2, P3)> +struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, bool> { + typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F> > Func; }; -template <class R, class C> -inline StartStringHandlerWrapper2<R, C> MatchWrapper(R *(*f)(C *, size_t)) { - UPB_UNUSED(f); - return StartStringHandlerWrapper2<R, C>(); +// If our function returns void but we want one returning void*, wrap it in a +// function that returns the first argument. +template <class P1, class P2, void F(P1, P2)> +struct MaybeWrapReturn<Func2<void, P1, P2, F>, void *> { + typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F> > Func; +}; + +template <class P1, class P2, class P3, void F(P1, P2, P3)> +struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, void *> { + typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F> > Func; +}; + +// If our function returns void but we want one returning size_t, wrap it in a +// function that returns the last argument. +template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)> +struct MaybeWrapReturn<Func4<void, P1, P2, P3, size_t, F>, size_t> { + typedef Func4<size_t, P1, P2, P3, size_t, ReturnStringLen<P1, P2, P3, F> > + Func; +}; + +// If our function returns R* but we want one returning void*, wrap it in a +// function that casts to void*. +template <class R, class P1, class P2, R *F(P1, P2)> +struct MaybeWrapReturn<Func2<R *, P1, P2, F>, void *, + typename disable_if_same<R *, void *>::Type> { + typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F> > Func; +}; + +template <class R, class P1, class P2, class P3, R *F(P1, P2, P3)> +struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F>, void *, + typename disable_if_same<R *, void *>::Type> { + typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F> > + Func; +}; + +// ConvertParams /////////////////////////////////////////////////////////////// + +// Template class that converts the function parameters if necessary, and +// ignores the HandlerData parameter if appropriate. +// +// Template parameter is the are FuncN function type. +template <class F> +struct ConvertParams; + +// Function that discards the handler data parameter. +template <class R, class P1, R F(P1)> +R IgnoreHandlerData2(void *p1, const void *hd) { + UPB_UNUSED(hd); + return F(static_cast<P1>(p1)); } -template <class R, class C, class D> -inline StartStringHandlerWrapper3<R, C, D> MatchWrapper(R *(*f)(C *, const D *, - size_t)) { - UPB_UNUSED(f); - return StartStringHandlerWrapper3<R, C, D>(); +template <class R, class P1, class P2Wrapper, class P2Wrapped, + R F(P1, P2Wrapped)> +R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) { + UPB_UNUSED(hd); + return F(static_cast<P1>(p1), p2); } -inline Handlers::StartStringHandler MakeHandler(void *(*wrapper)(void *, - const void *, - size_t)) { - return Handlers::StartStringHandler::Make(wrapper, NULL, NULL); +template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { + UPB_UNUSED(hd); + return F(static_cast<P1>(p1), p2, p3); } -template <class R, class C, class D> -inline Handlers::StartStringHandler BindHandler( - void *(*wrapper)(void *, const void *, size_t), - R *(*h)(C *, const D *, size_t), D *data) { - UPB_UNUSED(h); // Only for making sure function matches "D". - return Handlers::StartStringHandler::Make(wrapper, data, - MatchDeleter(data).Delete); +// Function that casts the handler data parameter. +template <class R, class P1, class P2, R F(P1, P2)> +R CastHandlerData2(void *c, const void *hd) { + return F(static_cast<P1>(c), static_cast<P2>(hd)); } -// StringHandler -template <class C> struct StringHandlerWrapper2 { - template <size_t F(C *, const char *buf, size_t len)> - inline static size_t Wrapper(void *closure, const void *hd, const char *buf, - size_t len) { - UPB_UNUSED(hd); - return F(static_cast<C *>(closure), buf, len); - } +template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped, + R F(P1, P2, P3Wrapped)> +R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { + return F(static_cast<P1>(c), static_cast<P2>(hd), p3); +} + +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +R CastHandlerData4(void *c, const void *hd, P3 p3, P4 p4) { + return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4); +} + +// For unbound functions, ignore the handler data. +template <class R, class P1, R F(P1)> +struct ConvertParams<Func1<R, P1, F> > { + typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F> > Func; }; -template <class C, class D> struct StringHandlerWrapper3 { - template <size_t F(C *, const D *, const char *buf, size_t len)> - inline static size_t Wrapper(void *closure, const void *hd, const char *buf, - size_t len) { - return F(static_cast<C *>(closure), static_cast<const D *>(hd), buf, len); - } +template <class R, class P1, class P2, R F(P1, P2)> +struct ConvertParams<Func2<R, P1, P2, F> > { + typedef typename CanonicalType<P2>::Type CanonicalP2; + typedef Func3<R, void *, const void *, CanonicalP2, + IgnoreHandlerData3<R, P1, CanonicalP2, P2, F> > Func; }; -template <class C> -inline StringHandlerWrapper2<C> MatchWrapper(size_t (*f)(C *, const char *, - size_t)) { - UPB_UNUSED(f); - return StringHandlerWrapper2<C>(); -} +template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +struct ConvertParams<Func3<R, P1, P2, P3, F> > { + typedef Func4<R, void *, const void *, P2, P3, + IgnoreHandlerData4<R, P1, P2, P3, F> > Func; +}; -template <class C, class D> -inline StringHandlerWrapper3<C, D> MatchWrapper(size_t (*f)(C *, const D *, - const char *, - size_t)) { - UPB_UNUSED(f); - return StringHandlerWrapper3<C, D>(); -} +// For bound functions, cast the handler data. +template <class R, class P1, class P2, R F(P1, P2)> +struct ConvertParams<BoundFunc2<R, P1, P2, F> > { + typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F> > Func; +}; -inline Handlers::StringHandler MakeHandler( - size_t (*wrapper)(void *, const void *, const char *, size_t)) { - return Handlers::StringHandler::Make(wrapper, NULL, NULL); -} +template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +struct ConvertParams<BoundFunc3<R, P1, P2, P3, F> > { + typedef typename CanonicalType<P3>::Type CanonicalP3; + typedef Func3<R, void *, const void *, CanonicalP3, + CastHandlerData3<R, P1, P2, CanonicalP3, P3, F> > Func; +}; -template <class C, class D> -inline Handlers::StringHandler BindHandler( - size_t (*wrapper)(void *, const void *, const char *, size_t), - size_t (*h)(C *, const D *, const char *, size_t), D *data) { - UPB_UNUSED(h); // Only for making sure function matches "D". - return Handlers::StringHandler::Make(wrapper, data, - MatchDeleter(data).Delete); -} +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +struct ConvertParams<BoundFunc4<R, P1, P2, P3, P4, F> > { + typedef Func4<R, void *, const void *, P3, P4, + CastHandlerData4<R, P1, P2, P3, P4, F> > Func; +}; // utype/ltype are upper/lower-case, ctype is canonical C type, vtype is // variant C type. @@ -386,8 +599,7 @@ inline Handlers::StringHandler BindHandler( const Handlers::utype ## Handler& handler) { \ assert(!handler.registered_); \ handler.registered_ = true; \ - return upb_handlers_set##ltype(this, f, handler.handler_, handler.data_, \ - handler.cleanup_); \ + return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \ } \ TYPE_METHODS(Double, double, double, double); @@ -409,6 +621,10 @@ TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T); #endif #undef TYPE_METHODS +template <> struct CanonicalType<Status*> { + typedef Status* Type; +}; + // Type methods that are only one-per-canonical-type and not one-per-cvariant. #define TYPE_METHODS(utype, ctype) \ @@ -426,23 +642,56 @@ TYPE_METHODS(Int32, int32_t); TYPE_METHODS(Bool, bool); #undef TYPE_METHODS -template <class T1, bool F(T1*)> bool Wrapper1(void *p1) { - return F(static_cast<T1*>(p1)); +template <class F> struct ReturnOf; + +template <class R, class P1, class P2> +struct ReturnOf<R (*)(P1, P2)> { + typedef R Return; +}; + +template <class R, class P1, class P2, class P3> +struct ReturnOf<R (*)(P1, P2, P3)> { + typedef R Return; +}; + +template <class R, class P1, class P2, class P3, class P4> +struct ReturnOf<R (*)(P1, P2, P3, P4)> { + typedef R Return; +}; + +template <class T> +template <class F> +inline Handler<T>::Handler(F func) + : registered_(false) { + upb_handlerattr_sethandlerdata(&attr_, func.GetData(), func.GetCleanup()); + typedef typename ReturnOf<T>::Return Return; + typedef typename ConvertParams<F>::Func ConvertedParamsFunc; + typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func + ReturnWrappedFunc; + handler_ = ReturnWrappedFunc().Call; } -template <class T1, bool F(T1 *, upb::Status *)> -bool EndMessageWrapper(void *p1, upb::Status *s) { - return F(static_cast<T1 *>(p1), s); + +template <class T> +inline Handler<T>::~Handler() { + assert(registered_); } -inline Handlers *Handlers::New(const MessageDef *m, const FrameType *ft, - const void *owner) { - return upb_handlers_new(m, ft, owner); + +inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); } +inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); } +inline bool HandlerAttributes::SetHandlerData(void *hd, + upb_handlerfree *cleanup) { + return upb_handlerattr_sethandlerdata(this, hd, cleanup); } -inline const Handlers *Handlers::NewFrozen(const MessageDef *m, - const FrameType *ft, - const void *owner, - upb_handlers_callback *callback, - void *closure) { - return upb_handlers_newfrozen(m, ft, owner, callback, closure); + +inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) { + upb_handlers *h = upb_handlers_new(m, &h); + return reffed_ptr<Handlers>(h, &h); +} +inline reffed_ptr<const Handlers> Handlers::NewFrozen( + const MessageDef *m, upb_handlers_callback *callback, + void *closure) { + const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure); + return reffed_ptr<const Handlers>(h, &h); } inline bool Handlers::IsFrozen() const { return upb_handlers_isfrozen(this); } inline void Handlers::Ref(const void *owner) const { @@ -463,11 +712,15 @@ inline const Status* Handlers::status() { inline void Handlers::ClearError() { return upb_handlers_clearerr(this); } +inline bool Handlers::Freeze(Status *s) { + upb::Handlers* h = this; + return upb_handlers_freeze(&h, 1, s); +} inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) { return upb_handlers_freeze(handlers, n, s); } -inline const FrameType *Handlers::frame_type() const { - return upb_handlers_frametype(this); +inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) { + return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status); } inline const MessageDef *Handlers::message_def() const { return upb_handlers_msgdef(this); @@ -476,64 +729,55 @@ inline bool Handlers::SetStartMessageHandler( const Handlers::StartMessageHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setstartmsg(this, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndMessageHandler( const Handlers::EndMessageHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setendmsg(this, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_); } inline bool Handlers::SetStartStringHandler(const FieldDef *f, const StartStringHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setstartstr(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndStringHandler(const FieldDef *f, const EndFieldHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setendstr(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetStringHandler(const FieldDef *f, const StringHandler& handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setstring(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetStartSequenceHandler( const FieldDef *f, const StartFieldHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setstartseq(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetStartSubMessageHandler( const FieldDef *f, const StartFieldHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setstartsubmsg(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setendsubmsg(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndSequenceHandler(const FieldDef *f, const EndFieldHandler &handler) { assert(!handler.registered_); handler.registered_ = true; - return upb_handlers_setendseq(this, f, handler.handler_, handler.data_, - handler.cleanup_); + return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) { return upb_handlers_setsubhandlers(this, f, sub); diff --git a/upb/handlers.c b/upb/handlers.c index 169dbe0..baa3e06 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -19,22 +19,16 @@ // UPB_NO_CLOSURE. char _upb_noclosure; -typedef struct { - void (*func)(); - void *data; -} tabent; - static void freehandlers(upb_refcounted *r) { upb_handlers *h = (upb_handlers*)r; - upb_msgdef_unref(h->msg, h); - for (size_t i = 0; i < h->cleanup_len; i++) { - h->cleanup[i].cleanup(h->cleanup[i].ptr); - } - if (h->status_) { - upb_status_uninit(h->status_); - free(h->status_); + for (int i = 0; i < h->msg->selector_count; i++) { + upb_handlerfree *cleanup = h->table[i].attr.cleanup; + if (cleanup) { + cleanup(h->table[i].attr.handler_data_); + } } - free(h->cleanup); + upb_msgdef_unref(h->msg, h); + free(h->sub); free(h); } @@ -58,10 +52,9 @@ typedef struct { void *closure; } dfs_state; -static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft, - const void *owner, +static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, dfs_state *s) { - upb_handlers *h = upb_handlers_new(m, ft, owner); + upb_handlers *h = upb_handlers_new(m, owner); if (!h) return NULL; if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; @@ -79,7 +72,7 @@ static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft, if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) { upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent)); } else { - upb_handlers *sub_mh = newformsg(subdef, ft, &sub_mh, s); + upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); if (!sub_mh) goto oom; upb_handlers_setsubhandlers(h, f, sub_mh); upb_handlers_unref(sub_mh, &sub_mh); @@ -92,10 +85,12 @@ oom: return NULL; } -// This wastes a bit of space since the "func" member of this slot is unused, -// but the code is simpler. Worst-case overhead is 20% (messages with only -// non-repeated submessage fields). Can change later if necessary. -#define SUBH(h, field_base) h->table[field_base + 2].data +// Given a selector for a STARTSUBMSG handler, resolves to a pointer to the +// subhandlers for this submessage field. +#define SUBH(h, selector) (h->sub[selector]) + +// The selector for a submessage field is the field index. +#define SUBH_F(h, f) SUBH(h, f->index_) static int32_t getsel(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { @@ -103,13 +98,13 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, assert(!upb_handlers_isfrozen(h)); if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { upb_status_seterrf( - h->status_, "type mismatch: field %s does not belong to message %s", + &h->status_, "type mismatch: field %s does not belong to message %s", upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h))); return -1; } if (!upb_handlers_getselector(f, type, &sel)) { upb_status_seterrf( - h->status_, + &h->status_, "type mismatch: cannot register handler type %d for field %s", type, upb_fielddef_name(f)); return -1; @@ -117,35 +112,29 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, return sel; } -static bool addcleanup(upb_handlers *h, void *ptr, void (*cleanup)(void*)) { - if (h->cleanup_len == h->cleanup_size) { - h->cleanup_size = UPB_MAX(4, h->cleanup_size * 2); - void *resized = realloc(h->cleanup, sizeof(*h->cleanup) * h->cleanup_size); - if (!resized) { - h->cleanup_size = h->cleanup_len; - cleanup(ptr); - upb_status_seterrliteral(h->status_, "out of memory"); - return false; - } - h->cleanup = resized; +static bool doset(upb_handlers *h, int32_t sel, upb_func *func, + upb_handlerattr *attr) { + assert(!upb_handlers_isfrozen(h)); + + if (sel < 0) { + upb_status_seterrmsg(&h->status_, + "incorrect handler type for this field."); + return false; } - h->cleanup[h->cleanup_len].ptr = ptr; - h->cleanup[h->cleanup_len].cleanup = cleanup; - h->cleanup_len++; - return true; -} -static bool doset(upb_handlers *h, upb_selector_t sel, upb_func *func, - void *data, upb_handlerfree *cleanup) { - assert(!upb_handlers_isfrozen(h)); if (h->table[sel].func) { - upb_status_seterrliteral(h->status_, - "cannot change handler once it has been set."); + upb_status_seterrmsg(&h->status_, + "cannot change handler once it has been set."); return false; } - if (cleanup && !addcleanup(h, data, cleanup)) return false; + + upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER; + if (attr) { + set_attr = *attr; + } + h->table[sel].func = (upb_func*)func; - h->table[sel].data = data; + h->table[sel].attr = set_attr; return true; } @@ -173,25 +162,18 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner) { upb_refcounted_checkref(UPB_UPCAST(h), owner); } - -upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft, - const void *owner) { +upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { assert(upb_msgdef_isfrozen(md)); - int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1 + 100); + int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1); upb_handlers *h = calloc(sizeof(*h) + extra, 1); if (!h) return NULL; - h->status_ = malloc(sizeof(*h->status_)); - if (!h->status_) goto oom; - upb_status_init(h->status_); - h->msg = md; - h->ft = ft; - h->cleanup = NULL; - h->cleanup_size = 0; - h->cleanup_len = 0; upb_msgdef_ref(h->msg, h); + upb_status_clear(&h->status_); + h->sub = calloc(md->submsg_field_count, sizeof(*h->sub)); + if (!h->sub) goto oom; if (!upb_refcounted_init(UPB_UPCAST(h), &vtbl, owner)) goto oom; // calloc() above initialized all handlers to NULL. @@ -203,7 +185,6 @@ oom: } const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, - const upb_frametype *ft, const void *owner, upb_handlers_callback *callback, void *closure) { @@ -212,7 +193,7 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, state.closure = closure; if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL; - upb_handlers *ret = newformsg(m, ft, owner, &state); + upb_handlers *ret = newformsg(m, owner, &state); upb_inttable_uninit(&state.tab); if (!ret) return NULL; @@ -226,48 +207,47 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const upb_status *upb_handlers_status(upb_handlers *h) { assert(!upb_handlers_isfrozen(h)); - return h->status_; + return &h->status_; } void upb_handlers_clearerr(upb_handlers *h) { assert(!upb_handlers_isfrozen(h)); - upb_status_clear(h->status_); + upb_status_clear(&h->status_); } #define SETTER(name, handlerctype, handlertype) \ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ - handlerctype func, void *data, \ - upb_handlerfree *cleanup) { \ + handlerctype func, upb_handlerattr *attr) { \ int32_t sel = getsel(h, f, handlertype); \ - return sel >= 0 && doset(h, sel, (upb_func*)func, data, cleanup); \ + return doset(h, sel, (upb_func*)func, attr); \ } -SETTER(int32, upb_int32_handler*, UPB_HANDLER_INT32); -SETTER(int64, upb_int64_handler*, UPB_HANDLER_INT64); -SETTER(uint32, upb_uint32_handler*, UPB_HANDLER_UINT32); -SETTER(uint64, upb_uint64_handler*, UPB_HANDLER_UINT64); -SETTER(float, upb_float_handler*, UPB_HANDLER_FLOAT); -SETTER(double, upb_double_handler*, UPB_HANDLER_DOUBLE); -SETTER(bool, upb_bool_handler*, UPB_HANDLER_BOOL); -SETTER(startstr, upb_startstr_handler*, UPB_HANDLER_STARTSTR); -SETTER(string, upb_string_handler*, UPB_HANDLER_STRING); -SETTER(endstr, upb_endfield_handler*, UPB_HANDLER_ENDSTR); -SETTER(startseq, upb_startfield_handler*, UPB_HANDLER_STARTSEQ); -SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG); -SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG); -SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ); +SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32); +SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64); +SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32); +SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64); +SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT); +SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE); +SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL); +SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR); +SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING); +SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR); +SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ); +SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG); +SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG); +SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ); #undef SETTER -bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler, - void *d, upb_handlerfree *cleanup) { - return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)handler, d, cleanup); +bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, + upb_handlerattr *attr) { + return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)func, attr); } -bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler, - void *d, upb_handlerfree *cleanup) { +bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, + upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); - return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)handler, d, cleanup); + return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)func, attr); } bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, @@ -275,11 +255,11 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, assert(sub); assert(!upb_handlers_isfrozen(h)); assert(upb_fielddef_issubmsg(f)); - if (SUBH(h, f->selector_base)) return false; // Can't reset. + if (SUBH_F(h, f)) return false; // Can't reset. if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { return false; } - SUBH(h, f->selector_base) = sub; + SUBH_F(h, f) = sub; upb_ref2(sub, h); return true; } @@ -287,39 +267,27 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, const upb_fielddef *f) { assert(upb_fielddef_issubmsg(f)); - return SUBH(h, f->selector_base); + return SUBH_F(h, f); } const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel) { // STARTSUBMSG selector in sel is the field's selector base. - return SUBH(h, sel); + return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT); } const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } -const upb_frametype *upb_handlers_frametype(const upb_handlers *h) { - return h->ft; -} - -upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) { - return (upb_func *)h->table[s].func; -} - -const void *upb_handlers_gethandlerdata(const upb_handlers *h, - upb_selector_t s) { - return h->table[s].data; -} /* "Static" methods ***********************************************************/ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { // TODO: verify we have a transitive closure. for (int i = 0; i < n; i++) { - if (!upb_ok(handlers[i]->status_)) { + if (!upb_ok(&handlers[i]->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", upb_msgdef_fullname(upb_handlers_msgdef(handlers[i])), - upb_status_getstr(handlers[i]->status_)); + upb_status_errmsg(&handlers[i]->status_)); return false; } } @@ -329,11 +297,6 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { return false; } - for (int i = 0; i < n; i++) { - upb_status_uninit(handlers[i]->status_); - free(handlers[i]->status_); - handlers[i]->status_ = NULL; - } return true; } @@ -388,11 +351,15 @@ bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, break; case UPB_HANDLER_STARTSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; - *s = f->selector_base; + // Selectors for STARTSUBMSG are at the beginning of the table so that the + // selector can also be used as an index into the "sub" array of + // subhandlers. The indexes for the two into these two tables are the + // same, except that in the handler table the static selectors come first. + *s = f->index_ + UPB_STATIC_SELECTOR_COUNT; break; case UPB_HANDLER_ENDSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; - *s = f->selector_base + 1; + *s = f->selector_base; break; // Subhandler slot is selector_base + 2. } @@ -408,6 +375,61 @@ uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { uint32_t ret = 1; if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ if (upb_fielddef_isstring(f)) ret += 2; // [STARTSTR]/STRING/ENDSTR - if (upb_fielddef_issubmsg(f)) ret += 2; // [STARTSUBMSG]/ENDSUBMSG/SUBH + // ENDSUBMSG (STARTSUBMSG is at table beginning) + if (upb_fielddef_issubmsg(f)) ret += 0; return ret; } + + +/* upb_handlerattr ************************************************************/ + +void upb_handlerattr_init(upb_handlerattr *attr) { + upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER; + memcpy(attr, &from, sizeof(*attr)); +} + +void upb_handlerattr_uninit(upb_handlerattr *attr) { + UPB_UNUSED(attr); +} + +bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, + upb_handlerfree *cleanup) { + if (attr->handler_data_) + return false; + attr->handler_data_ = hd; + attr->cleanup = cleanup; + return true; +} + + +/* upb_byteshandler ***********************************************************/ + +void upb_byteshandler_init(upb_byteshandler* h) { + memset(h, 0, sizeof(*h)); +} + +// For when we support handlerfree callbacks. +void upb_byteshandler_uninit(upb_byteshandler* h) { + UPB_UNUSED(h); +} + +bool upb_byteshandler_setstartstr(upb_byteshandler *h, + upb_startstr_handlerfunc *func, void *d) { + h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func; + h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d; + return true; +} + +bool upb_byteshandler_setstring(upb_byteshandler *h, + upb_string_handlerfunc *func, void *d) { + h->table[UPB_STRING_SELECTOR].func = (upb_func*)func; + h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d; + return true; +} + +bool upb_byteshandler_setendstr(upb_byteshandler *h, + upb_endfield_handlerfunc *func, void *d) { + h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func; + h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d; + return true; +} diff --git a/upb/handlers.h b/upb/handlers.h index bb9c3b6..ceb559f 100644 --- a/upb/handlers.h +++ b/upb/handlers.h @@ -25,22 +25,21 @@ #include "upb/def.h" #ifdef __cplusplus -struct upb_frametype; namespace upb { -typedef upb_frametype FrameType; +class HandlerAttributes; class Handlers; template <class T> class Handler; template <class T> struct CanonicalType; } // namespace upb -typedef upb::FrameType upb_frametype; +typedef upb::HandlerAttributes upb_handlerattr; typedef upb::Handlers upb_handlers; #else -struct upb_frametype; +struct upb_handlerattr; struct upb_handlers; struct upb_sinkframe; -typedef struct upb_frametype upb_frametype; +typedef struct upb_handlerattr upb_handlerattr; typedef struct upb_handlers upb_handlers; typedef struct upb_sinkframe upb_sinkframe; #endif @@ -54,11 +53,6 @@ typedef struct upb_sinkframe upb_sinkframe; // of Handlers::Freeze that allows specifying this as a parameter. #define UPB_MAX_HANDLER_DEPTH 64 -typedef struct { - void (*func)(); - const void *data; -} upb_handlers_tabent; - // All the different types of handlers that can be registered. // Only needed for the advanced functions in upb::Handlers. typedef enum { @@ -89,12 +83,67 @@ extern char _upb_noclosure; // A selector refers to a specific field handler in the Handlers object // (for example: the STARTSUBMSG handler for field "field15"). typedef int32_t upb_selector_t; +typedef void upb_func(); + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, + upb_selector_t s); +UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr); +UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, + upb_selector_t s); + +#ifdef __cplusplus +} +#endif -// Message-level callbacks have static selectors. + +// Static selectors for upb::Handlers. #define UPB_STARTMSG_SELECTOR 0 #define UPB_ENDMSG_SELECTOR 1 #define UPB_STATIC_SELECTOR_COUNT 2 +// Static selectors for upb::BytesHandler. +#define UPB_STARTSTR_SELECTOR 0 +#define UPB_STRING_SELECTOR 1 +#define UPB_ENDSTR_SELECTOR 2 + +typedef void upb_handlerfree(void *d); + +#ifdef __cplusplus + +class upb::HandlerAttributes { + public: + HandlerAttributes(); + ~HandlerAttributes(); + + // Sets the handler data that will be passed as the second parameter of the + // handler. + // + // Warning: if you use these attributes for multiple handlers, the + // cleanup handler will be called once for each handler it was successfully + // set on. + bool SetHandlerData(void *handler_data, upb_handlerfree *cleanup); + void *handler_data() const; + + private: + friend UPB_INLINE const void * ::upb_handlerattr_handlerdata( + const upb_handlerattr *attr); + +#else +struct upb_handlerattr { +#endif + void *handler_data_; + upb_handlerfree *cleanup; +}; + +typedef struct { + upb_func *func; + upb_handlerattr attr; +} upb_handlers_tabent; + #ifdef __cplusplus // A upb::Handlers object represents the set of handlers associated with a @@ -139,24 +188,18 @@ class upb::Handlers { typedef void HandlersCallback(void *closure, upb_handlers *h); - // Returns a new handlers object for the given frozen msgdef that will use - // the given FrameType as its top-level state (can be NULL, for now). A - // single ref on the returned object will belong to the given owner. + // Returns a new handlers object for the given frozen msgdef. // Returns NULL if memory allocation failed. - static Handlers* New(const MessageDef* m, - const FrameType* ft, - const void *owner); + static reffed_ptr<Handlers> New(const MessageDef *m); // Convenience function for registering a graph of handlers that mirrors the // graph of msgdefs for some message. For "m" and all its children a new set // of handlers will be created and the given callback will be invoked, // allowing the client to register handlers for this message. Note that any - // subhandlers set by the callback will be overwritten. A single ref on the - // returned object will belong to the given owner. - static const Handlers* NewFrozen(const MessageDef *m, - const FrameType* ft, - const void *owner, - HandlersCallback *callback, void *closure); + // subhandlers set by the callback will be overwritten. + static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m, + HandlersCallback *callback, + void *closure); // Functionality from upb::RefCounted. bool IsFrozen() const; @@ -173,14 +216,15 @@ class upb::Handlers { const Status* status(); void ClearError(); - // Top-level frame type. - const FrameType* frame_type() const; + // Call to freeze these Handlers. Requires that any SubHandlers are already + // frozen. For cycles, you must use the static version below and freeze the + // whole graph at once. + bool Freeze(Status* s); // Freezes the given set of handlers. You may not freeze a handler without - // also freezing any handlers they point to. In the future we may want to - // require that all fields of the submessage have had subhandlers set for - // them. + // also freezing any handlers they point to. static bool Freeze(Handlers*const* handlers, int n, Status* s); + static bool Freeze(const vector<Handlers*>& handlers, Status* s); // Returns the msgdef associated with this handlers object. const MessageDef* message_def() const; @@ -367,23 +411,24 @@ class upb::Handlers { // static bool IsSequence(Selector selector); private: - UPB_DISALLOW_POD_OPS(Handlers); + UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers); + + friend UPB_INLINE GenericFunction *::upb_handlers_gethandler( + const upb_handlers *h, upb_selector_t s); + friend UPB_INLINE const void *::upb_handlers_gethandlerdata( + const upb_handlers *h, upb_selector_t s); #else struct upb_handlers { #endif upb_refcounted base; const upb_msgdef *msg; - const upb_frametype *ft; - upb_status *status_; // Used only when mutable. - struct { - void *ptr; - void (*cleanup)(void*); - } *cleanup; - size_t cleanup_len, cleanup_size; + const upb_handlers **sub; + upb_status status_; // Used only when mutable. upb_handlers_tabent table[1]; // Dynamically-sized field handler array. }; + #ifdef __cplusplus namespace upb { @@ -393,55 +438,63 @@ namespace upb { // of the underlying C API into nice C++ function. // // Sample usage: -// bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) { +// void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) { // // do stuff ... -// return true; // } // // // Handler that doesn't need any data bound to it. -// bool OnValue(MyClosure* c, int32_t val) { +// void OnValue2(MyClosure* c, int32_t val) { +// // do stuff ... +// } +// +// // Handler that returns bool so it can return failure if necessary. +// bool OnValue3(MyClosure* c, int32_t val) { // // do stuff ... -// return true; +// return ok; // } // +// // Member function handler. +// class MyClosure { +// public: +// void OnValue(int32_t val) { +// // do stuff ... +// } +// }; +// // // Takes ownership of the MyHandlerData. -// handlers->SetInt32Handler(f1, UpbBind(OnValue, new MyHandlerData(...))); -// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue)); +// handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...))); +// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2)); +// handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3)); +// handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue)); #ifdef UPB_CXX11 // In C++11, the "template" disambiguator can appear even outside templates, // so all calls can safely use this pair of macros. -#define UpbMakeHandler(f) \ - upb::MakeHandler(upb::MatchWrapper(f).template Wrapper<f>) +#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>() // We have to be careful to only evaluate "d" once. -#define UpbBind(f, d) \ - upb::BindHandler(upb::MatchWrapper(f).template Wrapper<f>, f, (d)) +#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d)) #else // Prior to C++11, the "template" disambiguator may only appear inside a // template, so the regular macro must not use "template" -#define UpbMakeHandler(f) \ - upb::MakeHandler(upb::MatchWrapper(f).Wrapper<f>) +#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>() -#define UpbBind(f, d) \ - upb::BindHandler(upb::MatchWrapper(f).Wrapper<f>, f, (d)) +#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d)) #endif // UPB_CXX11 // This macro must be used in C++98 for calls from inside a template. But we // define this variant in all cases; code that wants to be compatible with both // C++98 and C++11 should always use this macro when calling from a template. -#define UpbMakeHandlerT(f) \ - upb::MakeHandler(upb::MatchWrapper(f).template Wrapper<f>) - -#define UpbBindT(f, d) \ - upb::BindHandler(upb::MatchWrapper(f).template Wrapper<f>, f, (d)) +#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>() +// We have to be careful to only evaluate "d" once. +#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d)) // Handler: a struct that contains the (handler, data, deleter) tuple that is // used to register all handlers. Users can Make() these directly but it's @@ -451,96 +504,16 @@ template <class T> class Handler { // The underlying, handler function signature that upb uses internally. typedef T FuncPtr; - // Creates a Handler object with the given function, data, and cleanup func. - // - // This is like a constructor but we don't want to expose the actual - // constructor publicly because letting users construct them leads to hairy - // ownership issues: - // - // Int32Handler handler(MyFunc, new MyData, MyCleanup); - // - // // What should happen to ownership of MyData? - // handlers->SetInt32Handler(f, handler); - // handlers2->SetInt32Handler(f, handler); - // - // To avoid this ownership question we prevent the Handler objects from - // being constructed, copied, or assigned. They are only available as the - // return value of this Make() function, and they must be registered exactly - // once before the temporary object is destroyed. This allows the Handler - // object to be the *unique* owner of the passed-in data. - static Handler<T> Make(FuncPtr h, void* hd, void (*fr)(void*)) { - return Handler<T>(h, hd, fr); - } - - ~Handler() { assert(registered_); } + // Intentionally implicit. + template <class F> Handler(F func); + ~Handler(); private: + UPB_DISALLOW_COPY_AND_ASSIGN(Handler); friend class Handlers; - - Handler(FuncPtr h, void *d, void (*c)(void *)) - : handler_(h), data_(d), cleanup_(c), registered_(false) {} - void operator=(const Handler&); -#ifdef UPB_CXX11 - // C++98 doesn't support binding a const ref to a temporary, at least - // according to Clang. It is still intended that users NOT create instances - // of this object via this copy constructor, and any attempts to register - // such an object more than once will assert-fail. - Handler(const Handler&); -#endif - FuncPtr handler_; - void *data_; - void (*cleanup_)(void*); + mutable HandlerAttributes attr_; mutable bool registered_; - - // Noisy friend declarations; these are all of the "Bind" functions, - // two for each type of handler. They need to be friends so that - // they can call the copy constructor to return a temporary. - - friend Handlers::EndMessageHandler MakeHandler( - bool (*wrapper)(void *, const void *, Status *)); - - template <class T1> - friend typename Handlers::ValueHandler<T1>::H MakeHandler( - bool (*wrapper)(void *, const void *, T1)); - - template <class C, class D, class T1, class T2> - friend typename Handlers::ValueHandler<T1>::H BindHandler( - bool (*wrapper)(void *, const void *, T1), bool (*h)(C *, const D *, T2), - D *data); - - friend Handlers::StartFieldHandler MakeHandler( - void *(*wrapper)(void *, const void *)); - - template <class R, class C, class D> - friend Handlers::StartFieldHandler BindHandler( - void *(*wrapper)(void *, const void *), R *(*h)(C *, const D *), D *data); - - friend Handlers::EndFieldHandler MakeHandler(bool (*wrapper)(void *, - const void *)); - - template <class C, class D> - friend Handlers::EndFieldHandler BindHandler(bool (*wrapper)(void *, - const void *), - bool (*h)(C *, const D *), - D *data); - - friend Handlers::StringHandler MakeHandler( - size_t (*wrapper)(void *, const void *, const char *, size_t)); - - template <class C, class D> - friend Handlers::StringHandler BindHandler( - size_t (*wrapper)(void *, const void *, const char *, size_t), - size_t (*h)(C *, const D *, const char *, size_t), D *data); - - friend Handlers::StartStringHandler MakeHandler(void *(*wrapper)(void *, - const void *, - size_t)); - - template <class R, class C, class D> - friend Handlers::StartStringHandler BindHandler( - void *(*wrapper)(void *, const void *, size_t), - R *(*h)(C *, const D *, size_t), D *data); }; } // namespace upb @@ -549,30 +522,42 @@ extern "C" { #endif // __cplusplus // Native C API. -typedef void upb_handlers_callback(void *closure, upb_handlers *h); -typedef void upb_handlerfree(void *d); -typedef void upb_func(); -typedef bool upb_startmsg_handler(void *c, const void*); -typedef bool upb_endmsg_handler(void *c, const void *, upb_status *status); -typedef void* upb_startfield_handler(void *c, const void *hd); -typedef bool upb_endfield_handler(void *c, const void *hd); -typedef bool upb_int32_handler(void *c, const void *hd, int32_t val); -typedef bool upb_int64_handler(void *c, const void *hd, int64_t val); -typedef bool upb_uint32_handler(void *c, const void *hd, uint32_t val); -typedef bool upb_uint64_handler(void *c, const void *hd, uint64_t val); -typedef bool upb_float_handler(void *c, const void *hd, float val); -typedef bool upb_double_handler(void *c, const void *hd, double val); -typedef bool upb_bool_handler(void *c, const void *hd, bool val); -typedef void* upb_startstr_handler(void *c, const void *hd, size_t size_hint); -typedef size_t upb_string_handler(void *c, const void *hd, const char *buf, - size_t n); +// Handler function typedefs. +typedef bool upb_startmsg_handlerfunc(void *c, const void*); +typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status); +typedef void* upb_startfield_handlerfunc(void *c, const void *hd); +typedef bool upb_endfield_handlerfunc(void *c, const void *hd); +typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val); +typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val); +typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val); +typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val); +typedef bool upb_float_handlerfunc(void *c, const void *hd, float val); +typedef bool upb_double_handlerfunc(void *c, const void *hd, double val); +typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val); +typedef void *upb_startstr_handlerfunc(void *c, const void *hd, + size_t size_hint); +typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf, + size_t n); +// upb_handlerattr +#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL} + +void upb_handlerattr_init(upb_handlerattr *attr); +void upb_handlerattr_uninit(upb_handlerattr *attr); + +bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, + upb_handlerfree *cleanup); +UPB_INLINE const void *upb_handlerattr_handlerdata( + const upb_handlerattr *attr) { + return attr->handler_data_; +} + +typedef void upb_handlers_callback(void *closure, upb_handlers *h); +// upb_handlers upb_handlers *upb_handlers_new(const upb_msgdef *m, - const upb_frametype *ft, const void *owner); const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, - const upb_frametype *ft, const void *owner, upb_handlers_callback *callback, void *closure); @@ -588,62 +573,95 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner); const upb_status *upb_handlers_status(upb_handlers *h); void upb_handlers_clearerr(upb_handlers *h); const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h); -const upb_frametype *upb_handlers_frametype(const upb_handlers *h); -bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler, - void *d, upb_handlerfree *fr); -bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler, - void *d, upb_handlerfree *fr); + +bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f, - upb_int32_handler *handler, void *d, - upb_handlerfree *fr); + upb_int32_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f, - upb_int64_handler *handler, void *d, - upb_handlerfree *fr); + upb_int64_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f, - upb_uint32_handler *handler, void *d, - upb_handlerfree *fr); + upb_uint32_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f, - upb_uint64_handler *handler, void *d, - upb_handlerfree *fr); + upb_uint64_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f, - upb_float_handler *handler, void *d, - upb_handlerfree *fr); + upb_float_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f, - upb_double_handler *handler, void *d, - upb_handlerfree *fr); + upb_double_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f, - upb_bool_handler *handler, void *d, - upb_handlerfree *fr); + upb_bool_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f, - upb_startstr_handler *handler, void *d, - upb_handlerfree *fr); + upb_startstr_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f, - upb_string_handler *handler, void *d, - upb_handlerfree *fr); + upb_string_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f, - upb_endfield_handler *handler, void *d, - upb_handlerfree *fr); + upb_endfield_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f, - upb_startfield_handler *handler, void *d, - upb_handlerfree *fr); + upb_startfield_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f, - upb_startfield_handler *handler, void *d, - upb_handlerfree *fr); + upb_startfield_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f, - upb_endfield_handler *handler, void *d, - upb_handlerfree *fr); + upb_endfield_handlerfunc *func, + upb_handlerattr *attr); bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f, - upb_endfield_handler *handler, void *d, - upb_handlerfree *fr); + upb_endfield_handlerfunc *func, + upb_handlerattr *attr); + bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, const upb_handlers *sub); const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, const upb_fielddef *f); const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel); -upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s); -const void *upb_handlers_gethandlerdata(const upb_handlers *h, - upb_selector_t s); + +UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, + upb_selector_t s) { + return (upb_func *)h->table[s].func; +} + +UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, + upb_selector_t s) { + return upb_handlerattr_handlerdata(&h->table[s].attr); +} + +// Handler types for single fields. +// Right now we only have one for TYPE_BYTES but ones for other types +// should follow. +// +// These follow the same handlers protocol for fields of a message. +typedef struct { upb_handlers_tabent table[3]; } upb_byteshandler; + +void upb_byteshandler_init(upb_byteshandler *h); +void upb_byteshandler_uninit(upb_byteshandler *h); + +// Caller must ensure that "d" outlives the handlers. +// TODO(haberman): support handlerfree function for the data. +// TODO(haberman): should this have a "freeze" operation? It's not necessary +// for memory management, but could be useful to force immutability and provide +// a convenient moment to verify that all registration succeeded. +bool upb_byteshandler_setstartstr(upb_byteshandler *h, + upb_startstr_handlerfunc *func, void *d); +bool upb_byteshandler_setstring(upb_byteshandler *h, + upb_string_handlerfunc *func, void *d); +bool upb_byteshandler_setendstr(upb_byteshandler *h, + upb_endfield_handlerfunc *func, void *d); + +#ifdef __cplusplus +namespace upb { +typedef upb_byteshandler BytesHandler; +} +#endif // "Static" methods bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s); diff --git a/upb/pb/compile_decoder.c b/upb/pb/compile_decoder.c index 200eef5..f96f07a 100644 --- a/upb/pb/compile_decoder.c +++ b/upb/pb/compile_decoder.c @@ -11,7 +11,6 @@ #include <stdarg.h> #include "upb/pb/decoder.int.h" #include "upb/pb/varint.int.h" -#include "upb/bytestream.h" #ifdef UPB_DUMP_BYTECODE #include <stdio.h> @@ -20,76 +19,140 @@ #define MAXLABEL 5 #define EMPTYLABEL -1 +static const void *methodkey(const upb_msgdef *md, const upb_handlers *h) { + const void *ret = h ? (const void*)h : (const void*)md; + assert(ret); + return ret; +} + + +/* mgroup *********************************************************************/ + +static void freegroup(upb_refcounted *r) { + mgroup *g = (mgroup*)r; + upb_inttable_uninit(&g->methods); +#ifdef UPB_USE_JIT_X64 + upb_pbdecoder_freejit(g); +#endif + free(g->bytecode); + free(g); +} + +static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const mgroup *g = (const mgroup*)r; + upb_inttable_iter i; + upb_inttable_begin(&i, &g->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + visit(r, UPB_UPCAST(method), closure); + } +} + +mgroup *newgroup(const void *owner) { + mgroup *g = malloc(sizeof(*g)); + static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup}; + upb_refcounted_init(UPB_UPCAST(g), &vtbl, owner); + upb_inttable_init(&g->methods, UPB_CTYPE_PTR); + g->bytecode = NULL; + g->bytecode_end = NULL; + return g; +} + + /* upb_pbdecodermethod ********************************************************/ +static void freemethod(upb_refcounted *r) { + upb_pbdecodermethod *method = (upb_pbdecodermethod*)r; + upb_byteshandler_uninit(&method->input_handler_); + + if (method->dest_handlers_) { + upb_handlers_unref(method->dest_handlers_, method); + } + + upb_inttable_uninit(&method->dispatch); + free(method); +} + +static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r; + visit(r, m->group, closure); +} + static upb_pbdecodermethod *newmethod(const upb_msgdef *msg, - const upb_handlers *dest_handlers) { - upb_pbdecodermethod *ret = malloc(sizeof(upb_pbdecodermethod)); - ret->msg = msg; - ret->dest_handlers = dest_handlers; - ret->native_code = false; // If we JIT, it will update this later. + const upb_handlers *dest_handlers, + mgroup *group, + const void *key) { + static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod}; + upb_pbdecodermethod *ret = malloc(sizeof(*ret)); + upb_refcounted_init(UPB_UPCAST(ret), &vtbl, &ret); + upb_byteshandler_init(&ret->input_handler_); + + // The method references the group and vice-versa, in a circular reference. + upb_ref2(ret, group); + upb_ref2(group, ret); + upb_inttable_insertptr(&group->methods, key, upb_value_ptr(ret)); // Owns ref + upb_refcounted_unref(UPB_UPCAST(ret), &ret); + + ret->group = UPB_UPCAST(group); + ret->schema_ = msg; + ret->dest_handlers_ = dest_handlers; + ret->is_native_ = false; // If we JIT, it will update this later. upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64); - if (ret->dest_handlers) { - upb_handlers_ref(ret->dest_handlers, ret); + if (ret->dest_handlers_) { + upb_handlers_ref(ret->dest_handlers_, ret); } return ret; } -static void freemethod(upb_pbdecodermethod *method) { - if (method->dest_handlers) { - upb_handlers_unref(method->dest_handlers, method); - } +void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner) { + upb_refcounted_ref(UPB_UPCAST(m), owner); +} - upb_inttable_uninit(&method->dispatch); - free(method); +void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m, + const void *owner) { + upb_refcounted_unref(UPB_UPCAST(m), owner); } +void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m, + const void *from, const void *to) { + upb_refcounted_donateref(UPB_UPCAST(m), from, to); +} -/* upb_pbdecoderplan **********************************************************/ +void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m, + const void *owner) { + upb_refcounted_checkref(UPB_UPCAST(m), owner); +} -upb_pbdecoderplan *newplan() { - upb_pbdecoderplan *p = malloc(sizeof(*p)); - upb_inttable_init(&p->methods, UPB_CTYPE_PTR); - p->code = NULL; - p->code_end = NULL; - return p; +const upb_msgdef *upb_pbdecodermethod_schema(const upb_pbdecodermethod *m) { + return m->schema_; } -void freeplan(void *_p) { - upb_pbdecoderplan *p = _p; +const upb_handlers *upb_pbdecodermethod_desthandlers( + const upb_pbdecodermethod *m) { + return m->dest_handlers_; +} - upb_inttable_iter i; - upb_inttable_begin(&i, &p->methods); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); - freemethod(method); - } - upb_inttable_uninit(&p->methods); - free(p->code); -#ifdef UPB_USE_JIT_X64 - upb_pbdecoder_freejit(p); -#endif - free(p); +const upb_byteshandler *upb_pbdecodermethod_inputhandler( + const upb_pbdecodermethod *m) { + return &m->input_handler_; } -void set_bytecode_handlers(upb_pbdecoderplan *p, upb_handlers *h) { - upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p, - NULL); - upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_decode, p, - freeplan); - upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL); +bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) { + return m->is_native_; } -static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) { - if (upb_handlers_frametype(h) != &upb_pbdecoder_frametype) - return NULL; - upb_selector_t sel; - if (!upb_handlers_getselector(UPB_BYTESTREAM_BYTES, UPB_HANDLER_STARTSTR, - &sel)) { - return NULL; - } - return upb_handlers_gethandlerdata(h, sel); +const upb_pbdecodermethod *upb_pbdecodermethod_newfordesthandlers( + const upb_handlers *dest, const void *owner) { + upb_pbcodecache cache; + upb_pbcodecache_init(&cache); + const upb_pbdecodermethod *ret = + upb_pbcodecache_getdecodermethodfordesthandlers(&cache, dest); + upb_pbdecodermethod_ref(ret, owner); + upb_pbcodecache_uninit(&cache); + return ret; } @@ -97,16 +160,16 @@ static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) { // Data used only at compilation time. typedef struct { - upb_pbdecoderplan *plan; + mgroup *group; uint32_t *pc; int fwd_labels[MAXLABEL]; int back_labels[MAXLABEL]; } compiler; -static compiler *newcompiler(upb_pbdecoderplan *plan) { - compiler *ret = malloc(sizeof(compiler)); - ret->plan = plan; +static compiler *newcompiler(mgroup *group) { + compiler *ret = malloc(sizeof(*ret)); + ret->group = group; for (int i = 0; i < MAXLABEL; i++) { ret->fwd_labels[i] = EMPTYLABEL; ret->back_labels[i] = EMPTYLABEL; @@ -165,7 +228,7 @@ static void setofs(uint32_t *instruction, int32_t ofs) { assert(getofs(*instruction) == ofs); // Would fail in cases of overflow. } -static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; } +static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; } // Defines a local label at the current PC location. All previous forward // references are updated to point to this location. The location is noted @@ -173,7 +236,7 @@ static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; } static void label(compiler *c, unsigned int label) { assert(label < MAXLABEL); int val = c->fwd_labels[label]; - uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->plan->code + val; + uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val; while (codep) { int ofs = getofs(*codep); setofs(codep, c->pc - codep - instruction_len(*codep)); @@ -197,7 +260,7 @@ static int32_t labelref(compiler *c, int label) { return 0; } else if (label < 0) { // Backward local label. Relative to the next instruction. - uint32_t from = (c->pc + 1) - c->plan->code; + uint32_t from = (c->pc + 1) - c->group->bytecode; return c->back_labels[-label] - from; } else { // Forward local label: prepend to (possibly-empty) linked list. @@ -209,14 +272,15 @@ static int32_t labelref(compiler *c, int label) { } static void put32(compiler *c, uint32_t v) { - if (c->pc == c->plan->code_end) { + mgroup *g = c->group; + if (c->pc == g->bytecode_end) { int ofs = pcofs(c); - size_t oldsize = c->plan->code_end - c->plan->code; + size_t oldsize = g->bytecode_end - g->bytecode; size_t newsize = UPB_MAX(oldsize * 2, 64); // TODO(haberman): handle OOM. - c->plan->code = realloc(c->plan->code, newsize * sizeof(uint32_t)); - c->plan->code_end = c->plan->code + newsize; - c->pc = c->plan->code + ofs; + g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t)); + g->bytecode_end = g->bytecode + newsize; + c->pc = g->bytecode + ofs; } *c->pc++ = v; } @@ -272,7 +336,7 @@ static void putop(compiler *c, opcode op, ...) { break; case OP_CALL: { const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *); - put32(c, op | (method->base.ofs - (pcofs(c) + 1)) << 8); + put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8); break; } case OP_CHECKDELIM: @@ -349,7 +413,7 @@ static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) { const upb_pbdecodermethod *method = (void *)((char *)dispatch - offsetof(upb_pbdecodermethod, dispatch)); - fprintf(f, " %s", upb_msgdef_fullname(method->msg)); + fprintf(f, " %s", upb_msgdef_fullname(method->schema_)); break; } case OP_STARTMSG: @@ -453,7 +517,7 @@ static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { static void dispatchtarget(compiler *c, upb_pbdecodermethod *method, const upb_fielddef *f, int wire_type) { // Offset is relative to msg base. - uint64_t ofs = pcofs(c) - method->base.ofs; + uint64_t ofs = pcofs(c) - method->code_base.ofs; uint32_t fn = upb_fielddef_number(f); upb_inttable *d = &method->dispatch; upb_value v; @@ -485,11 +549,11 @@ static void putpush(compiler *c, const upb_fielddef *f) { static upb_pbdecodermethod *find_submethod(const compiler *c, const upb_pbdecodermethod *method, const upb_fielddef *f) { - const void *key = method->dest_handlers ? - (const void*)upb_handlers_getsubhandlers(method->dest_handlers, f) : - (const void*)upb_downcast_msgdef(upb_fielddef_subdef(f)); + const upb_handlers *sub = method->dest_handlers_ ? + upb_handlers_getsubhandlers(method->dest_handlers_, f) : NULL; + const void *key = methodkey(upb_downcast_msgdef(upb_fielddef_subdef(f)), sub); upb_value v; - bool ok = upb_inttable_lookupptr(&c->plan->methods, key, &v); + bool ok = upb_inttable_lookupptr(&c->group->methods, key, &v); UPB_ASSERT_VAR(ok, ok); return upb_value_getptr(v); } @@ -532,12 +596,12 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) { upb_inttable_uninit(&method->dispatch); upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64); - method->base.ofs = pcofs(c); + method->code_base.ofs = pcofs(c); putop(c, OP_SETDISPATCH, &method->dispatch); putop(c, OP_STARTMSG); label(c, LABEL_FIELD); upb_msg_iter i; - for(upb_msg_begin(&i, method->msg); !upb_msg_done(&i); upb_msg_next(&i)) { + for(upb_msg_begin(&i, method->schema_); !upb_msg_done(&i); upb_msg_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); upb_descriptortype_t type = upb_fielddef_descriptortype(f); @@ -680,17 +744,15 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) { // On the other hand, if/when the optimization mentioned below is implemented, // binding to a upb_handlers can result in *fewer* methods being generated if // many of the submessages have no handlers bound to them. -static upb_pbdecodermethod *find_methods(compiler *c, - const upb_msgdef *md, - const upb_handlers *h) { - const void *key = h ? (const void*)h : (const void*)md; +static void find_methods(compiler *c, const upb_msgdef *md, + const upb_handlers *h) { + const void *key = methodkey(md, h); upb_value v; - if (upb_inttable_lookupptr(&c->plan->methods, key, &v)) - return upb_value_getptr(v); - upb_pbdecodermethod *method = newmethod(md, h); - // Takes ownership of method. - upb_inttable_insertptr(&c->plan->methods, key, upb_value_ptr(method)); + if (upb_inttable_lookupptr(&c->group->methods, key, &v)) + return; + newmethod(md, h, c->group, key); + // Find submethods. upb_msg_iter i; for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); @@ -706,24 +768,34 @@ static upb_pbdecodermethod *find_methods(compiler *c, find_methods(c, upb_downcast_msgdef(upb_fielddef_subdef(f)), sub_h); } - - return method; } -// (Re-)compile bytecode for all messages in "msgs", ensuring that the code -// for "md" is emitted first. Overwrites any existing bytecode in "c". +// (Re-)compile bytecode for all messages in "msgs." +// Overwrites any existing bytecode in "c". static void compile_methods(compiler *c) { // Start over at the beginning of the bytecode. - c->pc = c->plan->code; - compile_method(c, c->plan->topmethod); + c->pc = c->group->bytecode; upb_inttable_iter i; - upb_inttable_begin(&i, &c->plan->methods); + upb_inttable_begin(&i, &c->group->methods); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); - if (method != c->plan->topmethod) { - compile_method(c, method); - } + compile_method(c, method); + } +} + +static void set_bytecode_handlers(mgroup *g) { + upb_inttable_iter i; + upb_inttable_begin(&i, &g->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i)); + + m->code_base.ptr = g->bytecode + m->code_base.ofs; + + upb_byteshandler *h = &m->input_handler_; + upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr); + upb_byteshandler_setstring(h, upb_pbdecoder_decode, g); + upb_byteshandler_setendstr(h, upb_pbdecoder_end, m); } } @@ -732,17 +804,13 @@ static void compile_methods(compiler *c) { #ifdef UPB_USE_JIT_X64 -static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) { - p->jit_code = NULL; - +static void sethandlers(mgroup *g, bool allowjit) { + g->jit_code = NULL; if (allowjit) { - upb_pbdecoder_jit(p); // Compile byte-code into machine code. - upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p, - freeplan); - upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, p->jit_code, NULL, NULL); - upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL); + // Compile byte-code into machine code, create handlers. + upb_pbdecoder_jit(g); } else { - set_bytecode_handlers(p, h); + set_bytecode_handlers(g); } } @@ -754,10 +822,10 @@ static bool bind_dynamic(bool allowjit) { #else // UPB_USE_JIT_X64 -static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) { +static void sethandlers(mgroup *g, bool allowjit) { // No JIT compiled in; use bytecode handlers unconditionally. UPB_UNUSED(allowjit); - set_bytecode_handlers(p, h); + set_bytecode_handlers(g); } static bool bind_dynamic(bool allowjit) { @@ -769,56 +837,16 @@ static bool bind_dynamic(bool allowjit) { #endif // UPB_USE_JIT_X64 -/* Public interface ***********************************************************/ - -bool upb_pbdecoder_isdecoder(const upb_handlers *h) { - return getdecoderplan(h) != NULL; -} - -bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p) { -#ifdef UPB_USE_JIT_X64 - return p->jit_code != NULL; -#else - UPB_UNUSED(p); - return false; -#endif -} - -bool upb_pbdecoder_hasjitcode(const upb_handlers *h) { - const upb_pbdecoderplan *p = getdecoderplan(h); - if (!p) return false; - return upb_pbdecoderplan_hasjitcode(p); -} - -uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p) { - return p->code; -} - -upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p) { -#ifdef UPB_USE_JIT_X64 - return p->jit_code; -#else - UPB_UNUSED(p); - assert(false); - return NULL; -#endif -} - -const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h) { - const upb_pbdecoderplan *p = getdecoderplan(h); - if (!p) return NULL; - return p->topmethod->dest_handlers; -} - -const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest, - bool allowjit, - const void *owner) { +// TODO(haberman): allow this to be constructed for an arbitrary set of dest +// handlers and other mgroups (but verify we have a transitive closure). +const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, + const void *owner) { UPB_UNUSED(allowjit); assert(upb_handlers_isfrozen(dest)); const upb_msgdef *md = upb_handlers_msgdef(dest); - upb_pbdecoderplan *p = newplan(); - compiler *c = newcompiler(p); + mgroup *g = newgroup(owner); + compiler *c = newcompiler(g); if (bind_dynamic(allowjit)) { // If binding dynamically, remove the reference against destination @@ -826,32 +854,75 @@ const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest, dest = NULL; } - p->topmethod = find_methods(c, md, dest); + find_methods(c, md, dest); // We compile in two passes: // 1. all messages are assigned relative offsets from the beginning of the - // bytecode (saved in method->base). + // bytecode (saved in method->code_base). // 2. forwards OP_CALL instructions can be correctly linked since message // offsets have been previously assigned. // // Could avoid the second pass by linking OP_CALL instructions somehow. compile_methods(c); compile_methods(c); - p->code_end = c->pc; + g->bytecode_end = c->pc; + freecompiler(c); #ifdef UPB_DUMP_BYTECODE FILE *f = fopen("/tmp/upb-bytecode", "wb"); assert(f); - dumpbc(p->code, p->code_end, stderr); - dumpbc(p->code, p->code_end, f); + dumpbc(g->bytecode, g->bytecode_end, stderr); + dumpbc(g->bytecode, g->bytecode_end, f); fclose(f); #endif - upb_handlers *h = upb_handlers_new( - UPB_BYTESTREAM, &upb_pbdecoder_frametype, owner); - sethandlers(p, h, allowjit); + sethandlers(g, allowjit); + return g; +} - freecompiler(c); - return h; +/* upb_pbcodecache ************************************************************/ + +void upb_pbcodecache_init(upb_pbcodecache *c) { + upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR); + c->allow_jit_ = true; +} + +void upb_pbcodecache_uninit(upb_pbcodecache *c) { + upb_inttable_iter i; + upb_inttable_begin(&i, &c->groups); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i)); + upb_refcounted_unref(UPB_UPCAST(group), c); + } + upb_inttable_uninit(&c->groups); +} + +bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) { + return c->allow_jit_; +} + +bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) { + if (upb_inttable_count(&c->groups) > 0) + return false; + c->allow_jit_ = allow; + return true; +} + +const upb_pbdecodermethod *upb_pbcodecache_getdecodermethodfordesthandlers( + upb_pbcodecache *c, const upb_handlers *handlers) { + // Right now we build a new DecoderMethod every time. + // TODO(haberman): properly cache methods by their true key. + const mgroup *g = mgroup_new(handlers, c->allow_jit_, c); + upb_inttable_push(&c->groups, upb_value_constptr(g)); + + const upb_msgdef *md = upb_handlers_msgdef(handlers); + if (bind_dynamic(c->allow_jit_)) { + handlers = NULL; + } + + upb_value v; + bool ok = upb_inttable_lookupptr(&g->methods, methodkey(md, handlers), &v); + UPB_ASSERT_VAR(ok, ok); + return upb_value_getptr(v); } diff --git a/upb/pb/compile_decoder_x64.c b/upb/pb/compile_decoder_x64.c index 2e8132e..429f690 100644 --- a/upb/pb/compile_decoder_x64.c +++ b/upb/pb/compile_decoder_x64.c @@ -34,13 +34,13 @@ #define DECODE_EOF -3 typedef struct { - upb_pbdecoderplan *plan; + mgroup *group; uint32_t *pc; // This pointer is allocated by dasm_init() and freed by dasm_free(). struct dasm_State *dynasm; - // Maps bytecode pc location -> pclabel. + // Maps arbitrary void* -> pclabel. upb_inttable pclabels; upb_inttable pcdefined; @@ -57,7 +57,6 @@ typedef struct { // Used by DynASM to store globals. void **globals; - bool usefp; bool chkret; } jitcompiler; @@ -65,16 +64,16 @@ typedef struct { static int pclabel(jitcompiler *jc, const void *here); static int define_pclabel(jitcompiler *jc, const void *here); static void asmlabel(jitcompiler *jc, const char *fmt, ...); +static int pcofs(jitcompiler* jc); #include "dynasm/dasm_proto.h" #include "dynasm/dasm_x86.h" #include "upb/pb/compile_decoder_x64.h" -static jitcompiler *newjitcompiler(upb_pbdecoderplan *plan) { +static jitcompiler *newjitcompiler(mgroup *group) { jitcompiler *jc = malloc(sizeof(jitcompiler)); - jc->usefp = false; jc->chkret = false; - jc->plan = plan; + jc->group = group; jc->pclabel_count = 0; jc->lastlabelofs = -1; upb_inttable_init(&jc->pclabels, UPB_CTYPE_UINT32); @@ -123,13 +122,22 @@ static int define_pclabel(jitcompiler *jc, const void *here) { return pclabel(jc, here); } +// Returns a bytecode pc offset relative to the beginning of the group's code. +static int pcofs(jitcompiler *jc) { + return jc->pc - jc->group->bytecode; +} + static void upb_reg_jit_gdb(jitcompiler *jc); +static int getpclabel(jitcompiler *jc, const void *target) { + return dasm_getpclabel(jc, pclabel(jc, target)); +} + // Given a pcofs relative to method, returns the machine code offset for it // (relative to the beginning of the machine code). int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) { - void *target = jc->plan->code + method->base.ofs + pcofs; - return dasm_getpclabel(jc, pclabel(jc, target)); + void *target = jc->group->bytecode + method->code_base.ofs + pcofs; + return getpclabel(jc, target); } // Given a pcofs relative to this method's base, returns a machine code offset @@ -137,7 +145,7 @@ int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) { // machine code base for dispatch table lookups). uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) { - int ofs1 = dasm_getpclabel(jc, pclabel(jc, method->dispatch.array)); + int ofs1 = getpclabel(jc, method->dispatch.array); int ofs2 = nativeofs(jc, method, pcofs); assert(ofs1 > 0); assert(ofs2 > 0); @@ -149,9 +157,11 @@ uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method, // Rewrites the dispatch tables into machine code offsets. static void patchdispatch(jitcompiler *jc) { upb_inttable_iter i; - upb_inttable_begin(&i, &jc->plan->methods); + upb_inttable_begin(&i, &jc->group->methods); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + method->is_native_ = true; + upb_inttable *dispatch = &method->dispatch; upb_inttable_iter i2; upb_inttable_begin(&i2, dispatch); @@ -169,11 +179,20 @@ static void patchdispatch(jitcompiler *jc) { } else { // Secondary slot. Since we have 64 bits for the value, we use an // absolute offset. - newval = (uint64_t)(jc->plan->jit_code + nativeofs(jc, method, val)); + newval = (uint64_t)(jc->group->jit_code + nativeofs(jc, method, val)); } bool ok = upb_inttable_replace(dispatch, key, upb_value_uint64(newval)); UPB_ASSERT_VAR(ok, ok); } + + // Set this only *after* we have patched the offsets (nativeofs() above + // reads this). + method->code_base.ptr = jc->group->jit_code + getpclabel(jc, method); + + upb_byteshandler *h = &method->input_handler_; + upb_byteshandler_setstartstr(h, upb_pbdecoder_startjit, NULL); + upb_byteshandler_setstring(h, jc->group->jit_code, method->code_base.ptr); + upb_byteshandler_setendstr(h, upb_pbdecoder_end, method); } } @@ -202,9 +221,10 @@ static void load_so(jitcompiler *jc) { FILE *f = fopen("/tmp/upb-jit-code.s", "w"); if (f) { + uint8_t *jit_code = (uint8_t*)jc->group->jit_code; fputs(" .text\n\n", f); size_t linelen = 0; - for (size_t i = 0; i < jc->plan->jit_size; i++) { + for (size_t i = 0; i < jc->group->jit_size; i++) { upb_value v; if (upb_inttable_lookup(&mclabels, i, &v)) { const char *label = upb_value_getptr(v); @@ -223,23 +243,25 @@ static void load_so(jitcompiler *jc) { fputs("\n", f); fclose(f); } else { - fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing/\n"); + fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing\n"); + abort(); } // TODO: racy if (system("gcc -shared -o /tmp/upb-jit-code.so /tmp/upb-jit-code.s") != 0) { + fprintf(stderr, "Error compiling upb-jit-code.s\n"); abort(); } - jc->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY); - if (!jc->dl) { + jc->group->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY); + if (!jc->group->dl) { fprintf(stderr, "Couldn't dlopen(): %s\n", dlerror()); abort(); } - munmap(jit_code, jc->plan->jit_size); - jit_code = dlsym(jc->dl, "X.enterjit"); - if (!jit_code) { + munmap(jc->group->jit_code, jc->group->jit_size); + jc->group->jit_code = dlsym(jc->group->dl, "X.enterjit"); + if (!jc->group->jit_code) { fprintf(stderr, "Couldn't find enterjit sym\n"); abort(); } @@ -248,45 +270,51 @@ static void load_so(jitcompiler *jc) { } #endif -void upb_pbdecoder_jit(upb_pbdecoderplan *plan) { - plan->debug_info = NULL; - plan->dl = NULL; +void upb_pbdecoder_jit(mgroup *group) { + group->debug_info = NULL; + group->dl = NULL; - jitcompiler *jc = newjitcompiler(plan); + assert(group->bytecode); + jitcompiler *jc = newjitcompiler(group); emit_static_asm(jc); jitbytecode(jc); - int dasm_status = dasm_link(jc, &jc->plan->jit_size); + int dasm_status = dasm_link(jc, &jc->group->jit_size); if (dasm_status != DASM_S_OK) { fprintf(stderr, "DynASM error; returned status: 0x%08x\n", dasm_status); abort(); } - char *jit_code = mmap(NULL, jc->plan->jit_size, PROT_READ | PROT_WRITE, + char *jit_code = mmap(NULL, jc->group->jit_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); dasm_encode(jc, jit_code); - mprotect(jit_code, jc->plan->jit_size, PROT_EXEC | PROT_READ); + mprotect(jit_code, jc->group->jit_size, PROT_EXEC | PROT_READ); upb_reg_jit_gdb(jc); + jc->group->jit_code = (upb_string_handlerfunc *)jit_code; #ifdef UPB_JIT_LOAD_SO load_so(jc); #endif - jc->plan->jit_code = (upb_string_handler *)jit_code; patchdispatch(jc); + freejitcompiler(jc); + + // Now the bytecode is no longer needed. + free(group->bytecode); + group->bytecode = NULL; } -void upb_pbdecoder_freejit(upb_pbdecoderplan *plan) { - if (!plan->jit_code) return; - if (plan->dl) { +void upb_pbdecoder_freejit(mgroup *group) { + if (!group->jit_code) return; + if (group->dl) { #ifdef UPB_JIT_LOAD_SO - dlclose(plan->dl); + dlclose(group->dl); #endif } else { - munmap(plan->jit_code, plan->jit_size); + munmap(group->jit_code, group->jit_size); } - free(plan->debug_info); + free(group->debug_info); // TODO: unregister GDB JIT interface. } @@ -338,15 +366,15 @@ void __attribute__((noinline)) __jit_debug_register_code() { static void upb_reg_jit_gdb(jitcompiler *jc) { // Create debug info. size_t elf_len = sizeof(upb_jit_debug_elf_file); - jc->plan->debug_info = malloc(elf_len); - memcpy(jc->plan->debug_info, upb_jit_debug_elf_file, elf_len); - uint64_t *p = (void *)jc->plan->debug_info; - for (; (void *)(p + 1) <= (void *)jc->plan->debug_info + elf_len; ++p) { + jc->group->debug_info = malloc(elf_len); + memcpy(jc->group->debug_info, upb_jit_debug_elf_file, elf_len); + uint64_t *p = (void *)jc->group->debug_info; + for (; (void *)(p + 1) <= (void *)jc->group->debug_info + elf_len; ++p) { if (*p == 0x12345678) { - *p = (uintptr_t)jc->plan->jit_code; + *p = (uintptr_t)jc->group->jit_code; } if (*p == 0x321) { - *p = jc->plan->jit_size; + *p = jc->group->jit_size; } } @@ -355,7 +383,7 @@ static void upb_reg_jit_gdb(jitcompiler *jc) { e->next_entry = __jit_debug_descriptor.first_entry; e->prev_entry = NULL; if (e->next_entry) e->next_entry->prev_entry = e; - e->symfile_addr = jc->plan->debug_info; + e->symfile_addr = jc->group->debug_info; e->symfile_size = elf_len; __jit_debug_descriptor.first_entry = e; __jit_debug_descriptor.relevant_entry = e; diff --git a/upb/pb/compile_decoder_x64.dasc b/upb/pb/compile_decoder_x64.dasc index 0bddade..fec822a 100644 --- a/upb/pb/compile_decoder_x64.dasc +++ b/upb/pb/compile_decoder_x64.dasc @@ -44,7 +44,7 @@ | sub DELIMEND, DECODER->buf | add DELIMEND, DECODER->bufstart_ofs | mov FRAME->end_ofs, DELIMEND -| mov FRAME->u.closure, CLOSURE +| mov FRAME->sink.closure, CLOSURE |.endmacro | | // Loads unsynced registers from memory back into registers. @@ -52,7 +52,7 @@ | mov FRAME, DECODER->top | mov PTR, DECODER->ptr | mov DATAEND, DECODER->data_end -| mov CLOSURE, FRAME->u.closure +| mov CLOSURE, FRAME->sink.closure | mov DELIMEND, FRAME->end_ofs | sub DELIMEND, DECODER->bufstart_ofs | add DELIMEND, DECODER->buf @@ -145,7 +145,7 @@ static void asmlabel(jitcompiler *jc, const char *fmt, ...) { char *str = malloc(len + 1); // + 1 for NULL terminator. if (!str) exit(1); - int written = vsnprintf(str, len, fmt, args); + int written = vsnprintf(str, len + 1, fmt, args); va_end(args); UPB_ASSERT_VAR(written, written == len); @@ -155,6 +155,10 @@ static void asmlabel(jitcompiler *jc, const char *fmt, ...) { upb_inttable_insert(&jc->asmlabels, label, upb_value_ptr(str)); } +static upb_func *gethandler(const upb_handlers *h, upb_selector_t sel) { + return h ? upb_handlers_gethandler(h, sel) : NULL; +} + // Emit static assembly routines; code that does not vary based on the message // schema. Since it's not input-dependent, we only need one single copy of it. // For the moment we generate a single copy per generated handlers. Eventually @@ -174,9 +178,6 @@ static void emit_static_asm(jitcompiler *jc) { |->enterjit: |1: | push rbp - if (jc->usefp) { - | mov rbp, rsp - } | push r15 | push r14 | push r13 @@ -189,9 +190,12 @@ static void emit_static_asm(jitcompiler *jc) { | // 16-byte stack alignment. | sub rsp, 8 | + | mov rbx, ARG2_64 // Preserve JIT method. + | | mov DECODER, rdi | callp upb_pbdecoder_resume // Same args as us; reuse regs. | mov DECODER->saved_rsp, rsp + | mov rax, rbx | load_regs | | // Test whether we have a saved stack to resume. @@ -199,7 +203,7 @@ static void emit_static_asm(jitcompiler *jc) { | test ARG3_64, ARG3_64 | jnz >1 | - | call =>pclabel(jc, jc->plan->topmethod) + | call rax | | mov rax, DECODER->size_param | mov qword DECODER->call_len, 0 @@ -265,7 +269,7 @@ static void emit_static_asm(jitcompiler *jc) { asmlabel(jc, "pushlendelim"); |->pushlendelim: |1: - | mov FRAME->u.closure, CLOSURE + | mov FRAME->sink.closure, CLOSURE | mov DECODER->checkpoint, PTR | dv32 | mov rcx, DELIMEND @@ -511,7 +515,7 @@ static void jitprimitive(jitcompiler *jc, opcode op, static char fastpath_bytes[] = { 1, 1, 4, 8 }; const valtype_t type = types[op]; const int fastbytes = fastpath_bytes[type]; - upb_func *handler = upb_handlers_gethandler(h, sel); + upb_func *handler = gethandler(h, sel); if (handler) { |1: @@ -678,12 +682,20 @@ static void jitdispatch(jitcompiler *jc, |=>define_pclabel(jc, &method->dispatch): |1: // Decode the field tag. - // OPT: inline two bytes of varint decoding for big messages. | mov aword DECODER->checkpoint, PTR - | chkeob 1, >6 + | chkeob 2, >6 | movzx edx, byte [PTR] | test dl, dl - | jns >7 + | jns >7 // Jump if first byte has no continuation bit. + | movzx ecx, byte [PTR + 1] + | test cl, cl + | js >6 // Jump if second byte has continuation bit. + | // Confirmed two-byte varint. + | shl ecx, 7 + | and edx, 0x7f + | or edx, ecx + | add PTR, 2 + | jmp >8 |6: | call ->decode_unknown_tag_fallback | test eax, eax // Hit DELIMEND? @@ -848,15 +860,14 @@ static void jittag(jitcompiler *jc, uint64_t tag, int n, int ofs, static void jitbytecode(jitcompiler *jc) { upb_pbdecodermethod *method = NULL; const upb_handlers *h = NULL; - for (jc->pc = jc->plan->code; jc->pc < jc->plan->code_end; ) { + for (jc->pc = jc->group->bytecode; jc->pc < jc->group->bytecode_end; ) { int32_t instr = *jc->pc; opcode op = instr & 0xff; uint32_t arg = instr >> 8; int32_t longofs = arg; if (op != OP_STARTMSG && op != OP_SETDISPATCH) { - asmlabel(jc, "0x%lx.%s", jc->pc - jc->plan->code, - upb_pbdecoder_getopname(op)); + asmlabel(jc, "0x%lx.%s", pcofs(jc), upb_pbdecoder_getopname(op)); } // TODO: optimize this to only define pclabels that are actually used. |=>define_pclabel(jc, jc->pc): @@ -865,16 +876,11 @@ static void jitbytecode(jitcompiler *jc) { switch (op) { case OP_STARTMSG: { // This opcode serves as a function prolouge also. - const char *msgname = upb_msgdef_fullname(method->msg); - asmlabel(jc, "parse.%s", msgname); + const char *msgname = upb_msgdef_fullname(method->schema_); + asmlabel(jc, "0x%lx.parse.%s", pcofs(jc), msgname); |=>define_pclabel(jc, method): - if (jc->usefp) { - | push rbp - | mov rbp, rsp - } else { - | sub rsp, 8 - } - upb_func *startmsg = upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR); + | sub rsp, 8 + upb_func *startmsg = gethandler(h, UPB_STARTMSG_SELECTOR); if (startmsg) { // bool startmsg(void *closure, const void *hd) |1: @@ -892,7 +898,7 @@ static void jitbytecode(jitcompiler *jc) { } case OP_ENDMSG: { // This opcode serves as a function epiloue also. - upb_func *endmsg = upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR); + upb_func *endmsg = gethandler(h, UPB_ENDMSG_SELECTOR); |9: if (endmsg) { // bool endmsg(void *closure, const void *hd, upb_status *status) @@ -901,11 +907,7 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG3_64, DECODER->status | callp endmsg } - if (jc->usefp) { - | pop rbp - } else { - | add rsp, 8 - } + | add rsp, 8 | ret break; } @@ -917,10 +919,13 @@ static void jitbytecode(jitcompiler *jc) { // &method->dispatch; we want to go backwards and recover method. method = (void*)((char*)dispatch - offsetof(upb_pbdecodermethod, dispatch)); - h = method->dest_handlers; - assert(h); // We only support statically-bound handlers for now. - const char *msgname = upb_msgdef_fullname(method->msg); - asmlabel(jc, "dispatch.%s", msgname); + // May be NULL, in which case no handlers for this message will be found. + // OPT: we should do better by completely skipping the message in this + // case instead of parsing it field by field. We should also do the skip + // in the containing message's code. + h = method->dest_handlers_; + const char *msgname = upb_msgdef_fullname(method->schema_); + asmlabel(jc, "0x%lx.dispatch.%s", pcofs(jc), msgname); jitdispatch(jc, method); break; } @@ -942,7 +947,7 @@ static void jitbytecode(jitcompiler *jc) { case OP_STARTSEQ: case OP_STARTSUBMSG: case OP_STARTSTR: { - upb_func *start = upb_handlers_gethandler(h, arg); + upb_func *start = gethandler(h, arg); if (start) { // void *startseq(void *closure, const void *hd) // void *startsubmsg(void *closure, const void *hd) @@ -972,7 +977,7 @@ static void jitbytecode(jitcompiler *jc) { case OP_ENDSEQ: case OP_ENDSUBMSG: case OP_ENDSTR: { - upb_func *end = upb_handlers_gethandler(h, arg); + upb_func *end = gethandler(h, arg); if (end) { // bool endseq(void *closure, const void *hd) // bool endsubmsg(void *closure, const void *hd) @@ -995,7 +1000,7 @@ static void jitbytecode(jitcompiler *jc) { break; } case OP_STRING: { - upb_func *str = upb_handlers_gethandler(h, arg); + upb_func *str = gethandler(h, arg); | cmp PTR, DELIMEND | je >4 |1: @@ -1028,7 +1033,13 @@ static void jitbytecode(jitcompiler *jc) { break; } case OP_PUSHTAGDELIM: - | mov FRAME->u.closure, CLOSURE + | mov FRAME->sink.closure, CLOSURE + | // This shouldn't need to be read, because tag-delimited fields + | // shouldn't have an OP_SETDELIM after them. But for the moment + | // non-packed repeated fields do OP_SETDELIM so they can share more + | // code with the packed code-path. If this is changed later, this + | // store can be removed. + | mov qword FRAME->end_ofs, 0 | add FRAME, sizeof(upb_pbdecoder_frame) | cmp FRAME, DECODER->limit | je ->err @@ -1038,13 +1049,14 @@ static void jitbytecode(jitcompiler *jc) { break; case OP_POP: | sub FRAME, sizeof(upb_pbdecoder_frame) - | mov CLOSURE, FRAME->u.closure + | mov CLOSURE, FRAME->sink.closure break; case OP_SETDELIM: // OPT: experiment with testing vs old offset to optimize away. | mov DATAEND, DECODER->end | add DELIMEND, FRAME->end_ofs - | jc >1 + | cmp DELIMEND, DECODER->buf + | jb >1 | cmp DELIMEND, DATAEND | ja >1 // OPT: try cmov. | mov DATAEND, DELIMEND diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c index 70862d5..6fd6576 100644 --- a/upb/pb/decoder.c +++ b/upb/pb/decoder.c @@ -10,7 +10,6 @@ #include <stdarg.h> #include <stddef.h> #include <stdlib.h> -#include "upb/bytestream.h" #include "upb/pb/decoder.int.h" #include "upb/pb/varint.int.h" @@ -70,7 +69,7 @@ static bool in_residual_buf(upb_pbdecoder *d, const char *p); static void seterr(upb_pbdecoder *d, const char *msg) { // TODO(haberman): encapsulate this access to pipeline->status, but not sure // exactly what that interface should look like. - upb_status_seterrliteral(&d->sink->pipeline_->status_, msg); + upb_status_seterrmsg(d->status, msg); } void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) { @@ -377,7 +376,7 @@ static bool push(upb_pbdecoder *d, uint64_t end) { fr++; fr->end_ofs = end; - fr->u.dispatch = NULL; + fr->dispatch = NULL; fr->groupnum = -1; d->top = fr; return true; @@ -441,7 +440,7 @@ int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum, } static int32_t dispatch(upb_pbdecoder *d) { - upb_inttable *dispatch = d->top->u.dispatch; + upb_inttable *dispatch = d->top->dispatch; // Decode tag. uint32_t tag; @@ -478,16 +477,23 @@ static int32_t dispatch(upb_pbdecoder *d) { } } +// Callers know that the stack is more than one deep because the opcodes that +// call this only occur after PUSH operations. +upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { + assert(d->top != d->stack); + return d->top - 1; +} + /* The main decoding loop *****************************************************/ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, size_t size) { upb_pbdecoder *d = closure; - const upb_pbdecoderplan *p = hd; + const mgroup *group = hd; assert(buf); upb_pbdecoder_resume(d, NULL, buf, size); - UPB_UNUSED(p); + UPB_UNUSED(group); #define VMCASE(op, code) \ case op: { code; if (consumes_input(op)) checkpoint(d); break; } @@ -495,7 +501,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, VMCASE(OP_PARSE_ ## type, { \ ctype val; \ CHECK_RETURN(decode_ ## wt(d, &val)); \ - upb_sink_put ## name(d->sink, arg, (convfunc)(val)); \ + upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \ }) while(1) { @@ -513,7 +519,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, (int)(d->data_end - ptr(d)), (int)(d->end - ptr(d)), (int)((d->top->end_ofs - d->bufstart_ofs) - (ptr(d) - d->buf)), - (int)(d->pc - 1 - upb_pbdecoderplan_codebase(p)), + (int)(d->pc - 1 - group->bytecode), upb_pbdecoder_getopname(op), arg); #endif @@ -537,39 +543,42 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, VMCASE(OP_SETDISPATCH, d->top->base = d->pc - 1; - memcpy(&d->top->u.dispatch, d->pc, sizeof(void*)); + memcpy(&d->top->dispatch, d->pc, sizeof(void*)); d->pc += sizeof(void*) / sizeof(uint32_t); ) VMCASE(OP_STARTMSG, - CHECK_SUSPEND(upb_sink_startmsg(d->sink)); + CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink)); ) VMCASE(OP_ENDMSG, - CHECK_SUSPEND(upb_sink_endmsg(d->sink)); + CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status)); assert(d->call_len > 0); d->pc = d->callstack[--d->call_len]; ) VMCASE(OP_STARTSEQ, - CHECK_SUSPEND(upb_sink_startseq(d->sink, arg)); + upb_pbdecoder_frame *outer = outer_frame(d); + CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink)); ) VMCASE(OP_ENDSEQ, - CHECK_SUSPEND(upb_sink_endseq(d->sink, arg)); + CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg)); ) VMCASE(OP_STARTSUBMSG, - CHECK_SUSPEND(upb_sink_startsubmsg(d->sink, arg)); + upb_pbdecoder_frame *outer = outer_frame(d); + CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink)); ) VMCASE(OP_ENDSUBMSG, - CHECK_SUSPEND(upb_sink_endsubmsg(d->sink, arg)); + CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg)); ) VMCASE(OP_STARTSTR, uint32_t len = d->top->end_ofs - offset(d); - CHECK_SUSPEND(upb_sink_startstr(d->sink, arg, len)); + upb_pbdecoder_frame *outer = outer_frame(d); + CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink)); if (len == 0) { d->pc++; // Skip OP_STRING. } ) VMCASE(OP_STRING, uint32_t len = curbufleft(d); - CHECK_SUSPEND(upb_sink_putstring(d->sink, arg, ptr(d), len)); + CHECK_SUSPEND(upb_sink_putstring(&d->top->sink, arg, ptr(d), len)); advance(d, len); if (d->delim_end == NULL) { // String extends beyond this buf? d->pc--; @@ -579,7 +588,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, } ) VMCASE(OP_ENDSTR, - CHECK_SUSPEND(upb_sink_endstr(d->sink, arg)); + CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg)); ) VMCASE(OP_PUSHTAGDELIM, CHECK_SUSPEND(push(d, d->top->end_ofs)); @@ -664,50 +673,52 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, } } -void *upb_pbdecoder_start(void *closure, const void *handler_data, - size_t size_hint) { +void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { + upb_pbdecoder *d = closure; UPB_UNUSED(size_hint); + d->call_len = 1; + d->pc = pc; + return d; +} + +void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) { + UPB_UNUSED(hd); upb_pbdecoder *d = closure; - const upb_pbdecoderplan *plan = handler_data; - UPB_UNUSED(plan); - if (upb_pbdecoderplan_hasjitcode(plan)) { - d->top->u.closure = d->sink->top->closure; - d->call_len = 0; - } else { - d->call_len = 1; - d->pc = upb_pbdecoderplan_codebase(plan); - } - assert(d); - assert(d->sink); - if (plan->topmethod->dest_handlers) { - assert(d->sink->top->h == plan->topmethod->dest_handlers); - } - d->status = &d->sink->pipeline_->status_; + d->call_len = 0; return d; } bool upb_pbdecoder_end(void *closure, const void *handler_data) { upb_pbdecoder *d = closure; - const upb_pbdecoderplan *plan = handler_data; + const upb_pbdecodermethod *method = handler_data; if (d->residual_end > d->residual) { seterr(d, "Unexpected EOF"); return false; } + if (d->top->end_ofs != UINT64_MAX) { + seterr(d, "Unexpected EOF inside delimited string"); + return false; + } + // Message ends here. uint64_t end = offset(d); d->top->end_ofs = end; + char dummy; - if (upb_pbdecoderplan_hasjitcode(plan)) { #ifdef UPB_USE_JIT_X64 + const mgroup *group = (const mgroup*)method->group; + if (group->jit_code) { if (d->top != d->stack) d->stack->end_ofs = 0; - upb_pbdecoderplan_jitcode(plan)(closure, handler_data, &dummy, 0); -#endif + group->jit_code(closure, method->code_base.ptr, &dummy, 0); } else { +#endif d->stack->end_ofs = end; - uint32_t *p = d->pc - 1; + const uint32_t *p = d->pc; + // Check the previous bytecode, but guard against beginning. + if (p != method->code_base.ptr) p--; if (getop(*p) == OP_CHECKDELIM) { // Rewind from OP_TAG* to OP_CHECKDELIM. assert(getop(*d->pc) == OP_TAG1 || @@ -716,28 +727,29 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { d->pc = p; } upb_pbdecoder_decode(closure, handler_data, &dummy, 0); +#ifdef UPB_USE_JIT_X64 } +#endif if (d->call_len != 0) { seterr(d, "Unexpected EOF"); return false; } - return upb_ok(&d->sink->pipeline_->status_); + return true; } -void init(void *_d, upb_pipeline *p) { - UPB_UNUSED(p); - upb_pbdecoder *d = _d; +void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *m, + upb_status *s) { d->limit = &d->stack[UPB_DECODER_MAX_NESTING]; - d->sink = NULL; + upb_bytessink_reset(&d->input_, &m->input_handler_, d); + d->method_ = m; d->callstack[0] = &halt; - // reset() must be called before decoding; this is guaranteed by assert() in - // start(). + d->status = s; + upb_pbdecoder_reset(d); } -void reset(void *_d) { - upb_pbdecoder *d = _d; +void upb_pbdecoder_reset(upb_pbdecoder *d) { d->top = d->stack; d->top->end_ofs = UINT64_MAX; d->bufstart_ofs = 0; @@ -748,21 +760,27 @@ void reset(void *_d) { d->call_len = 1; } -bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink* sink) { - // TODO(haberman): typecheck the sink, and test whether the decoder is in the - // middle of decoding. Return false if either assumption is violated. - d->sink = sink; - reset(d); - return true; +// Not currently required, but to support outgrowing the static stack we need +// this. +void upb_pbdecoder_uninit(upb_pbdecoder *d) {} + +const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) { + return d->method_; } -const upb_frametype upb_pbdecoder_frametype = { - sizeof(upb_pbdecoder), - init, - NULL, - reset, -}; +bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink* sink) { + // TODO(haberman): do we need to test whether the decoder is already on the + // stack (like calling this from within a callback)? Should we support + // rebinding the output at all? + assert(sink); + if (d->method_->dest_handlers_) { + if (sink->handlers != d->method_->dest_handlers_) + return false; + } + upb_sink_reset(&d->top->sink, sink->handlers, sink->closure); + return true; +} -const upb_frametype *upb_pbdecoder_getframetype() { - return &upb_pbdecoder_frametype; +upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) { + return &d->input_; } diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h index c645688..4529324 100644 --- a/upb/pb/decoder.h +++ b/upb/pb/decoder.h @@ -1,102 +1,447 @@ /* * upb - a minimalist implementation of protocol buffers. * - * Copyright (c) 2009-2010 Google Inc. See LICENSE for details. + * Copyright (c) 2009-2013 Google Inc. See LICENSE for details. * Author: Josh Haberman <jhaberman@gmail.com> * - * upb::Decoder implements a high performance, streaming decoder for protobuf - * data that works by parsing input data one buffer at a time and calling into - * a upb::Handlers. + * upb::pb::Decoder implements a high performance, streaming, resumable decoder + * for the binary protobuf format. */ #ifndef UPB_DECODER_H_ #define UPB_DECODER_H_ +#include "upb/table.int.h" #include "upb/sink.h" +#ifdef __cplusplus +namespace upb { +namespace pb { +class CodeCache; +class Decoder; +class DecoderMethod; +} // namespace pb +} // namespace upb + +typedef upb::pb::CodeCache upb_pbcodecache; +typedef upb::pb::Decoder upb_pbdecoder; +typedef upb::pb::DecoderMethod upb_pbdecodermethod; +#else +struct upb_pbdecoder; +struct upb_pbdecodermethod; +struct upb_pbcodecache; + +typedef struct upb_pbdecoder upb_pbdecoder; +typedef struct upb_pbdecodermethod upb_pbdecodermethod; +typedef struct upb_pbcodecache upb_pbcodecache; +#endif + // The maximum that any submessages can be nested. Matches proto2's limit. -// At the moment this specifies the size of several statically-sized arrays -// and therefore setting it high will cause more memory to be used. Will -// be replaced by a runtime-configurable limit and dynamically-resizing arrays. -// TODO: make this a runtime-settable property of Decoder. +// This specifies the size of the decoder's statically-sized array and therefore +// setting it high will cause the upb::pb::Decoder object to be larger. +// +// If necessary we can add a runtime-settable property to Decoder that allow +// this to be larger than the compile-time setting, but this would add +// complexity, particularly since we would have to decide how/if to give users +// the ability to set a custom memory allocation function. #define UPB_DECODER_MAX_NESTING 64 +// Internal-only struct used by the decoder. +typedef struct { #ifdef __cplusplus -namespace upb { -namespace pb { + private: +#endif + // Space optimization note: we store two pointers here that the JIT + // doesn't need at all; the upb_handlers* inside the sink and + // the dispatch table pointer. We can optimze so that the JIT uses + // smaller stack frames than the interpreter. The only thing we need + // to guarantee is that the fallback routines can find end_ofs. -// Frame type that encapsulates decoder state. -class Decoder; +#ifdef __cplusplus + char sink[sizeof(upb_sink)]; +#else + upb_sink sink; +#endif + // The absolute stream offset of the end-of-frame delimiter. + // Non-delimited frames (groups and non-packed repeated fields) reuse the + // delimiter of their parent, even though the frame may not end there. + // + // NOTE: the JIT stores a slightly different value here for non-top frames. + // It stores the value relative to the end of the enclosed message. But the + // top frame is still stored the same way, which is important for ensuring + // that calls from the JIT into C work correctly. + uint64_t end_ofs; + const uint32_t *base; + uint32_t groupnum; + upb_inttable *dispatch; // Not used by the JIT. +} upb_pbdecoder_frame; -// Resets the sink of the Decoder. This must be called at least once before -// the decoder can be used. It may only be called with the decoder is in a -// state where it was just created or reset. The given sink must be from the -// same pipeline as this decoder. -inline bool ResetDecoderSink(Decoder* d, Sink* sink); +#ifdef __cplusplus -// Gets the handlers suitable for parsing protobuf data according to the given -// destination handlers. The protobuf schema to parse is taken from dest. -inline const upb::Handlers *GetDecoderHandlers(const upb::Handlers *dest, - bool allowjit, - const void *owner); +// Represents the code to parse a protobuf according to a specific schema, +// optionally bound to a set of destination handlers. +class upb::pb::DecoderMethod /* : public upb::RefCounted */ { + public: + // From upb::ReferenceCounted. + void Ref(const void* owner) const; + void Unref(const void* owner) const; + void DonateRef(const void* from, const void* to) const; + void CheckRef(const void* owner) const; -// Returns true if these handlers represent a upb::pb::Decoder. -bool IsDecoder(const upb::Handlers *h); + // The schema that this method parses. Never NULL. + const MessageDef* schema() const; -// Returns true if IsDecoder(h) and the given handlers have JIT code. -inline bool HasJitCode(const upb::Handlers* h); + // The destination handlers that are statically bound to this method. + // This method is only capable of outputting to a sink that uses these + // handlers. + // + // Will be NULL if this method is not statically bound. + const Handlers* dest_handlers() const; -// Returns the destination handlers if IsDecoder(h), otherwise returns NULL. -const upb::Handlers* GetDestHandlers(const upb::Handlers* h); + // The input handlers for this decoder method. + const BytesHandler* input_handler() const; -} // namespace pb -} // namespace upb + // Whether this method is native. + bool is_native() const; -typedef upb::pb::Decoder upb_pbdecoder; + // Convenience method for generating a DecoderMethod without explicitly + // creating a CodeCache. + static reffed_ptr<const DecoderMethod> NewForDestHandlers( + const upb::Handlers *dest); -extern "C" { + private: + UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod); #else -struct upb_pbdecoder; -typedef struct upb_pbdecoder upb_pbdecoder; +struct upb_pbdecodermethod { +#endif + upb_refcounted base; + + // While compiling, the base is relative in "ofs", after compiling it is + // absolute in "ptr". + union { + uint32_t ofs; // PC offset of method. + void *ptr; // Pointer to bytecode or machine code for this method. + } code_base; + + // The decoder method group to which this method belongs. We own a ref. + // Owning a ref on the entire group is more coarse-grained than is strictly + // necessary; all we truly require is that methods we directly reference + // outlive us, while the group could contain many other messages we don't + // require. But the group represents the messages that were + // allocated+compiled together, so it makes the most sense to free them + // together also. + const upb_refcounted *group; + + // Whether this method is native code or bytecode. + bool is_native_; + + // The handler one calls to invoke this method. + upb_byteshandler input_handler_; + + // The message type that this method is parsing. + const upb_msgdef *schema_; + + // The destination handlers this method is bound to, or NULL if this method + // can be bound to a destination handlers instance at runtime. + // + // If non-NULL, we own a ref. + const upb_handlers *dest_handlers_; + + // The dispatch table layout is: + // [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ] + // + // If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup + // (UPB_MAX_FIELDNUMBER + fieldnum) and jump there. + // + // We need two wire types because of packed/non-packed compatibility. A + // primitive repeated field can use either wire type and be valid. While we + // could key the table on fieldnum+wiretype, the table would be 8x sparser. + // + // Storing two wire types in the primary value allows us to quickly rule out + // the second wire type without needing to do a separate lookup (this case is + // less common than an unknown field). + upb_inttable dispatch; +}; + +#ifdef __cplusplus + +// A Decoder receives binary protobuf data on its input sink and pushes the +// decoded data to its output sink. +class upb::pb::Decoder { + public: + // Constructs a decoder instance for the given method, which must outlive this + // decoder. Any errors during parsing will be set on the given status, which + // must also outlive this decoder. + Decoder(const DecoderMethod* method, Status* status); + ~Decoder(); + + // Returns the DecoderMethod this decoder is parsing from. + // TODO(haberman): Do users need to be able to rebind this? + const DecoderMethod* method() const; + + // Resets the state of the decoder. + void Reset(); + + // Resets the output sink of the Decoder. + // The given sink must match method()->schema() as well as + // method()->dest_handlers() if the latter is non-NULL. + // + // This must be called at least once before the decoder can be used. It may + // only be called with the decoder is in a state where it was just created or + // reset with pipeline.Reset(). The given sink must be from the same pipeline + // as this decoder. + bool ResetOutput(Sink* sink); + + // The sink on which this decoder receives input. + BytesSink* input(); + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Decoder); +#else +struct upb_pbdecoder { +#endif + // Our input sink. + upb_bytessink input_; + + // The decoder method we are parsing with (owned). + const upb_pbdecodermethod *method_; + + size_t call_len; + const uint32_t *pc, *last; + + // Current input buffer and its stream offset. + const char *buf, *ptr, *end, *checkpoint; + + // End of the delimited region, relative to ptr, or NULL if not in this buf. + const char *delim_end; + + // End of the delimited region, relative to ptr, or end if not in this buf. + const char *data_end; + + // Overall stream offset of "buf." + uint64_t bufstart_ofs; + + // How many bytes past the end of the user buffer we want to skip. + size_t skip; + + // Buffer for residual bytes not parsed from the previous buffer. + // The maximum number of residual bytes we require is 12; a five-byte + // unknown tag plus an eight-byte value, less one because the value + // is only a partial value. + char residual[12]; + char *residual_end; + + // Stores the user buffer passed to our decode function. + const char *buf_param; + size_t size_param; + +#ifdef UPB_USE_JIT_X64 + // Used momentarily by the generated code to store a value while a user + // function is called. + uint32_t tmp_len; + + const void *saved_rsp; +#endif + + upb_status *status; + + // Our internal stack. + upb_pbdecoder_frame *top, *limit; + upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING]; +#ifdef UPB_USE_JIT_X64 + // Each native stack frame needs two pointers, plus we need a few frames for + // the enter/exit trampolines. + const uint32_t *callstack[(UPB_DECODER_MAX_NESTING * 2) + 10]; +#else + const uint32_t *callstack[UPB_DECODER_MAX_NESTING]; +#endif +}; + +#ifdef __cplusplus + +// A class for caching protobuf processing code, whether bytecode for the +// interpreted decoder or machine code for the JIT. +// +// This class is not thread-safe. +class upb::pb::CodeCache { + public: + CodeCache(); + ~CodeCache(); + + // Whether the cache is allowed to generate machine code. Defaults to true. + // There is no real reason to turn it off except for testing or if you are + // having a specific problem with the JIT. + // + // Note that allow_jit = true does not *guarantee* that the code will be JIT + // compiled. If this platform is not supported or the JIT was not compiled + // in, the code may still be interpreted. + bool allow_jit() const; + + // This may only be called when the object is first constructed, and prior to + // any code generation, otherwise returns false and does nothing. + bool set_allow_jit(bool allow); + + // Returns a DecoderMethod that can push data to the given handlers. + // If a suitable method already exists, it will be returned from the cache. + // + // Specifying the destination handlers here allows the DecoderMethod to be + // statically bound to the destination handlers if possible, which can allow + // more efficient decoding. However the returned method may or may not + // actually be statically bound. But in all cases, the returned method can + // push data to the given handlers. + const DecoderMethod *GetDecoderMethodForDestHandlers( + const upb::Handlers *handlers); + + // If/when someone needs to explicitly create a dynamically-bound + // DecoderMethod*, we can add a method to get it here. + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache); +#else +struct upb_pbcodecache { #endif + bool allow_jit_; + + // Array of mgroups. + upb_inttable groups; +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *method, + upb_status *status); +void upb_pbdecoder_uninit(upb_pbdecoder *d); +void upb_pbdecoder_reset(upb_pbdecoder *d); +const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d); +bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink *sink); +upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d); -// C API. -const upb_frametype *upb_pbdecoder_getframetype(); -bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink *sink); -const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest, - bool allowjit, - const void *owner); -bool upb_pbdecoder_isdecoder(const upb_handlers *h); -bool upb_pbdecoder_hasjitcode(const upb_handlers *h); -const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h); +void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner); +void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m, const void *owner); +void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m, + const void *from, const void *to); +void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m, + const void *owner); +const upb_msgdef *upb_pbdecodermethod_schema(const upb_pbdecodermethod *m); +const upb_handlers *upb_pbdecodermethod_desthandlers( + const upb_pbdecodermethod *m); +const upb_byteshandler *upb_pbdecodermethod_inputhandler( + const upb_pbdecodermethod *m); +bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m); +const upb_pbdecodermethod *upb_pbdecodermethod_newfordesthandlers( + const upb_handlers *dest, const void *owner); -// C++ implementation details. ///////////////////////////////////////////////// +void upb_pbcodecache_init(upb_pbcodecache *c); +void upb_pbcodecache_uninit(upb_pbcodecache *c); +bool upb_pbcodecache_allowjit(const upb_pbcodecache *c); +bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow); +const upb_pbdecodermethod *upb_pbcodecache_getdecodermethodfordesthandlers( + upb_pbcodecache *c, const upb_handlers *handlers); + +#ifdef __cplusplus +} /* extern "C" */ +#endif #ifdef __cplusplus -} // extern "C" namespace upb { +template<> +class Pointer<pb::DecoderMethod> { + public: + explicit Pointer(pb::DecoderMethod* ptr) : ptr_(ptr) {} + operator pb::DecoderMethod*() { return ptr_; } + operator RefCounted*() { return UPB_UPCAST(ptr_); } + private: + pb::DecoderMethod* ptr_; +}; + +template<> +class Pointer<const pb::DecoderMethod> { + public: + explicit Pointer(const pb::DecoderMethod* ptr) : ptr_(ptr) {} + operator const pb::DecoderMethod*() { return ptr_; } + operator const RefCounted*() { return UPB_UPCAST(ptr_); } + private: + const pb::DecoderMethod* ptr_; +}; + namespace pb { -inline bool ResetDecoderSink(Decoder* r, Sink* sink) { - return upb_pbdecoder_resetsink(r, sink); + +inline Decoder::Decoder(const DecoderMethod* m, Status* s) { + upb_pbdecoder_init(this, m, s); +} +inline Decoder::~Decoder() { + upb_pbdecoder_uninit(this); +} +inline const DecoderMethod* Decoder::method() const { + return upb_pbdecoder_method(this); +} +inline void Decoder::Reset() { + upb_pbdecoder_reset(this); +} +inline bool Decoder::ResetOutput(Sink* sink) { + return upb_pbdecoder_resetoutput(this, sink); +} +inline BytesSink* Decoder::input() { + return upb_pbdecoder_input(this); +} + +inline void DecoderMethod::Ref(const void *owner) const { + upb_pbdecodermethod_ref(this, owner); } -inline const upb::Handlers* GetDecoderHandlers(const upb::Handlers* dest, - bool allowjit, - const void* owner) { - return upb_pbdecoder_gethandlers(dest, allowjit, owner); +inline void DecoderMethod::Unref(const void *owner) const { + upb_pbdecodermethod_unref(this, owner); } -inline bool IsDecoder(const upb::Handlers* h) { - return upb_pbdecoder_isdecoder(h); +inline void DecoderMethod::DonateRef(const void *from, const void *to) const { + upb_pbdecodermethod_donateref(this, from, to); } -inline bool HasJitCode(const upb::Handlers* h) { - return upb_pbdecoder_hasjitcode(h); +inline void DecoderMethod::CheckRef(const void *owner) const { + upb_pbdecodermethod_checkref(this, owner); } -inline const upb::Handlers* GetDestHandlers(const upb::Handlers* h) { - return upb_pbdecoder_getdesthandlers(h); +inline const MessageDef* DecoderMethod::schema() const { + return upb_pbdecodermethod_schema(this); } +inline const Handlers* DecoderMethod::dest_handlers() const { + return upb_pbdecodermethod_desthandlers(this); +} +inline const BytesHandler* DecoderMethod::input_handler() const { + return upb_pbdecodermethod_inputhandler(this); +} +inline bool DecoderMethod::is_native() const { + return upb_pbdecodermethod_isnative(this); +} +// static +inline reffed_ptr<const DecoderMethod> DecoderMethod::NewForDestHandlers( + const Handlers *dest) { + const upb_pbdecodermethod *m = + upb_pbdecodermethod_newfordesthandlers(dest, &m); + return reffed_ptr<const DecoderMethod>(m, &m); +} + +inline CodeCache::CodeCache() { + upb_pbcodecache_init(this); +} +inline CodeCache::~CodeCache() { + upb_pbcodecache_uninit(this); +} +inline bool CodeCache::allow_jit() const { + return upb_pbcodecache_allowjit(this); +} +inline bool CodeCache::set_allow_jit(bool allow) { + return upb_pbcodecache_setallowjit(this, allow); +} +inline const DecoderMethod* CodeCache::GetDecoderMethodForDestHandlers( + const upb::Handlers* handlers) { + return upb_pbcodecache_getdecodermethodfordesthandlers(this, handlers); +} + } // namespace pb } // namespace upb -#endif + +#endif // __cplusplus #endif /* UPB_DECODER_H_ */ diff --git a/upb/pb/decoder.int.h b/upb/pb/decoder.int.h index 8c8710c..1c10eb3 100644 --- a/upb/pb/decoder.int.h +++ b/upb/pb/decoder.int.h @@ -67,11 +67,46 @@ typedef enum { UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; } -const upb_frametype upb_pbdecoder_frametype; +// Method group; represents a set of decoder methods that had their code +// emitted together, and must therefore be freed together. Immutable once +// created. It is possible we may want to expose this to users at some point. +// +// Overall ownership of Decoder objects looks like this: +// +// +----------+ +// | | <---> DecoderMethod +// | method | +// CodeCache ---> | group | <---> DecoderMethod +// | | +// | (mgroup) | <---> DecoderMethod +// +----------+ +typedef struct { + upb_refcounted base; + + // Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. We own refs on the + // methods. + upb_inttable methods; + + // When we add the ability to link to previously existing mgroups, we'll + // need an array of mgroups we reference here, and own refs on them. + + // The bytecode for our methods, if any exists. Owned by us. + uint32_t *bytecode; + uint32_t *bytecode_end; + +#ifdef UPB_USE_JIT_X64 + // JIT-generated machine code, if any. + upb_string_handlerfunc *jit_code; + // The size of the jit_code (required to munmap()). + size_t jit_size; + char *debug_info; + void *dl; +#endif +} mgroup; // Decoder entry points; used as handlers. -void *upb_pbdecoder_start(void *closure, const void *handler_data, - size_t size_hint); +void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint); +void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint); size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, size_t size); bool upb_pbdecoder_end(void *closure, const void *handler_data); @@ -91,18 +126,12 @@ void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg); // Error messages that are shared between the bytecode and JIT decoders. extern const char *kPbDecoderStackOverflow; -typedef struct _upb_pbdecoderplan upb_pbdecoderplan; - // Access to decoderplan members needed by the decoder. -bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p); -uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p); const char *upb_pbdecoder_getopname(unsigned int op); -upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p); - -// JIT entry point. -void upb_pbdecoder_jit(upb_pbdecoderplan *plan); -void upb_pbdecoder_freejit(upb_pbdecoderplan *plan); +// JIT codegen entry point. +void upb_pbdecoder_jit(mgroup *group); +void upb_pbdecoder_freejit(mgroup *group); // A special label that means "do field dispatch for this message and branch to // wherever that takes you." @@ -112,131 +141,4 @@ void upb_pbdecoder_freejit(upb_pbdecoderplan *plan); #define DECODE_MISMATCH -2 // Used only from checktag_slow(). #define DECODE_ENDGROUP -2 // Used only from checkunknown(). -typedef struct { - // The absolute stream offset of the end-of-frame delimiter. - // Non-delimited frames (groups and non-packed repeated fields) reuse the - // delimiter of their parent, even though the frame may not end there. - // - // NOTE: the JIT stores a slightly different value here for non-top frames. - // It stores the value relative to the end of the enclosed message. But the - // innermost frame is still stored the same way, which is important for - // ensuring that calls from the JIT into C work correctly. - uint64_t end_ofs; - uint32_t *base; - uint32_t groupnum; - union { - upb_inttable *dispatch; // Not used by the JIT. - void *closure; // Only used by the JIT. - } u; -} upb_pbdecoder_frame; - -struct upb_pbdecoder { - // Where we push parsed data (not owned). - upb_sink *sink; - - size_t call_len; - uint32_t *pc, *last; - - // Current input buffer and its stream offset. - const char *buf, *ptr, *end, *checkpoint; - - // End of the delimited region, relative to ptr, or NULL if not in this buf. - const char *delim_end; - - // End of the delimited region, relative to ptr, or end if not in this buf. - const char *data_end; - - // Overall stream offset of "buf." - uint64_t bufstart_ofs; - - // How many bytes past the end of the user buffer we want to skip. - size_t skip; - - // Buffer for residual bytes not parsed from the previous buffer. - // The maximum number of residual bytes we require is 12; a five-byte - // unknown tag plus an eight-byte value, less one because the value - // is only a partial value. - char residual[12]; - char *residual_end; - - // Stores the user buffer passed to our decode function. - const char *buf_param; - size_t size_param; - -#ifdef UPB_USE_JIT_X64 - // Used momentarily by the generated code to store a value while a user - // function is called. - uint32_t tmp_len; - - const void *saved_rsp; -#endif - - upb_status *status; - - // Our internal stack. - upb_pbdecoder_frame *top, *limit; - upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING]; - uint32_t *callstack[UPB_DECODER_MAX_NESTING * 2]; -}; - -// Data pertaining to a single decoding method/function. -// Each method contains code to parse a single message type. -// If may or may not be bound to a destination handlers object. -typedef struct { - // While compiling, the base is relative in "ofs", after compiling it is - // absolute in "ptr". - union { - uint32_t ofs; // PC offset of method. - const void *ptr; // Pointer to bytecode or machine code for this method. - } base; - - // Whether this method is native code or bytecode. - bool native_code; - - // The message type that this method is parsing. - const upb_msgdef *msg; - - // The destination handlers this method is bound to, or NULL if this method - // can be bound to a destination handlers instance at runtime. - // - // If non-NULL, we own a ref. - const upb_handlers *dest_handlers; - - // The dispatch table layout is: - // [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ] - // - // If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup - // (UPB_MAX_FIELDNUMBER + fieldnum) and jump there. - // - // We need two wire types because of packed/non-packed compatibility. A - // primitive repeated field can use either wire type and be valid. While we - // could key the table on fieldnum+wiretype, the table would be 8x sparser. - // - // Storing two wire types in the primary value allows us to quickly rule out - // the second wire type without needing to do a separate lookup (this case is - // less common than an unknown field). - upb_inttable dispatch; -} upb_pbdecodermethod; - -struct _upb_pbdecoderplan { - // Pointer to bytecode. - uint32_t *code, *code_end; - - // Maps upb_msgdef*/upb_handlers* -> upb_pbdecodermethod - upb_inttable methods; - - // The method that starts parsing when we first call into the plan. - // Ideally we will remove the idea that any of the methods in the plan - // are special like this, so that any method can be the top-level one. - upb_pbdecodermethod *topmethod; - -#ifdef UPB_USE_JIT_X64 - // JIT-generated machine code (else NULL). - upb_string_handler *jit_code; - size_t jit_size; - char *debug_info; - void *dl; -#endif -}; - #endif // UPB_DECODER_INT_H_ diff --git a/upb/pb/glue.c b/upb/pb/glue.c index 9027e0f..73ef145 100644 --- a/upb/pb/glue.c +++ b/upb/pb/glue.c @@ -10,45 +10,39 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "upb/bytestream.h" #include "upb/descriptor/reader.h" #include "upb/pb/decoder.h" upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, void *owner, upb_status *status) { // Create handlers. - const upb_handlers *reader_h = upb_descreader_gethandlers(&reader_h); - const upb_handlers *decoder_h = - upb_pbdecoder_gethandlers(reader_h, true, &decoder_h); + const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h); + const upb_pbdecodermethod *decoder_m = + upb_pbdecodermethod_newfordesthandlers(reader_h, &decoder_m); - // Create pipeline. - upb_pipeline pipeline; - upb_pipeline_init(&pipeline, NULL, 0, upb_realloc, NULL); - upb_pipeline_donateref(&pipeline, reader_h, &reader_h); - upb_pipeline_donateref(&pipeline, decoder_h, &decoder_h); + upb_pbdecoder decoder; + upb_descreader reader; - // Create sinks. - upb_sink *reader_sink = upb_pipeline_newsink(&pipeline, reader_h); - upb_sink *decoder_sink = upb_pipeline_newsink(&pipeline, decoder_h); - upb_pbdecoder *d = upb_sink_getobj(decoder_sink); - upb_pbdecoder_resetsink(d, reader_sink); + upb_pbdecoder_init(&decoder, decoder_m, status); + upb_descreader_init(&reader, reader_h, status); + upb_pbdecoder_resetoutput(&decoder, upb_descreader_input(&reader)); // Push input data. - bool ok = upb_bytestream_putstr(decoder_sink, str, len); + bool ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(&decoder)); - if (status) upb_status_copy(status, upb_pipeline_status(&pipeline)); - if (!ok) { - upb_pipeline_uninit(&pipeline); - return NULL; - } + upb_def **ret = NULL; - upb_descreader *r = upb_sink_getobj(reader_sink); - upb_def **defs = upb_descreader_getdefs(r, owner, n); - upb_def **defscopy = malloc(sizeof(upb_def*) * (*n)); - memcpy(defscopy, defs, sizeof(upb_def*) * (*n)); - upb_pipeline_uninit(&pipeline); + if (!ok) goto cleanup; + upb_def **defs = upb_descreader_getdefs(&reader, owner, n); + ret = malloc(sizeof(upb_def*) * (*n)); + memcpy(ret, defs, sizeof(upb_def*) * (*n)); - return defscopy; +cleanup: + upb_pbdecoder_uninit(&decoder); + upb_descreader_uninit(&reader); + upb_handlers_unref(reader_h, &reader_h); + upb_pbdecodermethod_unref(decoder_m, &decoder_m); + return ret; } bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len, diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c index 08eda15..0c12571 100644 --- a/upb/pb/textprinter.c +++ b/upb/pb/textprinter.c @@ -203,40 +203,42 @@ static void onmreg(void *c, upb_handlers *h) { upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + upb_handlerattr_sethandlerdata(&attr, f, NULL); switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: - upb_handlers_setint32(h, f, putint32, f, NULL); + upb_handlers_setint32(h, f, putint32, &attr); break; case UPB_TYPE_INT64: - upb_handlers_setint64(h, f, putint64, f, NULL); + upb_handlers_setint64(h, f, putint64, &attr); break; case UPB_TYPE_UINT32: - upb_handlers_setuint32(h, f, putuint32, f, NULL); + upb_handlers_setuint32(h, f, putuint32, &attr); break; case UPB_TYPE_UINT64: - upb_handlers_setuint64(h, f, putuint64, f, NULL); + upb_handlers_setuint64(h, f, putuint64, &attr); break; case UPB_TYPE_FLOAT: - upb_handlers_setfloat(h, f, putfloat, f, NULL); + upb_handlers_setfloat(h, f, putfloat, &attr); break; case UPB_TYPE_DOUBLE: - upb_handlers_setdouble(h, f, putdouble, f, NULL); + upb_handlers_setdouble(h, f, putdouble, &attr); break; case UPB_TYPE_BOOL: - upb_handlers_setbool(h, f, putbool, f, NULL); + upb_handlers_setbool(h, f, putbool, &attr); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: - upb_handlers_setstartstr(h, f, startstr, f, NULL); - upb_handlers_setstring(h, f, putstr, f, NULL); - upb_handlers_setendstr(h, f, endstr, f, NULL); + upb_handlers_setstartstr(h, f, startstr, &attr); + upb_handlers_setstring(h, f, putstr, &attr); + upb_handlers_setendstr(h, f, endstr, &attr); break; case UPB_TYPE_MESSAGE: - upb_handlers_setstartsubmsg(h, f, &startsubmsg, f, NULL); - upb_handlers_setendsubmsg(h, f, &endsubmsg, f, NULL); + upb_handlers_setstartsubmsg(h, f, startsubmsg, &attr); + upb_handlers_setendsubmsg(h, f, endsubmsg, &attr); break; case UPB_TYPE_ENUM: - upb_handlers_setint32(h, f, putenum, f, NULL); + upb_handlers_setint32(h, f, putenum, &attr); default: assert(false); break; @@ -246,5 +248,5 @@ static void onmreg(void *c, upb_handlers *h) { const upb_handlers *upb_textprinter_newhandlers(const void *owner, const upb_msgdef *m) { - return upb_handlers_newfrozen(m, NULL, owner, &onmreg, NULL); + return upb_handlers_newfrozen(m, owner, &onmreg, NULL); } diff --git a/upb/refcounted.c b/upb/refcounted.c index fbeca64..455e536 100644 --- a/upb/refcounted.c +++ b/upb/refcounted.c @@ -315,7 +315,7 @@ typedef enum { UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); } UPB_NORETURN static void oom(tarjan *t) { - upb_status_seterrliteral(t->status, "out of memory"); + upb_status_seterrmsg(t->status, "out of memory"); err(t); } @@ -353,7 +353,7 @@ static void push(tarjan *t, const upb_refcounted *r) { // get 31 bits, which is plenty (limit of 2B objects frozen at a time). setattr(t, r, GREEN | (t->index << 2) | (t->index << 33)); if (++t->index == 0x80000000) { - upb_status_seterrliteral(t->status, "too many objects to freeze"); + upb_status_seterrmsg(t->status, "too many objects to freeze"); err(t); } upb_inttable_push(&t->stack, upb_value_ptr((void*)r)); diff --git a/upb/refcounted.h b/upb/refcounted.h index a0d535a..9e2910b 100644 --- a/upb/refcounted.h +++ b/upb/refcounted.h @@ -67,7 +67,7 @@ class upb::RefCounted { void CheckRef(const void *owner) const; private: - UPB_DISALLOW_POD_OPS(RefCounted); + UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted); #else struct upb_refcounted { #endif diff --git a/upb/shim/shim.c b/upb/shim/shim.c index a249e84..5c3e026 100644 --- a/upb/shim/shim.c +++ b/upb/shim/shim.c @@ -36,8 +36,14 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, d->offset = offset; d->hasbit = hasbit; + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + upb_handlerattr_sethandlerdata(&attr, d, free); + #define TYPE(u, l) \ - case UPB_TYPE_##u: return upb_handlers_set##l(h, f, upb_shim_set##l, d, free) + case UPB_TYPE_##u: \ + ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break; + + bool ok = false; switch (upb_fielddef_type(f)) { TYPE(INT64, int64); @@ -48,28 +54,31 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, TYPE(DOUBLE, double); TYPE(FLOAT, float); TYPE(BOOL, bool); - default: assert(false); return false; + default: assert(false); break; } #undef TYPE + + upb_handlerattr_uninit(&attr); + return ok; } const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s, upb_fieldtype_t *type) { upb_func *f = upb_handlers_gethandler(h, s); - if ((upb_int64_handler*)f == upb_shim_setint64) { + if ((upb_int64_handlerfunc*)f == upb_shim_setint64) { *type = UPB_TYPE_INT64; - } else if ((upb_int32_handler*)f == upb_shim_setint32) { + } else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) { *type = UPB_TYPE_INT32; - } else if ((upb_uint64_handler*)f == upb_shim_setuint64) { + } else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) { *type = UPB_TYPE_UINT64; - } else if ((upb_uint32_handler*)f == upb_shim_setuint32) { + } else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) { *type = UPB_TYPE_UINT32; - } else if ((upb_double_handler*)f == upb_shim_setdouble) { + } else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) { *type = UPB_TYPE_DOUBLE; - } else if ((upb_float_handler*)f == upb_shim_setfloat) { + } else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) { *type = UPB_TYPE_FLOAT; - } else if ((upb_bool_handler*)f == upb_shim_setbool) { + } else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) { *type = UPB_TYPE_BOOL; } else { return NULL; diff --git a/upb/sink.c b/upb/sink.c deleted file mode 100644 index 8f810ee..0000000 --- a/upb/sink.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2011-2012 Google Inc. See LICENSE for details. - * Author: Josh Haberman <jhaberman@gmail.com> - */ - -#include "upb/sink.h" - -#include <stdlib.h> -#include <string.h> - -static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p); -static void upb_sink_resetobj(void *obj); -static const upb_frametype upb_sink_frametype; - -static bool chkstack(upb_sink *s) { - if (s->top + 1 >= s->limit) { - upb_status_seterrliteral(&s->pipeline_->status_, "Nesting too deep."); - return false; - } else { - return true; - } -} - -#define alignof(type) offsetof (struct { char c; type member; }, member) - -typedef union { double u; void *p; long l; } maxalign_t; -static const size_t maxalign = alignof(maxalign_t); - -static void *align_up(void *p) { - if (!p) return NULL; - uintptr_t val = (uintptr_t)p; - uintptr_t aligned = - val % maxalign == 0 ? val : val + maxalign - (val % maxalign); - return (void*)aligned; -} - -void *upb_realloc(void *ud, void *ptr, size_t size) { - UPB_UNUSED(ud); - return realloc(ptr, size); -} - - -/* upb_pipeline ***************************************************************/ - -// For the moment we get fixed-size blocks of this size, but we could change -// this strategy if necessary. -#define BLOCK_SIZE 8192 - -struct region { - struct region *prev; - maxalign_t data[1]; // Region data follows. -}; - -size_t regionsize(size_t usable_size) { - return sizeof(struct region) - sizeof(maxalign_t) + usable_size; -} - -struct obj { - struct obj *prev; - const upb_frametype *ft; - maxalign_t data; // Region data follows. -}; - -size_t objsize(size_t memsize) { - return sizeof(struct obj) - sizeof(maxalign_t) + memsize; -} - -void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size, - void *(*realloc)(void *ud, void *ptr, size_t bytes), - void *ud) { - p->realloc = realloc; - p->ud = ud; - p->bump_top = initial_mem; - p->bump_limit = initial_mem ? initial_mem + initial_size : NULL; - p->region_head = NULL; - p->obj_head = NULL; - p->last_alloc = NULL; - upb_status_init(&p->status_); -} - -void upb_pipeline_uninit(upb_pipeline *p) { - for (struct obj *o = p->obj_head; o; o = o->prev) { - if (o->ft->uninit) - o->ft->uninit(&o->data); - } - - for (struct region *r = p->region_head; r; ) { - struct region *prev = r->prev; - p->realloc(p->ud, r, 0); - r = prev; - } - upb_status_uninit(&p->status_); -} - -void *upb_pipeline_alloc(upb_pipeline *p, size_t bytes) { - void *mem = align_up(p->bump_top); - if (!mem || mem > p->bump_limit || p->bump_limit - mem < bytes) { - size_t size = regionsize(UPB_MAX(BLOCK_SIZE, bytes)); - struct region *r; - if (!p->realloc || !(r = p->realloc(p->ud, NULL, size))) { - return NULL; - } - r->prev = p->region_head; - p->region_head = r; - p->bump_limit = (char*)r + size; - mem = &r->data[0]; - assert(p->bump_limit > mem); - assert(p->bump_limit - mem >= bytes); - } - p->bump_top = mem + bytes; - p->last_alloc = mem; - return mem; -} - -void *upb_pipeline_realloc(upb_pipeline *p, void *ptr, - size_t oldsize, size_t bytes) { - if (ptr && ptr == p->last_alloc && - p->bump_limit - ptr >= bytes) { - p->bump_top = ptr + bytes; - return ptr; - } else { - void *mem = upb_pipeline_alloc(p, bytes); - memcpy(mem, ptr, oldsize); - return mem; - } -} - -void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *ft) { - struct obj *obj = upb_pipeline_alloc(p, objsize(ft->size)); - if (!obj) return NULL; - - obj->prev = p->obj_head; - obj->ft = ft; - p->obj_head = obj; - if (ft->init) ft->init(&obj->data, p); - return &obj->data; -} - -void upb_pipeline_reset(upb_pipeline *p) { - upb_status_clear(&p->status_); - for (struct obj *o = p->obj_head; o; o = o->prev) { - if (o->ft->reset) - o->ft->reset(&o->data); - } -} - -upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *handlers) { - upb_sink *s = upb_pipeline_allocobj(p, &upb_sink_frametype); - upb_sink_init(s, handlers, p); - return s; -} - -const upb_status *upb_pipeline_status(const upb_pipeline *p) { - return &p->status_; -} - -typedef struct { - const upb_handlers *h; -} handlersref_t; - -static void freehandlersref(void *r) { - handlersref_t *ref = r; - upb_handlers_unref(ref->h, &ref->h); -} - -static const upb_frametype handlersref_frametype = { - sizeof(handlersref_t), - NULL, - freehandlersref, - NULL, -}; - -void upb_pipeline_donateref( - upb_pipeline *p, const upb_handlers *h, const void *owner) { - handlersref_t *ref = upb_pipeline_allocobj(p, &handlersref_frametype); - upb_handlers_donateref(h, owner, &ref->h); - ref->h = h; -} - - -/* upb_sink *******************************************************************/ - -static const upb_frametype upb_sink_frametype = { - sizeof(upb_sink), - NULL, - NULL, - upb_sink_resetobj, -}; - -void upb_sink_reset(upb_sink *s, void *closure) { - s->top = s->stack; - s->top->closure = closure; -} - -static void upb_sink_resetobj(void *obj) { - upb_sink *s = obj; - s->top = s->stack; -} - -static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p) { - s->pipeline_ = p; - s->stack = upb_pipeline_alloc(p, sizeof(*s->stack) * UPB_SINK_MAX_NESTING); - s->top = s->stack; - s->limit = s->stack + UPB_SINK_MAX_NESTING; - s->top->h = h; - if (h->ft) { - s->top->closure = upb_pipeline_allocobj(p, h->ft); - } -} - -upb_pipeline *upb_sink_pipeline(const upb_sink *s) { - return s->pipeline_; -} - -void *upb_sink_getobj(const upb_sink *s) { - return s->stack[0].closure; -} - -bool upb_sink_startmsg(upb_sink *s) { - const upb_handlers *h = s->top->h; - upb_startmsg_handler *startmsg = - (upb_startmsg_handler *)upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR); - if (startmsg) { - const void *hd = upb_handlers_gethandlerdata(h, UPB_STARTMSG_SELECTOR); - bool ok = startmsg(s->top->closure, hd); - if (!ok) return false; - } - return true; -} - -bool upb_sink_endmsg(upb_sink *s) { - const upb_handlers *h = s->top->h; - upb_endmsg_handler *endmsg = - (upb_endmsg_handler *)upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR); - if (endmsg) { - const void *hd = upb_handlers_gethandlerdata(h, UPB_ENDMSG_SELECTOR); - bool ok = endmsg(s->top->closure, hd, &s->pipeline_->status_); - if (!ok) return false; - } - return true; -} - -#define PUTVAL(type, ctype) \ - bool upb_sink_put ## type(upb_sink *s, upb_selector_t sel, ctype val) { \ - const upb_handlers *h = s->top->h; \ - upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \ - upb_handlers_gethandler(h, sel); \ - if (handler) { \ - const void *hd = upb_handlers_gethandlerdata(h, sel); \ - bool ok = handler(s->top->closure, hd, val); \ - if (!ok) return false; \ - } \ - return true; \ - } - -PUTVAL(int32, int32_t); -PUTVAL(int64, int64_t); -PUTVAL(uint32, uint32_t); -PUTVAL(uint64, uint64_t); -PUTVAL(float, float); -PUTVAL(double, double); -PUTVAL(bool, bool); -#undef PUTVAL - -size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, - const char *buf, size_t n) { - const upb_handlers *h = s->top->h; - upb_string_handler *handler = - (upb_string_handler*)upb_handlers_gethandler(h, sel); - - if (handler) { - const void *hd = upb_handlers_gethandlerdata(h, sel);; - n = handler(s->top->closure, hd, buf, n); - } - - return n; -} - -bool upb_sink_startseq(upb_sink *s, upb_selector_t sel) { - if (!chkstack(s)) return false; - - void *subc = s->top->closure; - const upb_handlers *h = s->top->h; - upb_startfield_handler *startseq = - (upb_startfield_handler*)upb_handlers_gethandler(h, sel); - - if (startseq) { - const void *hd = upb_handlers_gethandlerdata(h, sel); - subc = startseq(s->top->closure, hd); - if (subc == UPB_BREAK) { - return false; - } - } - - s->top->selector = upb_handlers_getendselector(sel); - ++s->top; - s->top->h = h; - s->top->closure = subc; - return true; -} - -bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) { - --s->top; - assert(sel == s->top->selector); - - const upb_handlers *h = s->top->h; - upb_endfield_handler *endseq = - (upb_endfield_handler*)upb_handlers_gethandler(h, sel); - - if (endseq) { - const void *hd = upb_handlers_gethandlerdata(h, sel); - bool ok = endseq(s->top->closure, hd); - if (!ok) { - ++s->top; - return false; - } - } - - return true; -} - -bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint) { - if (!chkstack(s)) return false; - - void *subc = s->top->closure; - const upb_handlers *h = s->top->h; - upb_startstr_handler *startstr = - (upb_startstr_handler*)upb_handlers_gethandler(h, sel); - - if (startstr) { - const void *hd = upb_handlers_gethandlerdata(h, sel); - subc = startstr(s->top->closure, hd, size_hint); - if (subc == UPB_BREAK) { - return false; - } - } - - s->top->selector = upb_handlers_getendselector(sel); - ++s->top; - s->top->h = h; - s->top->closure = subc; - return true; -} - -bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) { - --s->top; - assert(sel == s->top->selector); - const upb_handlers *h = s->top->h; - upb_endfield_handler *endstr = - (upb_endfield_handler*)upb_handlers_gethandler(h, sel); - - if (endstr) { - const void *hd = upb_handlers_gethandlerdata(h, sel); - bool ok = endstr(s->top->closure, hd); - if (!ok) { - ++s->top; - return false; - } - } - - return true; -} - -bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel) { - if (!chkstack(s)) return false; - - void *subc = s->top->closure; - const upb_handlers *h = s->top->h; - upb_startfield_handler *startsubmsg = - (upb_startfield_handler*)upb_handlers_gethandler(h, sel); - - if (startsubmsg) { - const void *hd = upb_handlers_gethandlerdata(h, sel); - subc = startsubmsg(s->top->closure, hd); - if (subc == UPB_BREAK) { - return false; - } - } - - s->top->selector= upb_handlers_getendselector(sel); - ++s->top; - s->top->h = upb_handlers_getsubhandlers_sel(h, sel); - // TODO: should add support for submessages without any handlers - assert(s->top->h); - s->top->closure = subc; - return true; -} - -bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) { - --s->top; - - assert(sel == s->top->selector); - const upb_handlers *h = s->top->h; - upb_endfield_handler *endsubmsg = - (upb_endfield_handler*)upb_handlers_gethandler(h, sel); - - if (endsubmsg) { - const void *hd = upb_handlers_gethandlerdata(h, sel); - bool ok = endsubmsg(s->top->closure, hd); - if (!ok) { - ++s->top; - return false; - } - } - - return true; -} - -const upb_handlers *upb_sink_tophandlers(upb_sink *s) { - return s->top->h; -} @@ -24,144 +24,64 @@ #ifdef __cplusplus namespace upb { -class Pipeline; +class BufferSource; +class BytesSink; class Sink; -template <int size> class SeededPipeline; } -typedef upb::Pipeline upb_pipeline; +typedef upb::BufferSource upb_bufsrc; +typedef upb::BytesSink upb_bytessink; typedef upb::Sink upb_sink; #else -struct upb_pipeline; struct upb_sink; -typedef struct upb_pipeline upb_pipeline; +struct upb_bufsrc; +struct upb_bytessink; typedef struct upb_sink upb_sink; +typedef struct upb_bytessink upb_bytessink; +typedef struct upb_bufsrc upb_bufsrc; #endif -struct upb_sinkframe; -// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit. -// TODO: make this a runtime-settable property of Sink. -#define UPB_SINK_MAX_NESTING 64 - -#ifdef __cplusplus +// Internal-only struct for the sink. +struct upb_sinkframe { + const upb_handlers *h; + void *closure; -// A upb::Pipeline is a set of sinks that can send data to each other. The -// pipeline object also contains an arena allocator that the sinks and their -// associated processing state can use for fast memory allocation. This makes -// pipelines very fast to construct and destroy, especially if the arena is -// supplied with an initial block of memory. If this initial block of memory -// is from the C stack and is large enough, then actual heap allocation can be -// avoided entirely which significantly reduces overhead in some cases. -// -// All sinks and processing state are automatically freed when the pipeline is -// destroyed, so Free() is not necessary or possible. Allocated objects can -// optionally specify a Reset() callback that will be called when whenever the -// pipeline is Reset() or destroyed. This can be used to free any outside -// resources the object is holding. -// -// Pipelines (and sinks/objects allocated from them) are not thread-safe! -class upb::Pipeline { - public: - // Initializes the pipeline's arena with the given initial memory that will - // be used before allocating memory using the given allocation function. - // The "ud" pointer will be passed as the first parameter to the realloc - // callback, and can be used to pass user-specific state. - Pipeline(void *initial_mem, size_t initial_size, - void *(*realloc)(void *ud, void *ptr, size_t size), void *ud); - ~Pipeline(); - - // Returns a newly-allocated Sink for the given handlers. The sink is will - // live as long as the pipeline does. Caller retains ownership of the - // handlers object, which must outlive the pipeline. + // For any frames besides the top, this is the END* callback that will run + // when the subframe is popped (for example, for a "sequence" frame the frame + // above it will be a UPB_HANDLER_ENDSEQ handler). But this is only + // necessary for assertion checking inside upb_sink and can be omitted if the + // sink has only one caller. // - // TODO(haberman): add an option for the sink to take a ref, so the handlers - // don't have to outlive? This would be simpler but imposes a minimum cost. - // Taking an atomic ref is not *so* bad in the single-threaded case, but this - // can degrade heavily under contention, so we need a way to avoid it in - // cases where this overhead would be significant and the caller can easily - // guarantee the outlive semantics. - Sink* NewSink(const Handlers* handlers); - - // Accepts a ref donated from the given owner. Will unref the Handlers when - // the Pipeline is destroyed. - void DonateRef(const Handlers* h, const void* owner); - - // The current error status for the pipeline. - const upb::Status& status() const; - - // Calls "reset" on all Sinks and resettable state objects in the arena, and - // resets the error status. Useful for resetting processing state so new - // input can be accepted. - void Reset(); - - // Allocates/reallocates memory of the given size, or returns NULL if no - // memory is available. It is not necessary (or possible) to manually free - // the memory obtained from these functions. - void* Alloc(size_t size); - void* Realloc(void* ptr, size_t old_size, size_t size); - - // Allocates an object with the given FrameType. Note that this object may - // *not* be resized with Realloc(). - void* AllocObject(const FrameType* type); - - private: -#else -struct upb_pipeline { -#endif - void *(*realloc)(void *ud, void *ptr, size_t size); - void *ud; - void *bump_top; // Current alloc offset, either from initial or dyn region. - void *bump_limit; // Limit of current alloc block. - void *obj_head; // Linked list of objects with "reset" functions. - void *region_head; // Linked list of dyn regions we got from user's realloc(). - void *last_alloc; - upb_status status_; + // TODO(haberman): have a mechanism for ensuring that a sink only has one + // caller. + upb_selector_t selector; }; -struct upb_frametype { - size_t size; - void (*init)(void* obj, upb_pipeline *p); - void (*uninit)(void* obj); - void (*reset)(void* obj); -}; +// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit. +// TODO: make this a runtime-settable property of Sink. +#define UPB_SINK_MAX_NESTING 64 #ifdef __cplusplus -// For convenience, a template for a pipeline with an array of initial memory. -template <int initial_size> -class upb::SeededPipeline : public upb::Pipeline { - public: - SeededPipeline(void *(*realloc)(void *ud, void *ptr, size_t size), void *ud) - : Pipeline(mem_, initial_size, realloc, ud) { - } - - private: - char mem_[initial_size]; -}; - // A upb::Sink is an object that binds a upb::Handlers object to some runtime -// state. It is the object that can actually call a set of handlers. -// -// Unlike upb::Def and upb::Handlers, upb::Sink is never frozen, immutable, or -// thread-safe. You can create as many of them as you want, but each one may -// only be used in a single thread at a time. -// -// If we compare with class-based OOP, a you can think of a upb::Def as an -// abstract base class, a upb::Handlers as a concrete derived class, and a -// upb::Sink as an object (class instance). -// -// Each upb::Sink lives in exactly one pipeline. +// state. It represents an endpoint to which data can be sent. class upb::Sink { public: + // Constructor with no initialization; must be Reset() before use. + Sink() {} - // Resets the state of the sink so that it is ready to accept new input. - // Any state from previously received data is discarded. "Closure" will be - // used as the top-level closure. - void Reset(void *closure); + // Constructs a new sink for the given frozen handlers and closure. + // + // TODO: once the Handlers know the expected closure type, verify that T + // matches it. + template <class T> Sink(const Handlers* handlers, T* closure); - // Returns the pipeline that this sink comes from. - Pipeline* pipeline() const; + // Resets the value of the sink. + template <class T> void Reset(const Handlers* handlers, T* closure); // Returns the top-level object that is bound to this sink. + // + // TODO: once the Handlers know the expected closure type, verify that T + // matches it. template <class T> T* GetObject() const; // Functions for pushing data into the sink. @@ -178,10 +98,10 @@ class upb::Sink { // sink->StartSubMessage(startsubmsg_selector); // sink->StartMessage(); // // ... - // sink->EndMessage(); + // sink->EndMessage(&status); // sink->EndSubMessage(endsubmsg_selector); bool StartMessage(); - bool EndMessage(); + bool EndMessage(Status* status); // Putting of individual values. These work for both repeated and // non-repeated fields, but for repeated fields you must wrap them in @@ -196,122 +116,306 @@ class upb::Sink { // Putting of string/bytes values. Each string can consist of zero or more // non-contiguous buffers of data. - bool StartString(Handlers::Selector s, size_t size_hint); + // + // For StartString(), the function will write a sink for the string to "sub." + // The sub-sink must be used for any/all PutStringBuffer() calls. + bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub); size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len); bool EndString(Handlers::Selector s); // For submessage fields. - bool StartSubMessage(Handlers::Selector s); + // + // For StartSubMessage(), the function will write a sink for the string to + // "sub." The sub-sink must be used for any/all handlers called within the + // submessage. + bool StartSubMessage(Handlers::Selector s, Sink* sub); bool EndSubMessage(Handlers::Selector s); // For repeated fields of any type, the sequence of values must be wrapped in // these calls. - bool StartSequence(Handlers::Selector s); + // + // For StartSequence(), the function will write a sink for the string to + // "sub." The sub-sink must be used for any/all handlers called within the + // sequence. + bool StartSequence(Handlers::Selector s, Sink* sub); bool EndSequence(Handlers::Selector s); - private: - UPB_DISALLOW_POD_OPS(Sink); + // Copy and assign specifically allowed. + // We don't even bother making these members private because so many + // functions need them and this is mainly just a dumb data container anyway. #else struct upb_sink { #endif - upb_pipeline *pipeline_; - struct upb_sinkframe *top, *limit, *stack; + const upb_handlers *handlers; + void *closure; }; #ifdef __cplusplus -extern "C" { -#endif -void *upb_realloc(void *ud, void *ptr, size_t size); -void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size, - void *(*realloc)(void *ud, void *ptr, size_t size), - void *ud); -void upb_pipeline_uninit(upb_pipeline *p); -void *upb_pipeline_alloc(upb_pipeline *p, size_t size); -void *upb_pipeline_realloc( - upb_pipeline *p, void *ptr, size_t old_size, size_t size); -void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *type); -void upb_pipeline_reset(upb_pipeline *p); -void upb_pipeline_donateref( - upb_pipeline *p, const upb_handlers *h, const void *owner); -upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *h); -const upb_status *upb_pipeline_status(const upb_pipeline *p); - -void upb_sink_reset(upb_sink *s, void *closure); -upb_pipeline *upb_sink_pipeline(const upb_sink *s); -void *upb_sink_getobj(const upb_sink *s); -bool upb_sink_startmsg(upb_sink *s); -bool upb_sink_endmsg(upb_sink *s); -bool upb_sink_putint32(upb_sink *s, upb_selector_t sel, int32_t val); -bool upb_sink_putint64(upb_sink *s, upb_selector_t sel, int64_t val); -bool upb_sink_putuint32(upb_sink *s, upb_selector_t sel, uint32_t val); -bool upb_sink_putuint64(upb_sink *s, upb_selector_t sel, uint64_t val); -bool upb_sink_putfloat(upb_sink *s, upb_selector_t sel, float val); -bool upb_sink_putdouble(upb_sink *s, upb_selector_t sel, double val); -bool upb_sink_putbool(upb_sink *s, upb_selector_t sel, bool val); -bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint); -size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, - size_t len); -bool upb_sink_endstr(upb_sink *s, upb_selector_t sel); -bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel); -bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel); -bool upb_sink_startseq(upb_sink *s, upb_selector_t sel); -bool upb_sink_endseq(upb_sink *s, upb_selector_t sel); +class upb::BytesSink { + public: + BytesSink() {} + + // Constructs a new sink for the given frozen handlers and closure. + // + // TODO(haberman): once the Handlers know the expected closure type, verify + // that T matches it. + template <class T> BytesSink(const Handlers* handlers, T* closure); + + // Resets the value of the sink. + template <class T> void Reset(const Handlers* handlers, T* closure); + + bool Start(size_t size_hint, void **subc); + size_t PutBuffer(void *subc, const char *buf, size_t len); + bool End(); + +#else +struct upb_bytessink { +#endif + const upb_byteshandler *handler; + void *closure; +}; #ifdef __cplusplus -} /* extern "C" */ + +// A class for pushing a flat buffer of data to a BytesSink. +// You can construct an instance of this to get a resumable source, +// or just call the static PutBuffer() to do a non-resumable push all in one go. +class upb::BufferSource { + public: + BufferSource(); + BufferSource(const char* buf, size_t len, BytesSink* sink); + + // Returns true if the entire buffer was pushed successfully. Otherwise the + // next call to PutNext() will resume where the previous one left off. + // TODO(haberman): implement this. + bool PutNext(); + + // A static version; with this version is it not possible to resume in the + // case of failure or a partially-consumed buffer. + static bool PutBuffer(const char* buf, size_t len, BytesSink* sink); + + template <class T> static bool PutBuffer(const T& str, BytesSink* sink) { + return PutBuffer(str.c_str(), str.size(), sink); + } + + private: +#else +struct upb_bufsrc { #endif +}; #ifdef __cplusplus +extern "C" { +#endif -namespace upb { +// Inline definitions. + +UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h, + void *closure) { + s->handler = h; + s->closure = closure; +} + +UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, + void **subc) { + if (!s->handler) return true; + upb_startstr_handlerfunc *start = + (upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func; + + if (!start) return true; + *subc = start(s->closure, upb_handlerattr_handlerdata( + &s->handler->table[UPB_STARTSTR_SELECTOR].attr), + size_hint); + return *subc != NULL; +} + +UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, + const char *buf, size_t size) { + if (!s->handler) return true; + upb_string_handlerfunc *putbuf = + (upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func; + + if (!putbuf) return true; + return putbuf(subc, upb_handlerattr_handlerdata( + &s->handler->table[UPB_STRING_SELECTOR].attr), + buf, size); +} + +UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { + if (!s->handler) return true; + upb_endfield_handlerfunc *end = + (upb_endfield_handlerfunc *)s->handler->table[UPB_ENDSTR_SELECTOR].func; + + if (!end) return true; + return end(s->closure, + upb_handlerattr_handlerdata( + &s->handler->table[UPB_ENDSTR_SELECTOR].attr)); +} + +UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len, + upb_bytessink *sink) { + void *subc; + return + upb_bytessink_start(sink, len, &subc) && + (len == 0 || upb_bytessink_putbuf(sink, subc, buf, len) == len) && + upb_bytessink_end(sink); +} +#define PUTVAL(type, ctype) \ + UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \ + ctype val) { \ + if (!s->handlers) return true; \ + upb_##type##_handlerfunc *func = \ + (upb_##type##_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); \ + if (!func) return true; \ + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); \ + return func(s->closure, hd, val); \ + } -inline Pipeline::Pipeline(void *initial_mem, size_t initial_size, - void *(*realloc)(void *ud, void *ptr, size_t size), - void *ud) { - upb_pipeline_init(this, initial_mem, initial_size, realloc, ud); +PUTVAL(int32, int32_t); +PUTVAL(int64, int64_t); +PUTVAL(uint32, uint32_t); +PUTVAL(uint64, uint64_t); +PUTVAL(float, float); +PUTVAL(double, double); +PUTVAL(bool, bool); +#undef PUTVAL + +UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) { + s->handlers = h; + s->closure = c; } -inline Pipeline::~Pipeline() { - upb_pipeline_uninit(this); + +UPB_INLINE size_t +upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n) { + if (!s->handlers) return n; + upb_string_handlerfunc *handler = + (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); + + if (!handler) return n; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + return handler(s->closure, hd, buf, n); } -inline void* Pipeline::Alloc(size_t size) { - return upb_pipeline_alloc(this, size); + +UPB_INLINE bool upb_sink_startmsg(upb_sink *s) { + if (!s->handlers) return true; + upb_startmsg_handlerfunc *startmsg = + (upb_startmsg_handlerfunc *)upb_handlers_gethandler(s->handlers, + UPB_STARTMSG_SELECTOR); + if (!startmsg) return true; + const void *hd = + upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR); + return startmsg(s->closure, hd); } -inline void* Pipeline::Realloc(void* ptr, size_t old_size, size_t size) { - return upb_pipeline_realloc(this, ptr, old_size, size); + +UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) { + if (!s->handlers) return true; + upb_endmsg_handlerfunc *endmsg = + (upb_endmsg_handlerfunc *)upb_handlers_gethandler(s->handlers, + UPB_ENDMSG_SELECTOR); + + if (!endmsg) return true; + const void *hd = + upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR); + return endmsg(s->closure, hd, status); } -inline void* Pipeline::AllocObject(const upb::FrameType* type) { - return upb_pipeline_allocobj(this, type); + +UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel, + upb_sink *sub) { + sub->closure = s->closure; + sub->handlers = s->handlers; + if (!s->handlers) return true; + upb_startfield_handlerfunc *startseq = + (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); + + if (!startseq) return true; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + sub->closure = startseq(s->closure, hd); + return sub->closure ? true : false; } -inline void Pipeline::Reset() { - upb_pipeline_reset(this); + +UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) { + if (!s->handlers) return true; + upb_endfield_handlerfunc *endseq = + (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); + + if (!endseq) return true; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + return endseq(s->closure, hd); } -inline const upb::Status& Pipeline::status() const { - return *upb_pipeline_status(this); + +UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, + size_t size_hint, upb_sink *sub) { + sub->closure = s->closure; + sub->handlers = s->handlers; + if (!s->handlers) return true; + upb_startstr_handlerfunc *startstr = + (upb_startstr_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); + + if (!startstr) return true; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + sub->closure = startstr(s->closure, hd, size_hint); + return sub->closure ? true : false; } -inline Sink* Pipeline::NewSink(const upb::Handlers* handlers) { - return upb_pipeline_newsink(this, handlers); + +UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) { + if (!s->handlers) return true; + upb_endfield_handlerfunc *endstr = + (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); + + if (!endstr) return true; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + return endstr(s->closure, hd); } -inline void Pipeline::DonateRef(const upb::Handlers* h, const void *owner) { - return upb_pipeline_donateref(this, h, owner); + +UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel, + upb_sink *sub) { + sub->closure = s->closure; + if (!s->handlers) { + sub->handlers = NULL; + return true; + } + sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel); + upb_startfield_handlerfunc *startsubmsg = + (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); + + if (!startsubmsg) return true; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + sub->closure = startsubmsg(s->closure, hd); + return sub->closure ? true : false; } -inline void Sink::Reset(void *closure) { - upb_sink_reset(this, closure); +UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) { + if (!s->handlers) return true; + upb_endfield_handlerfunc *endsubmsg = + (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); + + if (!endsubmsg) return s->closure; + const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); + return endsubmsg(s->closure, hd); } -inline Pipeline* Sink::pipeline() const { - return upb_sink_pipeline(this); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#ifdef __cplusplus + +namespace upb { + +template <class T> Sink::Sink(const Handlers* handlers, T* closure) { + upb_sink_reset(this, handlers, closure); } template <class T> -inline T* Sink::GetObject() const { - return static_cast<T*>(upb_sink_getobj(this)); +inline void Sink::Reset(const Handlers* handlers, T* closure) { + upb_sink_reset(this, handlers, closure); } inline bool Sink::StartMessage() { return upb_sink_startmsg(this); } -inline bool Sink::EndMessage() { - return upb_sink_endmsg(this); +inline bool Sink::EndMessage(Status* status) { + return upb_sink_endmsg(this, status); } inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) { return upb_sink_putint32(this, sel, val); @@ -334,8 +438,9 @@ inline bool Sink::PutDouble(Handlers::Selector sel, double val) { inline bool Sink::PutBool(Handlers::Selector sel, bool val) { return upb_sink_putbool(this, sel, val); } -inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint) { - return upb_sink_startstr(this, sel, size_hint); +inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint, + Sink *sub) { + return upb_sink_startstr(this, sel, size_hint, sub); } inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf, size_t len) { @@ -344,39 +449,35 @@ inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf, inline bool Sink::EndString(Handlers::Selector sel) { return upb_sink_endstr(this, sel); } -inline bool Sink::StartSubMessage(Handlers::Selector sel) { - return upb_sink_startsubmsg(this, sel); +inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) { + return upb_sink_startsubmsg(this, sel, sub); } inline bool Sink::EndSubMessage(Handlers::Selector sel) { return upb_sink_endsubmsg(this, sel); } -inline bool Sink::StartSequence(Handlers::Selector sel) { - return upb_sink_startseq(this, sel); +inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) { + return upb_sink_startseq(this, sel, sub); } inline bool Sink::EndSequence(Handlers::Selector sel) { return upb_sink_endseq(this, sel); } -} // namespace upb -#endif +inline bool BytesSink::Start(size_t size_hint, void **subc) { + return upb_bytessink_start(this, size_hint, subc); +} +inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len) { + return upb_bytessink_putbuf(this, subc, buf, len); +} +inline bool BytesSink::End() { + return upb_bytessink_end(this); +} -// TODO(haberman): move this to sink.c. We keep it here now only because the -// JIT needs to modify it directly, which it only needs to do because it makes -// the interpreter handle fallback cases. When the JIT is self-sufficient, it -// will no longer need to touch the sink's stack at all. -struct upb_sinkframe { - const upb_handlers *h; - void *closure; +inline bool BufferSource::PutBuffer(const char *buf, size_t len, + BytesSink *sink) { + return upb_bufsrc_putbuf(buf, len, sink); +} - // For any frames besides the top, this is the END* callback that will run - // when the subframe is popped (for example, for a "sequence" frame the frame - // above it will be a UPB_HANDLER_ENDSEQ handler). But this is only - // necessary for assertion checking inside upb_sink and can be omitted if the - // sink has only one caller. - // - // TODO(haberman): have a mechanism for ensuring that a sink only has one - // caller. - upb_selector_t selector; -}; +} // namespace upb +#endif #endif diff --git a/upb/symtab.c b/upb/symtab.c index 31ae132..a3acd16 100644 --- a/upb/symtab.c +++ b/upb/symtab.c @@ -184,7 +184,7 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab, return need_dup; oom: - upb_status_seterrliteral(s, "out of memory"); + upb_status_seterrmsg(s, "out of memory"); return false; } @@ -193,7 +193,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, upb_def **add_defs = NULL; upb_strtable addtab; if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) { - upb_status_seterrliteral(status, "out of memory"); + upb_status_seterrmsg(status, "out of memory"); return false; } @@ -201,13 +201,13 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, for (int i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { - upb_status_seterrliteral(status, "added defs must be mutable"); + upb_status_seterrmsg(status, "added defs must be mutable"); goto err; } assert(!upb_def_isfrozen(def)); const char *fullname = upb_def_fullname(def); if (!fullname) { - upb_status_seterrliteral( + upb_status_seterrmsg( status, "Anonymous defs cannot be added to a symtab"); goto err; } @@ -297,7 +297,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, return true; oom_err: - upb_status_seterrliteral(status, "out of memory"); + upb_status_seterrmsg(status, "out of memory"); err: { // For defs the user passed in, we need to donate the refs back. For defs // we dup'd, we need to just unref them. diff --git a/upb/symtab.h b/upb/symtab.h index 01d5cd0..c260671 100644 --- a/upb/symtab.h +++ b/upb/symtab.h @@ -34,12 +34,7 @@ class upb::SymbolTable { public: // Returns a new symbol table with a single ref owned by "owner." // Returns NULL if memory allocation failed. - static SymbolTable* New(const void* owner); - - // Though not declared as such in C++, upb::RefCounted is the base of - // SymbolTable and we can upcast to it. - RefCounted* Upcast(); - const RefCounted* Upcast() const; + static reffed_ptr<SymbolTable> New(); // Functionality from upb::RefCounted. bool IsFrozen() const; @@ -56,16 +51,13 @@ class upb::SymbolTable { // types within this message are searched, then within the parent, on up // to the root namespace). // - // If a def is found, the caller owns one ref on the returned def, owned by - // owner. Otherwise returns NULL. - const Def* Resolve(const char* base, const char* sym, - const void* owner) const; + // If not found, returns NULL. + reffed_ptr<const Def> Resolve(const char* base, const char* sym) const; - // Finds an entry in the symbol table with this exact name. If a def is - // found, the caller owns one ref on the returned def, owned by owner. - // Otherwise returns NULL. - const Def* Lookup(const char *sym, const void *owner) const; - const MessageDef* LookupMessage(const char *sym, const void *owner) const; + // Finds an entry in the symbol table with this exact name. If not found, + // returns NULL. + reffed_ptr<const Def> Lookup(const char *sym) const; + reffed_ptr<const MessageDef> LookupMessage(const char *sym) const; // Gets an array of pointers to all currently active defs in this symtab. // The caller owns the returned array (which is of length *n) as well as a @@ -112,7 +104,7 @@ class upb::SymbolTable { } private: - UPB_DISALLOW_POD_OPS(SymbolTable); + UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable); #else struct upb_symtab { @@ -150,14 +142,32 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, // C++ inline wrappers. namespace upb { -inline SymbolTable* SymbolTable::New(const void* owner) { - return upb_symtab_new(owner); -} -inline RefCounted* SymbolTable::Upcast() { return UPB_UPCAST(this); } -inline const RefCounted* SymbolTable::Upcast() const { - return UPB_UPCAST(this); +template<> +class Pointer<SymbolTable> { + public: + explicit Pointer(SymbolTable* ptr) : ptr_(ptr) {} + operator SymbolTable*() { return ptr_; } + operator RefCounted*() { return UPB_UPCAST(ptr_); } + private: + SymbolTable* ptr_; +}; + +template<> +class Pointer<const SymbolTable> { + public: + explicit Pointer(const SymbolTable* ptr) : ptr_(ptr) {} + operator const SymbolTable*() { return ptr_; } + operator const RefCounted*() { return UPB_UPCAST(ptr_); } + private: + const SymbolTable* ptr_; +}; + +inline reffed_ptr<SymbolTable> SymbolTable::New() { + upb_symtab *s = upb_symtab_new(&s); + return reffed_ptr<SymbolTable>(s, &s); } + inline bool SymbolTable::IsFrozen() const { return upb_symtab_isfrozen(this); } @@ -174,17 +184,19 @@ inline void SymbolTable::CheckRef(const void *owner) const { upb_symtab_checkref(this, owner); } -inline const Def* SymbolTable::Resolve( - const char* base, const char* sym, const void* owner) const { - return upb_symtab_resolve(this, base, sym, owner); +inline reffed_ptr<const Def> SymbolTable::Resolve( + const char* base, const char* sym) const { + const upb_def *def = upb_symtab_resolve(this, base, sym, &def); + return reffed_ptr<const Def>(def, &def); } -inline const Def* SymbolTable::Lookup( - const char *sym, const void *owner) const { - return upb_symtab_lookup(this, sym, owner); +inline reffed_ptr<const Def> SymbolTable::Lookup(const char *sym) const { + const upb_def *def = upb_symtab_lookup(this, sym, &def); + return reffed_ptr<const Def>(def, &def); } -inline const MessageDef* SymbolTable::LookupMessage( - const char *sym, const void *owner) const { - return upb_symtab_lookupmsg(this, sym, owner); +inline reffed_ptr<const MessageDef> SymbolTable::LookupMessage( + const char *sym) const { + const upb_msgdef *m = upb_symtab_lookupmsg(this, sym, &m); + return reffed_ptr<const MessageDef>(m, &m); } inline const Def** SymbolTable::GetDefs( upb_deftype_t type, const void *owner, int *n) const { diff --git a/upb/table.int.h b/upb/table.int.h index 0ed37ba..109f76b 100644 --- a/upb/table.int.h +++ b/upb/table.int.h @@ -38,13 +38,14 @@ extern "C" { // clients calling table accessors are correctly typed without having to have // an explosion of accessors. typedef enum { - UPB_CTYPE_INT32 = 1, - UPB_CTYPE_INT64 = 2, - UPB_CTYPE_UINT32 = 3, - UPB_CTYPE_UINT64 = 4, - UPB_CTYPE_BOOL = 5, - UPB_CTYPE_CSTR = 6, - UPB_CTYPE_PTR = 7, + UPB_CTYPE_INT32 = 1, + UPB_CTYPE_INT64 = 2, + UPB_CTYPE_UINT32 = 3, + UPB_CTYPE_UINT64 = 4, + UPB_CTYPE_BOOL = 5, + UPB_CTYPE_CSTR = 6, + UPB_CTYPE_PTR = 7, + UPB_CTYPE_CONSTPTR = 8, } upb_ctype_t; typedef union { @@ -129,13 +130,14 @@ UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t ctype) { return val.val.membername; \ } -FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32); -FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64); -FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32); -FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64); -FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL); -FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR); -FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR); +FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32); +FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64); +FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32); +FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64); +FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL); +FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR); +FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR); +FUNCS(constptr, constptr, const void*, UPB_CTYPE_CONSTPTR); #undef FUNCS @@ -14,118 +14,69 @@ #include <string.h> #include "upb/upb.h" -// Like vasprintf (which allocates a string large enough for the result), but -// uses *buf (which can be NULL) as a starting point and reallocates it only if -// the new value will not fit. "size" is updated to reflect the allocated size -// of the buffer. Starts writing at the given offset into the string; bytes -// preceding this offset are unaffected. Returns the new length of the string, -// or -1 on memory allocation failure. -static int upb_vrprintf(char **buf, size_t *size, size_t ofs, - const char *fmt, va_list args) { - // Try once without reallocating. We have to va_copy because we might have - // to call vsnprintf again. - uint32_t len = *size - ofs; - va_list args_copy; - va_copy(args_copy, args); - uint32_t true_len = vsnprintf(*buf + ofs, len, fmt, args_copy); - va_end(args_copy); - - // Resize to be the correct size. - if (true_len >= len) { - // Need to print again, because some characters were truncated. vsnprintf - // will not write the entire string unless you give it space to store the - // NULL terminator also. - *size = (ofs + true_len + 1); - char *newbuf = realloc(*buf, *size); - if (!newbuf) return -1; - vsnprintf(newbuf + ofs, true_len + 1, fmt, args); - *buf = newbuf; - } - return true_len; +bool upb_dumptostderr(void *closure, const upb_status* status) { + UPB_UNUSED(closure); + fprintf(stderr, "%s\n", upb_status_errmsg(status)); + return false; } -void upb_status_init(upb_status *status) { - status->buf = NULL; - status->bufsize = 0; - upb_status_clear(status); +// Guarantee null-termination and provide ellipsis truncation. +// It may be tempting to "optimize" this by initializing these final +// four bytes up-front and then being careful never to overwrite them, +// this is safer and simpler. +static void nullz(upb_status *status) { + const char *ellipsis = "..."; + size_t len = strlen(ellipsis); + assert(sizeof(status->msg) > len); + memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len); } -void upb_status_uninit(upb_status *status) { - free(status->buf); +void upb_status_clear(upb_status *status) { + upb_status blank = UPB_STATUS_INIT; + upb_status_copy(status, &blank); } -bool upb_ok(const upb_status *status) { return !status->error; } -bool upb_eof(const upb_status *status) { return status->eof_; } +bool upb_ok(const upb_status *status) { return status->ok_; } -void upb_status_seterrf(upb_status *status, const char *msg, ...) { - if (!status) return; - status->error = true; - status->space = NULL; - va_list args; - va_start(args, msg); - upb_vrprintf(&status->buf, &status->bufsize, 0, msg, args); - va_end(args); - status->str = status->buf; +upb_errorspace *upb_status_errspace(const upb_status *status) { + return status->error_space_; } -void upb_status_seterrliteral(upb_status *status, const char *msg) { - if (!status) return; - status->error = true; - status->str = msg; - status->space = NULL; -} +int upb_status_errcode(const upb_status *status) { return status->code_; } -void upb_status_copy(upb_status *to, const upb_status *from) { - if (!to) return; - to->error = from->error; - to->eof_ = from->eof_; - to->code = from->code; - to->space = from->space; - if (from->str == from->buf) { - if (to->bufsize < from->bufsize) { - to->bufsize = from->bufsize; - to->buf = realloc(to->buf, to->bufsize); - } - memcpy(to->buf, from->buf, from->bufsize); - to->str = to->buf; - } else { - to->str = from->str; - } +const char *upb_status_errmsg(const upb_status *status) { return status->msg; } + +void upb_status_seterrmsg(upb_status *status, const char *msg) { + if (!status) return; + status->ok_ = false; + strncpy(status->msg, msg, sizeof(status->msg)); + nullz(status); } -const char *upb_status_getstr(const upb_status *_status) { - // Function is logically const but can modify internal state to materialize - // the string. - upb_status *status = (upb_status*)_status; - if (status->str == NULL && status->space) { - if (status->space->code_to_string) { - status->space->code_to_string(status->code, status->buf, status->bufsize); - status->str = status->buf; - } else { - upb_status_seterrf(status, "No message, error space=%s, code=%d\n", - status->space->name, status->code); - } - } - return status->str; +void upb_status_seterrf(upb_status *status, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + upb_status_vseterrf(status, fmt, args); + va_end(args); } -void upb_status_clear(upb_status *status) { +void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) { if (!status) return; - status->error = false; - status->eof_ = false; - status->code = 0; - status->space = NULL; - status->str = NULL; + status->ok_ = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + nullz(status); } -void upb_status_setcode(upb_status *status, upb_errorspace *space, int code) { +void upb_status_seterrcode(upb_status *status, upb_errorspace *space, + int code) { if (!status) return; - status->code = code; - status->space = space; - status->str = NULL; + status->ok_ = false; + status->error_space_ = space; + status->code_ = code; + space->set_message(status, code); } -void upb_status_seteof(upb_status *status) { - if (!status) return; - status->eof_ = true; +void upb_status_copy(upb_status *to, const upb_status *from) { + if (!to) return; + *to = *from; } @@ -13,6 +13,8 @@ #ifndef UPB_H_ #define UPB_H_ +#include <assert.h> +#include <stdarg.h> #include <stdbool.h> #include <stddef.h> @@ -33,17 +35,33 @@ #endif #ifdef UPB_CXX11 -#define UPB_DISALLOW_POD_OPS(class_name) \ - class_name() = delete; \ - ~class_name() = delete; \ +#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ class_name(const class_name&) = delete; \ void operator=(const class_name&) = delete; +#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \ + class_name() = delete; \ + ~class_name() = delete; \ + /* Friend Pointer<T> so it can access base class. */ \ + friend class Pointer<full_class_name>; \ + friend class Pointer<const full_class_name>; \ + UPB_DISALLOW_COPY_AND_ASSIGN(class_name) #else -#define UPB_DISALLOW_POD_OPS(class_name) \ - class_name(); \ - ~class_name(); \ +#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ class_name(const class_name&); \ void operator=(const class_name&); +#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \ + class_name(); \ + ~class_name(); \ + /* Friend Pointer<T> so it can access base class. */ \ + friend class Pointer<full_class_name>; \ + friend class Pointer<const full_class_name>; \ + UPB_DISALLOW_COPY_AND_ASSIGN(class_name) +#endif + +#ifdef __cplusplus +#define UPB_PRIVATE_FOR_CPP private: +#else +#define UPB_PRIVATE_FOR_CPP #endif #ifdef __GNUC__ @@ -79,24 +97,134 @@ // Example: // upb::Def* def = <...>; // upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def); -// -// For upcasts, see the Upcast() method in the types themselves. namespace upb { // Casts to a direct subclass. The caller must know that cast is correct; an -// incorrect cast will throw an assertion failure. +// incorrect cast will throw an assertion failure in debug mode. template<class To, class From> To down_cast(From* f); // Casts to a direct subclass. If the class does not actually match the given // subtype, returns NULL. template<class To, class From> To dyn_cast(From* f); +// Pointer<T> is a simple wrapper around a T*. It is only constructed for +// upcast() below, and its sole purpose is to be implicitly convertable to T* or +// pointers to base classes, just as a pointer would be in regular C++ if the +// inheritance were directly expressed as C++ inheritance. +template <class T> class Pointer; + +// Casts to any base class, or the type itself (ie. can be a no-op). +template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); } } #endif +/* upb::reffed_ptr ************************************************************/ + +#ifdef __cplusplus + +#include <algorithm> // For std::swap(). + +namespace upb { + +// Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a +// ref on whatever object it points to (if any). +template <class T> class reffed_ptr { + public: + reffed_ptr() : ptr_(NULL) {} + + // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. + template <class U> + reffed_ptr(U* val, const void* ref_donor = NULL) + : ptr_(upb::upcast(val)) { + if (ref_donor) { + assert(ptr_); + ptr_->DonateRef(ref_donor, this); + } else if (ptr_) { + ptr_->Ref(this); + } + } + + template <class U> + reffed_ptr(const reffed_ptr<U>& other) + : ptr_(upb::upcast(other.get())) { + if (ptr_) ptr_->Ref(this); + } + + ~reffed_ptr() { if (ptr_) ptr_->Unref(this); } + + template <class U> + reffed_ptr& operator=(const reffed_ptr<U>& other) { + reset(other.get()); + return *this; + } + + reffed_ptr& operator=(const reffed_ptr& other) { + reset(other.get()); + return *this; + } + + // TODO(haberman): add C++11 move construction/assignment for greater + // efficiency. + + void swap(reffed_ptr& other) { + if (ptr_ == other.ptr_) { + return; + } + + if (ptr_) ptr_->DonateRef(this, &other); + if (other.ptr_) other.ptr_->DonateRef(&other, this); + std::swap(ptr_, other.ptr_); + } + + T& operator*() const { + assert(ptr_); + return *ptr_; + } + + T* operator->() const { + assert(ptr_); + return ptr_; + } + + T* get() const { return ptr_; } + + // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. + template <class U> + void reset(U* ptr = NULL, const void* ref_donor = NULL) { + reffed_ptr(ptr, ref_donor).swap(*this); + } + + template <class U> + reffed_ptr<U> down_cast() { + return reffed_ptr<U>(upb::down_cast<U*>(get())); + } + + template <class U> + reffed_ptr<U> dyn_cast() { + return reffed_ptr<U>(upb::dyn_cast<U*>(get())); + } + + // Plain release() is unsafe; if we were the only owner, it would leak the + // object. Instead we provide this: + T* ReleaseTo(const void* new_owner) { + T* ret = NULL; + ptr_->DonateRef(this, new_owner); + std::swap(ret, ptr_); + return ret; + } + + private: + T* ptr_; +}; + +} // namespace upb + +#endif // __cplusplus + + /* upb::Status ****************************************************************/ #ifdef __cplusplus @@ -107,75 +235,91 @@ struct upb_status; typedef struct upb_status upb_status; #endif -typedef enum { - UPB_OK, // The operation completed successfully. - UPB_SUSPENDED, // The operation was suspended and may be resumed later. - UPB_ERROR, // An error occurred. -} upb_success_t; +// The maximum length of an error message before it will get truncated. +#define UPB_STATUS_MAX_MESSAGE 128 + +// An error callback function is used to report errors from some component. +// The function can return "true" to indicate that the component should try +// to recover and proceed, but this is not always possible. +typedef bool upb_errcb_t(void *closure, const upb_status* status); typedef struct { const char *name; - // Writes a NULL-terminated string to "buf" containing an error message for - // the given error code, returning false if the message was too large to fit. - bool (*code_to_string)(int code, char *buf, size_t len); + // Should the error message in the status object according to this code. + void (*set_message)(upb_status* status, int code); } upb_errorspace; #ifdef __cplusplus +typedef upb_errorspace ErrorSpace; + +// Object representing a success or failure status. +// It owns no resources and allocates no memory, so it should work +// even in OOM situations. class upb::Status { public: - typedef upb_success_t Success; - Status(); - ~Status(); + // Returns true if there is no error. bool ok() const; - bool eof() const; - const char *GetString() const; - void SetEof(); - void SetErrorLiteral(const char* msg); + // Optional error space and code, useful if the caller wants to + // programmatically check the specific kind of error. + ErrorSpace* error_space(); + int code() const; + + const char *error_message() const; + + // The error message will be truncated if it is longer than + // UPB_STATUS_MAX_MESSAGE-4. + void SetErrorMessage(const char* msg); + void SetFormattedErrorMessage(const char* fmt, ...); + + // If there is no error message already, this will use the ErrorSpace to + // populate the error message for this code. The caller can still call + // SetErrorMessage() to give a more specific message. + void SetErrorCode(ErrorSpace* space, int code); + + // Resets the status to a successful state with no message. void Clear(); + void CopyFrom(const Status& other); + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Status); #else struct upb_status { #endif - bool error; - bool eof_; + bool ok_; // Specific status code defined by some error space (optional). - int code; - upb_errorspace *space; + int code_; + upb_errorspace *error_space_; - // Error message (optional). - const char *str; // NULL when no message is present. NULL-terminated. - char *buf; // Owned by the status. - size_t bufsize; + // Error message; NULL-terminated. + char msg[UPB_STATUS_MAX_MESSAGE]; }; -#define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0} +#define UPB_STATUS_INIT {true, 0, NULL, {0}} #ifdef __cplusplus extern "C" { #endif -void upb_status_init(upb_status *status); -void upb_status_uninit(upb_status *status); - +// The returned string is invalidated by any other call into the status. +const char *upb_status_errmsg(const upb_status *status); bool upb_ok(const upb_status *status); -bool upb_eof(const upb_status *status); +upb_errorspace *upb_status_errspace(const upb_status *status); +int upb_status_errcode(const upb_status *status); // Any of the functions that write to a status object allow status to be NULL, // to support use cases where the function's caller does not care about the // status message. void upb_status_clear(upb_status *status); -void upb_status_seterrliteral(upb_status *status, const char *msg); -void upb_status_seterrf(upb_status *status, const char *msg, ...); -void upb_status_setcode(upb_status *status, upb_errorspace *space, int code); -void upb_status_seteof(upb_status *status); -// The returned string is invalidated by any other call into the status. -const char *upb_status_getstr(const upb_status *status); +void upb_status_seterrmsg(upb_status *status, const char *msg); +void upb_status_seterrf(upb_status *status, const char *fmt, ...); +void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args); +void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code); void upb_status_copy(upb_status *to, const upb_status *from); #ifdef __cplusplus @@ -184,16 +328,27 @@ void upb_status_copy(upb_status *to, const upb_status *from); namespace upb { // C++ Wrappers -inline Status::Status() { upb_status_init(this); } -inline Status::~Status() { upb_status_uninit(this); } +inline Status::Status() { Clear(); } inline bool Status::ok() const { return upb_ok(this); } -inline bool Status::eof() const { return upb_eof(this); } -inline const char *Status::GetString() const { return upb_status_getstr(this); } -inline void Status::SetEof() { upb_status_seteof(this); } -inline void Status::SetErrorLiteral(const char* msg) { - upb_status_seterrliteral(this, msg); +inline const char* Status::error_message() const { + return upb_status_errmsg(this); +} +inline void Status::SetErrorMessage(const char* msg) { + upb_status_seterrmsg(this, msg); +} +inline void Status::SetFormattedErrorMessage(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_status_vseterrf(this, fmt, args); + va_end(args); +} +inline void Status::SetErrorCode(ErrorSpace* space, int code) { + upb_status_seterrcode(this, space, code); } inline void Status::Clear() { upb_status_clear(this); } +inline void Status::CopyFrom(const Status& other) { + upb_status_copy(this, &other); +} } // namespace upb |