diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 2f1afca12c..a78ba0d375 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -3617,6 +3617,7 @@ static bool upb_JsonDecoder_Decode(jsondec* const d, upb_Message* const msg, bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, const upb_MessageDef* m, const upb_DefPool* symtab, int options, upb_Arena* arena, upb_Status* status) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); jsondec d; if (size == 0) return true; @@ -4916,6 +4917,8 @@ void UPB_PRIVATE(_upb_Arena_SwapOut)(upb_Arena* des, const upb_Arena* src) { bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTable* mini_table, const upb_MiniTableField* f, upb_Message* map_entry_message, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(map_entry_message)); + // TODO: use a variant of upb_MiniTable_GetSubMessageTable() here. const upb_MiniTable* map_entry_mini_table = upb_MiniTableSub_Message( mini_table->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]); @@ -4967,6 +4970,7 @@ upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i) { } void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); char* data = upb_Array_MutableDataPtr(arr); const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); UPB_ASSERT(i < arr->UPB_PRIVATE(size)); @@ -4974,6 +4978,7 @@ void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { } bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); UPB_ASSERT(arena); if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( arr, arr->UPB_PRIVATE(size) + 1, arena)) { @@ -4985,6 +4990,7 @@ bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); char* data = upb_Array_MutableDataPtr(arr); memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); @@ -4992,6 +4998,7 @@ void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); UPB_ASSERT(arena); UPB_ASSERT(i <= arr->UPB_PRIVATE(size)); UPB_ASSERT(count + arr->UPB_PRIVATE(size) >= count); @@ -5009,6 +5016,7 @@ bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, * |------------|XXXXXXXX|--------| */ void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); const size_t end = i + count; UPB_ASSERT(i <= end); UPB_ASSERT(end <= arr->UPB_PRIVATE(size)); @@ -5017,6 +5025,7 @@ void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { } bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); const size_t oldsize = arr->UPB_PRIVATE(size); if (UPB_UNLIKELY( !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena))) { @@ -5050,6 +5059,20 @@ bool UPB_PRIVATE(_upb_Array_Realloc)(upb_Array* array, size_t min_capacity, return true; } +void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m) { + if (upb_Array_IsFrozen(arr)) return; + UPB_PRIVATE(_upb_Array_ShallowFreeze)(arr); + + if (m) { + const size_t size = upb_Array_Size(arr); + + for (size_t i = 0; i < size; i++) { + upb_MessageValue val = upb_Array_Get(arr, i); + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + #include #include @@ -5079,6 +5102,7 @@ const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( } +#include #include @@ -5177,6 +5201,20 @@ upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { return ret; } +void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m) { + if (upb_Map_IsFrozen(map)) return; + UPB_PRIVATE(_upb_Map_ShallowFreeze)(map); + + if (m) { + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + + while (upb_Map_Next(map, &key, &val, &iter)) { + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + // EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { @@ -5186,6 +5224,7 @@ upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { upb_strtable_init(&map->table, 4, a); map->key_size = key_size; map->val_size = value_size; + map->UPB_PRIVATE(is_frozen) = false; return map; } @@ -5349,22 +5388,24 @@ upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) { bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, size_t len, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, len, arena)) return false; - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); memcpy(UPB_PTR_AT(in, in->unknown_end, char), data, len); in->unknown_end += len; return true; } void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = msg->internal; + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in) { in->unknown_end = message_overhead; } } const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in) { *len = in->unknown_end - message_overhead; return (char*)(in + 1); @@ -5375,7 +5416,8 @@ const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { } void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { - upb_Message_Internal* in = msg->internal; + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); const char* internal_unknown_end = UPB_PTR_AT(in, in->unknown_end, char); #ifndef NDEBUG @@ -5399,6 +5441,73 @@ size_t upb_Message_ExtensionCount(const upb_Message* msg) { return count; } +void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { + if (upb_Message_IsFrozen(msg)) return; + UPB_PRIVATE(_upb_Message_ShallowFreeze)(msg); + + // Base Fields. + const size_t field_count = upb_MiniTable_FieldCount(m); + + for (size_t i = 0; i < field_count; i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + const upb_MiniTable* m2 = upb_MiniTable_SubMessage(m, f); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = upb_Message_GetMutableArray(msg, f); + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: { + upb_Map* map = upb_Message_GetMutableMap(msg, f); + if (map) { + const upb_MiniTableField* f2 = upb_MiniTable_MapValue(m2); + const upb_MiniTable* m3 = upb_MiniTable_SubMessage(m2, f2); + upb_Map_Freeze(map, m3); + } + break; + } + case kUpb_FieldMode_Scalar: { + if (m2) { + upb_Message* msg2 = upb_Message_GetMutableMessage(msg, f); + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } + } + + // Extensions. + size_t ext_count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count); + + for (size_t i = 0; i < ext_count; i++) { + const upb_MiniTableExtension* e = ext[i].ext; + const upb_MiniTableField* f = &e->UPB_PRIVATE(field); + const upb_MiniTable* m2 = upb_MiniTableExtension_GetSubMessage(e); + + upb_MessageValue val; + memcpy(&val, &ext[i].data, sizeof(upb_MessageValue)); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = (upb_Array*)val.array_val; + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: + UPB_UNREACHABLE(); // Maps cannot be extensions. + break; + case kUpb_FieldMode_Scalar: + if (upb_MiniTableField_IsSubMessage(f)) { + upb_Message* msg2 = (upb_Message*)val.msg_val; + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } +} + #include @@ -8406,6 +8515,7 @@ upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, const upb_MiniTable* m, const upb_ExtensionRegistry* extreg, int options, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); upb_Decoder decoder; unsigned depth = (unsigned)options >> 16; @@ -11105,7 +11215,7 @@ const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( const upb_Extension* UPB_PRIVATE(_upb_Message_Getexts)( const struct upb_Message* msg, size_t* count) { - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in) { *count = (in->size - in->ext_begin) / sizeof(upb_Extension); return UPB_PTR_AT(in, in->ext_begin, void); @@ -11121,7 +11231,7 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( if (ext) return ext; if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, sizeof(upb_Extension), a)) return NULL; - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); in->ext_begin -= sizeof(upb_Extension); ext = UPB_PTR_AT(in, in->ext_begin, void); memset(ext, 0, sizeof(upb_Extension)); @@ -11144,7 +11254,7 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, upb_Arena* a) { const size_t overhead = sizeof(upb_Message_Internal); - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (!in) { // No internal data, allocate from scratch. size_t size = UPB_MAX(128, upb_Log2CeilingSize(need + overhead)); @@ -11154,7 +11264,7 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, in->size = size; in->unknown_end = overhead; in->ext_begin = size; - msg->internal = in; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); } else if (in->ext_begin - in->unknown_end < need) { // Internal data is too small, reallocate. size_t new_size = upb_Log2CeilingSize(in->size + need); @@ -11170,7 +11280,7 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, } in->ext_begin = new_ext_begin; in->size = new_size; - msg->internal = in; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); } UPB_ASSERT(in->ext_begin - in->unknown_end >= need); diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index e0c162adf6..f7cdf741ab 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -842,13 +842,21 @@ struct upb_Array { // 2 maps to elem size 8 // 3 maps to elem size 16 // - // Bit #2 contains the frozen/immutable flag (currently unimplemented). + // Bit #2 contains the frozen/immutable flag. uintptr_t UPB_ONLYBITS(data); size_t UPB_ONLYBITS(size); // The number of elements in the array. size_t UPB_PRIVATE(capacity); // Allocated storage. Measured in elements. }; +UPB_INLINE void UPB_PRIVATE(_upb_Array_ShallowFreeze)(struct upb_Array* arr) { + arr->UPB_ONLYBITS(data) |= _UPB_ARRAY_MASK_IMM; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Array_IsFrozen)(const struct upb_Array* arr) { + return (arr->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_IMM) != 0; +} + UPB_INLINE void UPB_PRIVATE(_upb_Array_SetTaggedPtr)(struct upb_Array* array, void* data, size_t lg2) { UPB_ASSERT(lg2 != 1); @@ -898,6 +906,7 @@ bool UPB_PRIVATE(_upb_Array_Realloc)(struct upb_Array* array, size_t min_size, UPB_INLINE bool UPB_PRIVATE(_upb_Array_Reserve)(struct upb_Array* array, size_t size, upb_Arena* arena) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Array_IsFrozen)(array)); if (array->UPB_PRIVATE(capacity) < size) return UPB_PRIVATE(_upb_Array_Realloc)(array, size, arena); return true; @@ -906,6 +915,7 @@ UPB_INLINE bool UPB_PRIVATE(_upb_Array_Reserve)(struct upb_Array* array, // Resize without initializing new elements. UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)( struct upb_Array* array, size_t size, upb_Arena* arena) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Array_IsFrozen)(array)); UPB_ASSERT(size <= array->UPB_ONLYBITS(size) || arena); // Allow NULL arena when shrinking. if (!UPB_PRIVATE(_upb_Array_Reserve)(array, size, arena)) return false; @@ -919,6 +929,7 @@ UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)( UPB_INLINE void UPB_PRIVATE(_upb_Array_Set)(struct upb_Array* array, size_t i, const void* data, size_t elem_size) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Array_IsFrozen)(array)); UPB_ASSERT(i < array->UPB_ONLYBITS(size)); UPB_ASSERT(elem_size == 1U << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array)); char* arr_data = (char*)UPB_PRIVATE(_upb_Array_MutableDataPtr)(array); @@ -981,218 +992,6 @@ typedef union { #endif /* UPB_MESSAGE_VALUE_H_ */ -// Must be last. - -typedef struct upb_Array upb_Array; - -#ifdef __cplusplus -extern "C" { -#endif - -// Creates a new array on the given arena that holds elements of this type. -UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); - -// Returns the number of elements in the array. -UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr) { - return UPB_PRIVATE(_upb_Array_Size)(arr); -} - -// Returns the given element, which must be within the array's current size. -UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); - -// Returns a mutating pointer to the given element, which must be within the -// array's current size. -UPB_API upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i); - -// Sets the given element, which must be within the array's current size. -UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); - -// Appends an element to the array. Returns false on allocation failure. -UPB_API bool upb_Array_Append(upb_Array* array, upb_MessageValue val, - upb_Arena* arena); - -// Moves elements within the array using memmove(). -// Like memmove(), the source and destination elements may be overlapping. -UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); - -// Inserts one or more empty elements into the array. -// Existing elements are shifted right. -// The new elements have undefined state and must be set with `upb_Array_Set()`. -// REQUIRES: `i <= upb_Array_Size(arr)` -UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); - -// Deletes one or more elements from the array. -// Existing elements are shifted left. -// REQUIRES: `i + count <= upb_Array_Size(arr)` -UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count); - -// Changes the size of a vector. New elements are initialized to NULL/0. -// Returns false on allocation failure. -UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); - -// Returns pointer to array data. -UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr) { - return UPB_PRIVATE(_upb_Array_DataPtr)(arr); -} - -// Returns mutable pointer to array data. -UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr) { - return UPB_PRIVATE(_upb_Array_MutableDataPtr)(arr); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MESSAGE_ARRAY_H_ */ - -#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_ -#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_ - -#include -#include -#include - - -#ifndef UPB_BASE_INTERNAL_ENDIAN_H_ -#define UPB_BASE_INTERNAL_ENDIAN_H_ - -#include - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -UPB_INLINE bool upb_IsLittleEndian(void) { - const int x = 1; - return *(char*)&x == 1; -} - -UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) { - if (upb_IsLittleEndian()) return val; - - return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); -} - -UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) { - if (upb_IsLittleEndian()) return val; - - const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32; - const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32)); - return hi | lo; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */ - -#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_ -#define UPB_MESSAGE_INTERNAL_EXTENSION_H_ - - -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_ -#define UPB_MESSAGE_INTERNAL_MESSAGE_H_ - -#include -#include - - -#ifndef UPB_MINI_TABLE_MESSAGE_H_ -#define UPB_MINI_TABLE_MESSAGE_H_ - - -#ifndef UPB_MINI_TABLE_ENUM_H_ -#define UPB_MINI_TABLE_ENUM_H_ - -#include - - -#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_ -#define UPB_MINI_TABLE_INTERNAL_ENUM_H_ - -#include - -// Must be last. - -struct upb_MiniTableEnum { - uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask. - uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield. - uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow. -}; - -#ifdef __cplusplus -extern "C" { -#endif - -UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)( - const struct upb_MiniTableEnum* e, uint32_t val) { - if (UPB_LIKELY(val < 64)) { - const uint64_t mask = - e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32); - const uint64_t bit = 1ULL << val; - return (mask & bit) != 0; - } - if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) { - const uint32_t mask = e->UPB_PRIVATE(data)[val / 32]; - const uint32_t bit = 1ULL << (val % 32); - return (mask & bit) != 0; - } - - // OPT: binary search long lists? - const uint32_t* start = - &e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32]; - const uint32_t* limit = &e->UPB_PRIVATE( - data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)]; - for (const uint32_t* p = start; p < limit; p++) { - if (*p == val) return true; - } - return false; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */ - -// Must be last - -typedef struct upb_MiniTableEnum upb_MiniTableEnum; - -#ifdef __cplusplus -extern "C" { -#endif - -// Validates enum value against range defined by enum mini table. -UPB_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, - uint32_t val) { - return UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)(e, val); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MINI_TABLE_ENUM_H_ */ - #ifndef UPB_MINI_TABLE_FIELD_H_ #define UPB_MINI_TABLE_FIELD_H_ @@ -1547,6 +1346,86 @@ upb_MiniTableField_Type(const upb_MiniTableField* f) { #endif /* UPB_MINI_TABLE_FIELD_H_ */ +#ifndef UPB_MINI_TABLE_MESSAGE_H_ +#define UPB_MINI_TABLE_MESSAGE_H_ + + +#ifndef UPB_MINI_TABLE_ENUM_H_ +#define UPB_MINI_TABLE_ENUM_H_ + +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_ +#define UPB_MINI_TABLE_INTERNAL_ENUM_H_ + +#include + +// Must be last. + +struct upb_MiniTableEnum { + uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask. + uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield. + uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow. +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)( + const struct upb_MiniTableEnum* e, uint32_t val) { + if (UPB_LIKELY(val < 64)) { + const uint64_t mask = + e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32); + const uint64_t bit = 1ULL << val; + return (mask & bit) != 0; + } + if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) { + const uint32_t mask = e->UPB_PRIVATE(data)[val / 32]; + const uint32_t bit = 1ULL << (val % 32); + return (mask & bit) != 0; + } + + // OPT: binary search long lists? + const uint32_t* start = + &e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32]; + const uint32_t* limit = &e->UPB_PRIVATE( + data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */ + +// Must be last + +typedef struct upb_MiniTableEnum upb_MiniTableEnum; + +#ifdef __cplusplus +extern "C" { +#endif + +// Validates enum value against range defined by enum mini table. +UPB_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, + uint32_t val) { + return UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)(e, val); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_ENUM_H_ */ + #ifndef UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ #define UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ @@ -1691,6 +1570,15 @@ UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE( return UPB_PRIVATE(_upb_MiniTable_IsEmpty)(ret) ? NULL : ret; } +UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(_upb_MiniTable_SubMessage)( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + if (UPB_PRIVATE(_upb_MiniTableField_CType)(f) != kUpb_CType_Message) { + return NULL; + } + return UPB_PRIVATE(_upb_MiniTableSub_Message)( + m->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]); +} + UPB_INLINE const struct upb_MiniTableEnum* UPB_PRIVATE( _upb_MiniTable_GetSubEnumTable)(const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { @@ -1761,12 +1649,19 @@ UPB_API_INLINE int upb_MiniTable_FieldCount(const upb_MiniTable* m) { return UPB_PRIVATE(_upb_MiniTable_FieldCount)(m); } +// DEPRECATED: use upb_MiniTable_SubMessage() instead // Returns the MiniTable for a message field, NULL if the field is unlinked. UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( const upb_MiniTable* m, const upb_MiniTableField* f) { return UPB_PRIVATE(_upb_MiniTable_GetSubMessageTable)(m, f); } +// Returns the MiniTable for a message field if it is a submessage. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage( + const upb_MiniTable* m, const upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTable_SubMessage)(m, f); +} + // Returns the MiniTableEnum for a message field, NULL if the field is unlinked. UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( const upb_MiniTable* m, const upb_MiniTableField* f) { @@ -1820,6 +1715,148 @@ bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, #endif /* UPB_MINI_TABLE_MESSAGE_H_ */ +// Must be last. + +typedef struct upb_Array upb_Array; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new array on the given arena that holds elements of this type. +UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +// Returns the number of elements in the array. +UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_Size)(arr); +} + +// Returns the given element, which must be within the array's current size. +UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +// Returns a mutating pointer to the given element, which must be within the +// array's current size. +UPB_API upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i); + +// Sets the given element, which must be within the array's current size. +UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +// Appends an element to the array. Returns false on allocation failure. +UPB_API bool upb_Array_Append(upb_Array* array, upb_MessageValue val, + upb_Arena* arena); + +// Moves elements within the array using memmove(). +// Like memmove(), the source and destination elements may be overlapping. +UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +// Inserts one or more empty elements into the array. +// Existing elements are shifted right. +// The new elements have undefined state and must be set with `upb_Array_Set()`. +// REQUIRES: `i <= upb_Array_Size(arr)` +UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); + +// Deletes one or more elements from the array. +// Existing elements are shifted left. +// REQUIRES: `i + count <= upb_Array_Size(arr)` +UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +// Changes the size of a vector. New elements are initialized to NULL/0. +// Returns false on allocation failure. +UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); + +// Returns pointer to array data. +UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_DataPtr)(arr); +} + +// Returns mutable pointer to array data. +UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_MutableDataPtr)(arr); +} + +// Mark an array and all of its descendents as frozen/immutable. +// If the array elements are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m); + +// Returns whether an array has been frozen. +UPB_API_INLINE bool upb_Array_IsFrozen(const upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_IsFrozen)(arr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_ARRAY_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_ +#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_ + +#include +#include +#include + + +#ifndef UPB_BASE_INTERNAL_ENDIAN_H_ +#define UPB_BASE_INTERNAL_ENDIAN_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool upb_IsLittleEndian(void) { + const int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) { + if (upb_IsLittleEndian()) return val; + + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} + +UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) { + if (upb_IsLittleEndian()) return val; + + const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32; + const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32)); + return hi | lo; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_ +#define UPB_MESSAGE_INTERNAL_EXTENSION_H_ + + +/* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ + +#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_ +#define UPB_MESSAGE_INTERNAL_MESSAGE_H_ + +#include +#include + + // Must be last. #ifdef __cplusplus @@ -2340,6 +2377,7 @@ struct upb_Map { // Strings are represented as '0' because they must be handled specially. char key_size; char val_size; + bool UPB_PRIVATE(is_frozen); upb_strtable table; }; @@ -2348,6 +2386,14 @@ struct upb_Map { extern "C" { #endif +UPB_INLINE void UPB_PRIVATE(_upb_Map_ShallowFreeze)(struct upb_Map* map) { + map->UPB_PRIVATE(is_frozen) = true; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Map_IsFrozen)(const struct upb_Map* map) { + return map->UPB_PRIVATE(is_frozen); +} + // Converting between internal table representation and user values. // // _upb_map_tokey() and _upb_map_fromkey() are inverses. @@ -2405,11 +2451,15 @@ UPB_INLINE void* _upb_map_next(const struct upb_Map* map, size_t* iter) { } UPB_INLINE void _upb_Map_Clear(struct upb_Map* map) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Map_IsFrozen)(map)); + upb_strtable_clear(&map->table); } UPB_INLINE bool _upb_Map_Delete(struct upb_Map* map, const void* key, size_t key_size, upb_value* val) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Map_IsFrozen)(map)); + upb_StringView k = _upb_map_tokey(key, key_size); return upb_strtable_remove2(&map->table, k.data, k.size, val); } @@ -2429,6 +2479,8 @@ UPB_INLINE upb_MapInsertStatus _upb_Map_Insert(struct upb_Map* map, const void* key, size_t key_size, void* val, size_t val_size, upb_Arena* a) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Map_IsFrozen)(map)); + upb_StringView strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; if (!_upb_map_tovalue(val, val_size, &tabval, a)) { @@ -2516,13 +2568,44 @@ UPB_INLINE struct upb_Message* UPB_PRIVATE( #ifndef UPB_MESSAGE_INTERNAL_TYPES_H_ #define UPB_MESSAGE_INTERNAL_TYPES_H_ +#include + +// Must be last. + +#define UPB_OPAQUE(x) x##_opaque + struct upb_Message { union { - struct upb_Message_Internal* internal; + uintptr_t UPB_OPAQUE(internal); // tagged pointer, low bit == frozen double d; // Forces same size for 32-bit/64-bit builds }; }; +UPB_INLINE void UPB_PRIVATE(_upb_Message_ShallowFreeze)( + struct upb_Message* msg) { + msg->UPB_OPAQUE(internal) |= 1ULL; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Message_IsFrozen)( + const struct upb_Message* msg) { + return (msg->UPB_OPAQUE(internal) & 1ULL) != 0; +} + +UPB_INLINE struct upb_Message_Internal* UPB_PRIVATE(_upb_Message_GetInternal)( + const struct upb_Message* msg) { + const uintptr_t tmp = msg->UPB_OPAQUE(internal) & ~1ULL; + return (struct upb_Message_Internal*)tmp; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetInternal)( + struct upb_Message* msg, struct upb_Message_Internal* internal) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); + msg->UPB_OPAQUE(internal) = (uintptr_t)internal; +} + +#undef UPB_OPAQUE + + #endif /* UPB_MESSAGE_INTERNAL_TYPES_H_ */ // Must be last. @@ -2772,6 +2855,7 @@ UPB_INLINE void _upb_Message_GetExtensionField( UPB_INLINE void _upb_Message_SetNonExtensionField( struct upb_Message* msg, const upb_MiniTableField* field, const void* val) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); UPB_PRIVATE(_upb_Message_SetPresence)(msg, field); UPB_PRIVATE(_upb_MiniTableField_DataCopy) @@ -2781,6 +2865,7 @@ UPB_INLINE void _upb_Message_SetNonExtensionField( UPB_INLINE bool _upb_Message_SetExtensionField( struct upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val, upb_Arena* a) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); UPB_ASSERT(a); upb_Extension* ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, mt_ext, a); @@ -2792,11 +2877,13 @@ UPB_INLINE bool _upb_Message_SetExtensionField( UPB_INLINE void UPB_PRIVATE(_upb_Message_Clear)(struct upb_Message* msg, const upb_MiniTable* m) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); memset(msg, 0, m->UPB_PRIVATE(size)); } UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearBaseField)( struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { UPB_PRIVATE(_upb_Message_ClearHasbit)(msg, f); } else if (upb_MiniTableField_IsInOneof(f)) { @@ -2811,7 +2898,8 @@ UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearBaseField)( UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearExtension)( struct upb_Message* msg, const upb_MiniTableExtension* e) { - upb_Message_Internal* in = msg->internal; + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (!in) return; const upb_Extension* base = UPB_PTR_AT(in, in->ext_begin, upb_Extension); upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e); @@ -2961,6 +3049,16 @@ UPB_API bool upb_MapIterator_Done(const upb_Map* map, size_t iter); UPB_API upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); UPB_API upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); +// Mark a map and all of its descendents as frozen/immutable. +// If the map values are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m); + +// Returns whether a map has been frozen. +UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map) { + return UPB_PRIVATE(_upb_Map_IsFrozen)(map); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -3004,6 +3102,14 @@ void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); // Returns the number of extensions present in this message. size_t upb_Message_ExtensionCount(const upb_Message* msg); +// Mark a message and all of its descendents as frozen/immutable. +UPB_API void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m); + +// Returns whether a message has been frozen. +UPB_API_INLINE bool upb_Message_IsFrozen(const upb_Message* msg) { + return UPB_PRIVATE(_upb_Message_IsFrozen)(msg); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -3398,6 +3504,11 @@ UPB_API_INLINE const upb_Message* upb_Message_GetMessage( return upb_TaggedMessagePtr_GetNonEmptyMessage(tagged); } +UPB_API_INLINE upb_Message* upb_Message_GetMutableMessage( + upb_Message* msg, const upb_MiniTableField* field) { + return (upb_Message*)upb_Message_GetMessage(msg, field, NULL); +} + // For internal use only; users cannot set tagged messages because only the // parser and the message copier are allowed to directly create an empty // message. diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 80ddfb60d8..f105474eee 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -3131,6 +3131,7 @@ static bool upb_JsonDecoder_Decode(jsondec* const d, upb_Message* const msg, bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, const upb_MessageDef* m, const upb_DefPool* symtab, int options, upb_Arena* arena, upb_Status* status) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); jsondec d; if (size == 0) return true; @@ -4430,6 +4431,8 @@ void UPB_PRIVATE(_upb_Arena_SwapOut)(upb_Arena* des, const upb_Arena* src) { bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTable* mini_table, const upb_MiniTableField* f, upb_Message* map_entry_message, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(map_entry_message)); + // TODO: use a variant of upb_MiniTable_GetSubMessageTable() here. const upb_MiniTable* map_entry_mini_table = upb_MiniTableSub_Message( mini_table->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]); @@ -4481,6 +4484,7 @@ upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i) { } void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); char* data = upb_Array_MutableDataPtr(arr); const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); UPB_ASSERT(i < arr->UPB_PRIVATE(size)); @@ -4488,6 +4492,7 @@ void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { } bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); UPB_ASSERT(arena); if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( arr, arr->UPB_PRIVATE(size) + 1, arena)) { @@ -4499,6 +4504,7 @@ bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); char* data = upb_Array_MutableDataPtr(arr); memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); @@ -4506,6 +4512,7 @@ void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); UPB_ASSERT(arena); UPB_ASSERT(i <= arr->UPB_PRIVATE(size)); UPB_ASSERT(count + arr->UPB_PRIVATE(size) >= count); @@ -4523,6 +4530,7 @@ bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, * |------------|XXXXXXXX|--------| */ void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); const size_t end = i + count; UPB_ASSERT(i <= end); UPB_ASSERT(end <= arr->UPB_PRIVATE(size)); @@ -4531,6 +4539,7 @@ void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { } bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); const size_t oldsize = arr->UPB_PRIVATE(size); if (UPB_UNLIKELY( !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena))) { @@ -4564,6 +4573,20 @@ bool UPB_PRIVATE(_upb_Array_Realloc)(upb_Array* array, size_t min_capacity, return true; } +void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m) { + if (upb_Array_IsFrozen(arr)) return; + UPB_PRIVATE(_upb_Array_ShallowFreeze)(arr); + + if (m) { + const size_t size = upb_Array_Size(arr); + + for (size_t i = 0; i < size; i++) { + upb_MessageValue val = upb_Array_Get(arr, i); + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + #include #include @@ -4593,6 +4616,7 @@ const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( } +#include #include @@ -4691,6 +4715,20 @@ upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { return ret; } +void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m) { + if (upb_Map_IsFrozen(map)) return; + UPB_PRIVATE(_upb_Map_ShallowFreeze)(map); + + if (m) { + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + + while (upb_Map_Next(map, &key, &val, &iter)) { + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + // EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { @@ -4700,6 +4738,7 @@ upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { upb_strtable_init(&map->table, 4, a); map->key_size = key_size; map->val_size = value_size; + map->UPB_PRIVATE(is_frozen) = false; return map; } @@ -4863,22 +4902,24 @@ upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) { bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, size_t len, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, len, arena)) return false; - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); memcpy(UPB_PTR_AT(in, in->unknown_end, char), data, len); in->unknown_end += len; return true; } void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = msg->internal; + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in) { in->unknown_end = message_overhead; } } const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in) { *len = in->unknown_end - message_overhead; return (char*)(in + 1); @@ -4889,7 +4930,8 @@ const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { } void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { - upb_Message_Internal* in = msg->internal; + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); const char* internal_unknown_end = UPB_PTR_AT(in, in->unknown_end, char); #ifndef NDEBUG @@ -4913,6 +4955,73 @@ size_t upb_Message_ExtensionCount(const upb_Message* msg) { return count; } +void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { + if (upb_Message_IsFrozen(msg)) return; + UPB_PRIVATE(_upb_Message_ShallowFreeze)(msg); + + // Base Fields. + const size_t field_count = upb_MiniTable_FieldCount(m); + + for (size_t i = 0; i < field_count; i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + const upb_MiniTable* m2 = upb_MiniTable_SubMessage(m, f); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = upb_Message_GetMutableArray(msg, f); + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: { + upb_Map* map = upb_Message_GetMutableMap(msg, f); + if (map) { + const upb_MiniTableField* f2 = upb_MiniTable_MapValue(m2); + const upb_MiniTable* m3 = upb_MiniTable_SubMessage(m2, f2); + upb_Map_Freeze(map, m3); + } + break; + } + case kUpb_FieldMode_Scalar: { + if (m2) { + upb_Message* msg2 = upb_Message_GetMutableMessage(msg, f); + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } + } + + // Extensions. + size_t ext_count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count); + + for (size_t i = 0; i < ext_count; i++) { + const upb_MiniTableExtension* e = ext[i].ext; + const upb_MiniTableField* f = &e->UPB_PRIVATE(field); + const upb_MiniTable* m2 = upb_MiniTableExtension_GetSubMessage(e); + + upb_MessageValue val; + memcpy(&val, &ext[i].data, sizeof(upb_MessageValue)); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = (upb_Array*)val.array_val; + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: + UPB_UNREACHABLE(); // Maps cannot be extensions. + break; + case kUpb_FieldMode_Scalar: + if (upb_MiniTableField_IsSubMessage(f)) { + upb_Message* msg2 = (upb_Message*)val.msg_val; + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } +} + #include @@ -7920,6 +8029,7 @@ upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, const upb_MiniTable* m, const upb_ExtensionRegistry* extreg, int options, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); upb_Decoder decoder; unsigned depth = (unsigned)options >> 16; @@ -10619,7 +10729,7 @@ const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( const upb_Extension* UPB_PRIVATE(_upb_Message_Getexts)( const struct upb_Message* msg, size_t* count) { - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in) { *count = (in->size - in->ext_begin) / sizeof(upb_Extension); return UPB_PTR_AT(in, in->ext_begin, void); @@ -10635,7 +10745,7 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( if (ext) return ext; if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, sizeof(upb_Extension), a)) return NULL; - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); in->ext_begin -= sizeof(upb_Extension); ext = UPB_PTR_AT(in, in->ext_begin, void); memset(ext, 0, sizeof(upb_Extension)); @@ -10658,7 +10768,7 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, upb_Arena* a) { const size_t overhead = sizeof(upb_Message_Internal); - upb_Message_Internal* in = msg->internal; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (!in) { // No internal data, allocate from scratch. size_t size = UPB_MAX(128, upb_Log2CeilingSize(need + overhead)); @@ -10668,7 +10778,7 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, in->size = size; in->unknown_end = overhead; in->ext_begin = size; - msg->internal = in; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); } else if (in->ext_begin - in->unknown_end < need) { // Internal data is too small, reallocate. size_t new_size = upb_Log2CeilingSize(in->size + need); @@ -10684,7 +10794,7 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, } in->ext_begin = new_ext_begin; in->size = new_size; - msg->internal = in; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); } UPB_ASSERT(in->ext_begin - in->unknown_end >= need); diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 9fb3e47fb0..2a3633ed0d 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -844,13 +844,21 @@ struct upb_Array { // 2 maps to elem size 8 // 3 maps to elem size 16 // - // Bit #2 contains the frozen/immutable flag (currently unimplemented). + // Bit #2 contains the frozen/immutable flag. uintptr_t UPB_ONLYBITS(data); size_t UPB_ONLYBITS(size); // The number of elements in the array. size_t UPB_PRIVATE(capacity); // Allocated storage. Measured in elements. }; +UPB_INLINE void UPB_PRIVATE(_upb_Array_ShallowFreeze)(struct upb_Array* arr) { + arr->UPB_ONLYBITS(data) |= _UPB_ARRAY_MASK_IMM; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Array_IsFrozen)(const struct upb_Array* arr) { + return (arr->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_IMM) != 0; +} + UPB_INLINE void UPB_PRIVATE(_upb_Array_SetTaggedPtr)(struct upb_Array* array, void* data, size_t lg2) { UPB_ASSERT(lg2 != 1); @@ -900,6 +908,7 @@ bool UPB_PRIVATE(_upb_Array_Realloc)(struct upb_Array* array, size_t min_size, UPB_INLINE bool UPB_PRIVATE(_upb_Array_Reserve)(struct upb_Array* array, size_t size, upb_Arena* arena) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Array_IsFrozen)(array)); if (array->UPB_PRIVATE(capacity) < size) return UPB_PRIVATE(_upb_Array_Realloc)(array, size, arena); return true; @@ -908,6 +917,7 @@ UPB_INLINE bool UPB_PRIVATE(_upb_Array_Reserve)(struct upb_Array* array, // Resize without initializing new elements. UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)( struct upb_Array* array, size_t size, upb_Arena* arena) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Array_IsFrozen)(array)); UPB_ASSERT(size <= array->UPB_ONLYBITS(size) || arena); // Allow NULL arena when shrinking. if (!UPB_PRIVATE(_upb_Array_Reserve)(array, size, arena)) return false; @@ -921,6 +931,7 @@ UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)( UPB_INLINE void UPB_PRIVATE(_upb_Array_Set)(struct upb_Array* array, size_t i, const void* data, size_t elem_size) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Array_IsFrozen)(array)); UPB_ASSERT(i < array->UPB_ONLYBITS(size)); UPB_ASSERT(elem_size == 1U << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array)); char* arr_data = (char*)UPB_PRIVATE(_upb_Array_MutableDataPtr)(array); @@ -983,218 +994,6 @@ typedef union { #endif /* UPB_MESSAGE_VALUE_H_ */ -// Must be last. - -typedef struct upb_Array upb_Array; - -#ifdef __cplusplus -extern "C" { -#endif - -// Creates a new array on the given arena that holds elements of this type. -UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); - -// Returns the number of elements in the array. -UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr) { - return UPB_PRIVATE(_upb_Array_Size)(arr); -} - -// Returns the given element, which must be within the array's current size. -UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); - -// Returns a mutating pointer to the given element, which must be within the -// array's current size. -UPB_API upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i); - -// Sets the given element, which must be within the array's current size. -UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); - -// Appends an element to the array. Returns false on allocation failure. -UPB_API bool upb_Array_Append(upb_Array* array, upb_MessageValue val, - upb_Arena* arena); - -// Moves elements within the array using memmove(). -// Like memmove(), the source and destination elements may be overlapping. -UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); - -// Inserts one or more empty elements into the array. -// Existing elements are shifted right. -// The new elements have undefined state and must be set with `upb_Array_Set()`. -// REQUIRES: `i <= upb_Array_Size(arr)` -UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); - -// Deletes one or more elements from the array. -// Existing elements are shifted left. -// REQUIRES: `i + count <= upb_Array_Size(arr)` -UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count); - -// Changes the size of a vector. New elements are initialized to NULL/0. -// Returns false on allocation failure. -UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); - -// Returns pointer to array data. -UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr) { - return UPB_PRIVATE(_upb_Array_DataPtr)(arr); -} - -// Returns mutable pointer to array data. -UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr) { - return UPB_PRIVATE(_upb_Array_MutableDataPtr)(arr); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MESSAGE_ARRAY_H_ */ - -#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_ -#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_ - -#include -#include -#include - - -#ifndef UPB_BASE_INTERNAL_ENDIAN_H_ -#define UPB_BASE_INTERNAL_ENDIAN_H_ - -#include - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -UPB_INLINE bool upb_IsLittleEndian(void) { - const int x = 1; - return *(char*)&x == 1; -} - -UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) { - if (upb_IsLittleEndian()) return val; - - return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); -} - -UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) { - if (upb_IsLittleEndian()) return val; - - const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32; - const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32)); - return hi | lo; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */ - -#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_ -#define UPB_MESSAGE_INTERNAL_EXTENSION_H_ - - -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_ -#define UPB_MESSAGE_INTERNAL_MESSAGE_H_ - -#include -#include - - -#ifndef UPB_MINI_TABLE_MESSAGE_H_ -#define UPB_MINI_TABLE_MESSAGE_H_ - - -#ifndef UPB_MINI_TABLE_ENUM_H_ -#define UPB_MINI_TABLE_ENUM_H_ - -#include - - -#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_ -#define UPB_MINI_TABLE_INTERNAL_ENUM_H_ - -#include - -// Must be last. - -struct upb_MiniTableEnum { - uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask. - uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield. - uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow. -}; - -#ifdef __cplusplus -extern "C" { -#endif - -UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)( - const struct upb_MiniTableEnum* e, uint32_t val) { - if (UPB_LIKELY(val < 64)) { - const uint64_t mask = - e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32); - const uint64_t bit = 1ULL << val; - return (mask & bit) != 0; - } - if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) { - const uint32_t mask = e->UPB_PRIVATE(data)[val / 32]; - const uint32_t bit = 1ULL << (val % 32); - return (mask & bit) != 0; - } - - // OPT: binary search long lists? - const uint32_t* start = - &e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32]; - const uint32_t* limit = &e->UPB_PRIVATE( - data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)]; - for (const uint32_t* p = start; p < limit; p++) { - if (*p == val) return true; - } - return false; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */ - -// Must be last - -typedef struct upb_MiniTableEnum upb_MiniTableEnum; - -#ifdef __cplusplus -extern "C" { -#endif - -// Validates enum value against range defined by enum mini table. -UPB_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, - uint32_t val) { - return UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)(e, val); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MINI_TABLE_ENUM_H_ */ - #ifndef UPB_MINI_TABLE_FIELD_H_ #define UPB_MINI_TABLE_FIELD_H_ @@ -1549,6 +1348,86 @@ upb_MiniTableField_Type(const upb_MiniTableField* f) { #endif /* UPB_MINI_TABLE_FIELD_H_ */ +#ifndef UPB_MINI_TABLE_MESSAGE_H_ +#define UPB_MINI_TABLE_MESSAGE_H_ + + +#ifndef UPB_MINI_TABLE_ENUM_H_ +#define UPB_MINI_TABLE_ENUM_H_ + +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_ +#define UPB_MINI_TABLE_INTERNAL_ENUM_H_ + +#include + +// Must be last. + +struct upb_MiniTableEnum { + uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask. + uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield. + uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow. +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)( + const struct upb_MiniTableEnum* e, uint32_t val) { + if (UPB_LIKELY(val < 64)) { + const uint64_t mask = + e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32); + const uint64_t bit = 1ULL << val; + return (mask & bit) != 0; + } + if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) { + const uint32_t mask = e->UPB_PRIVATE(data)[val / 32]; + const uint32_t bit = 1ULL << (val % 32); + return (mask & bit) != 0; + } + + // OPT: binary search long lists? + const uint32_t* start = + &e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32]; + const uint32_t* limit = &e->UPB_PRIVATE( + data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */ + +// Must be last + +typedef struct upb_MiniTableEnum upb_MiniTableEnum; + +#ifdef __cplusplus +extern "C" { +#endif + +// Validates enum value against range defined by enum mini table. +UPB_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, + uint32_t val) { + return UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)(e, val); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_ENUM_H_ */ + #ifndef UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ #define UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ @@ -1693,6 +1572,15 @@ UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE( return UPB_PRIVATE(_upb_MiniTable_IsEmpty)(ret) ? NULL : ret; } +UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(_upb_MiniTable_SubMessage)( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + if (UPB_PRIVATE(_upb_MiniTableField_CType)(f) != kUpb_CType_Message) { + return NULL; + } + return UPB_PRIVATE(_upb_MiniTableSub_Message)( + m->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]); +} + UPB_INLINE const struct upb_MiniTableEnum* UPB_PRIVATE( _upb_MiniTable_GetSubEnumTable)(const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { @@ -1763,12 +1651,19 @@ UPB_API_INLINE int upb_MiniTable_FieldCount(const upb_MiniTable* m) { return UPB_PRIVATE(_upb_MiniTable_FieldCount)(m); } +// DEPRECATED: use upb_MiniTable_SubMessage() instead // Returns the MiniTable for a message field, NULL if the field is unlinked. UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( const upb_MiniTable* m, const upb_MiniTableField* f) { return UPB_PRIVATE(_upb_MiniTable_GetSubMessageTable)(m, f); } +// Returns the MiniTable for a message field if it is a submessage. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage( + const upb_MiniTable* m, const upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTable_SubMessage)(m, f); +} + // Returns the MiniTableEnum for a message field, NULL if the field is unlinked. UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( const upb_MiniTable* m, const upb_MiniTableField* f) { @@ -1822,6 +1717,148 @@ bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, #endif /* UPB_MINI_TABLE_MESSAGE_H_ */ +// Must be last. + +typedef struct upb_Array upb_Array; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new array on the given arena that holds elements of this type. +UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +// Returns the number of elements in the array. +UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_Size)(arr); +} + +// Returns the given element, which must be within the array's current size. +UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +// Returns a mutating pointer to the given element, which must be within the +// array's current size. +UPB_API upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i); + +// Sets the given element, which must be within the array's current size. +UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +// Appends an element to the array. Returns false on allocation failure. +UPB_API bool upb_Array_Append(upb_Array* array, upb_MessageValue val, + upb_Arena* arena); + +// Moves elements within the array using memmove(). +// Like memmove(), the source and destination elements may be overlapping. +UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +// Inserts one or more empty elements into the array. +// Existing elements are shifted right. +// The new elements have undefined state and must be set with `upb_Array_Set()`. +// REQUIRES: `i <= upb_Array_Size(arr)` +UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); + +// Deletes one or more elements from the array. +// Existing elements are shifted left. +// REQUIRES: `i + count <= upb_Array_Size(arr)` +UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +// Changes the size of a vector. New elements are initialized to NULL/0. +// Returns false on allocation failure. +UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); + +// Returns pointer to array data. +UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_DataPtr)(arr); +} + +// Returns mutable pointer to array data. +UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_MutableDataPtr)(arr); +} + +// Mark an array and all of its descendents as frozen/immutable. +// If the array elements are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m); + +// Returns whether an array has been frozen. +UPB_API_INLINE bool upb_Array_IsFrozen(const upb_Array* arr) { + return UPB_PRIVATE(_upb_Array_IsFrozen)(arr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_ARRAY_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_ +#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_ + +#include +#include +#include + + +#ifndef UPB_BASE_INTERNAL_ENDIAN_H_ +#define UPB_BASE_INTERNAL_ENDIAN_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool upb_IsLittleEndian(void) { + const int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) { + if (upb_IsLittleEndian()) return val; + + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} + +UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) { + if (upb_IsLittleEndian()) return val; + + const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32; + const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32)); + return hi | lo; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_ +#define UPB_MESSAGE_INTERNAL_EXTENSION_H_ + + +/* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ + +#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_ +#define UPB_MESSAGE_INTERNAL_MESSAGE_H_ + +#include +#include + + // Must be last. #ifdef __cplusplus @@ -2342,6 +2379,7 @@ struct upb_Map { // Strings are represented as '0' because they must be handled specially. char key_size; char val_size; + bool UPB_PRIVATE(is_frozen); upb_strtable table; }; @@ -2350,6 +2388,14 @@ struct upb_Map { extern "C" { #endif +UPB_INLINE void UPB_PRIVATE(_upb_Map_ShallowFreeze)(struct upb_Map* map) { + map->UPB_PRIVATE(is_frozen) = true; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Map_IsFrozen)(const struct upb_Map* map) { + return map->UPB_PRIVATE(is_frozen); +} + // Converting between internal table representation and user values. // // _upb_map_tokey() and _upb_map_fromkey() are inverses. @@ -2407,11 +2453,15 @@ UPB_INLINE void* _upb_map_next(const struct upb_Map* map, size_t* iter) { } UPB_INLINE void _upb_Map_Clear(struct upb_Map* map) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Map_IsFrozen)(map)); + upb_strtable_clear(&map->table); } UPB_INLINE bool _upb_Map_Delete(struct upb_Map* map, const void* key, size_t key_size, upb_value* val) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Map_IsFrozen)(map)); + upb_StringView k = _upb_map_tokey(key, key_size); return upb_strtable_remove2(&map->table, k.data, k.size, val); } @@ -2431,6 +2481,8 @@ UPB_INLINE upb_MapInsertStatus _upb_Map_Insert(struct upb_Map* map, const void* key, size_t key_size, void* val, size_t val_size, upb_Arena* a) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Map_IsFrozen)(map)); + upb_StringView strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; if (!_upb_map_tovalue(val, val_size, &tabval, a)) { @@ -2518,13 +2570,44 @@ UPB_INLINE struct upb_Message* UPB_PRIVATE( #ifndef UPB_MESSAGE_INTERNAL_TYPES_H_ #define UPB_MESSAGE_INTERNAL_TYPES_H_ +#include + +// Must be last. + +#define UPB_OPAQUE(x) x##_opaque + struct upb_Message { union { - struct upb_Message_Internal* internal; + uintptr_t UPB_OPAQUE(internal); // tagged pointer, low bit == frozen double d; // Forces same size for 32-bit/64-bit builds }; }; +UPB_INLINE void UPB_PRIVATE(_upb_Message_ShallowFreeze)( + struct upb_Message* msg) { + msg->UPB_OPAQUE(internal) |= 1ULL; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Message_IsFrozen)( + const struct upb_Message* msg) { + return (msg->UPB_OPAQUE(internal) & 1ULL) != 0; +} + +UPB_INLINE struct upb_Message_Internal* UPB_PRIVATE(_upb_Message_GetInternal)( + const struct upb_Message* msg) { + const uintptr_t tmp = msg->UPB_OPAQUE(internal) & ~1ULL; + return (struct upb_Message_Internal*)tmp; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetInternal)( + struct upb_Message* msg, struct upb_Message_Internal* internal) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); + msg->UPB_OPAQUE(internal) = (uintptr_t)internal; +} + +#undef UPB_OPAQUE + + #endif /* UPB_MESSAGE_INTERNAL_TYPES_H_ */ // Must be last. @@ -2774,6 +2857,7 @@ UPB_INLINE void _upb_Message_GetExtensionField( UPB_INLINE void _upb_Message_SetNonExtensionField( struct upb_Message* msg, const upb_MiniTableField* field, const void* val) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); UPB_PRIVATE(_upb_Message_SetPresence)(msg, field); UPB_PRIVATE(_upb_MiniTableField_DataCopy) @@ -2783,6 +2867,7 @@ UPB_INLINE void _upb_Message_SetNonExtensionField( UPB_INLINE bool _upb_Message_SetExtensionField( struct upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val, upb_Arena* a) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); UPB_ASSERT(a); upb_Extension* ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, mt_ext, a); @@ -2794,11 +2879,13 @@ UPB_INLINE bool _upb_Message_SetExtensionField( UPB_INLINE void UPB_PRIVATE(_upb_Message_Clear)(struct upb_Message* msg, const upb_MiniTable* m) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); memset(msg, 0, m->UPB_PRIVATE(size)); } UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearBaseField)( struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { UPB_PRIVATE(_upb_Message_ClearHasbit)(msg, f); } else if (upb_MiniTableField_IsInOneof(f)) { @@ -2813,7 +2900,8 @@ UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearBaseField)( UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearExtension)( struct upb_Message* msg, const upb_MiniTableExtension* e) { - upb_Message_Internal* in = msg->internal; + UPB_ASSERT(!UPB_PRIVATE(_upb_Message_IsFrozen)(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (!in) return; const upb_Extension* base = UPB_PTR_AT(in, in->ext_begin, upb_Extension); upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e); @@ -2963,6 +3051,16 @@ UPB_API bool upb_MapIterator_Done(const upb_Map* map, size_t iter); UPB_API upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); UPB_API upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); +// Mark a map and all of its descendents as frozen/immutable. +// If the map values are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m); + +// Returns whether a map has been frozen. +UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map) { + return UPB_PRIVATE(_upb_Map_IsFrozen)(map); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -3006,6 +3104,14 @@ void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); // Returns the number of extensions present in this message. size_t upb_Message_ExtensionCount(const upb_Message* msg); +// Mark a message and all of its descendents as frozen/immutable. +UPB_API void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m); + +// Returns whether a message has been frozen. +UPB_API_INLINE bool upb_Message_IsFrozen(const upb_Message* msg) { + return UPB_PRIVATE(_upb_Message_IsFrozen)(msg); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -3400,6 +3506,11 @@ UPB_API_INLINE const upb_Message* upb_Message_GetMessage( return upb_TaggedMessagePtr_GetNonEmptyMessage(tagged); } +UPB_API_INLINE upb_Message* upb_Message_GetMutableMessage( + upb_Message* msg, const upb_MiniTableField* field) { + return (upb_Message*)upb_Message_GetMessage(msg, field, NULL); +} + // For internal use only; users cannot set tagged messages because only the // parser and the message copier are allowed to directly create an empty // message.