google-protobuf 4.34.2 → 4.35.0.rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -558,15 +558,7 @@ Error, UINTPTR_MAX is undefined
558
558
  // }
559
559
  // }
560
560
 
561
- #if defined(__GNUC__) && !defined(__clang__)
562
- // GCC can't handle mismatched retain attributes in the same section:
563
- // https://github.com/protocolbuffers/protobuf/issues/26385
564
- // To work around this, we retain all linker array elements, even though this
565
- // effectively disables tree-shaking of unused extensions when using GCC.
566
- #define UPB_LINKARR_ATTR UPB_RETAIN
567
- #else
568
561
  #define UPB_LINKARR_ATTR
569
- #endif
570
562
 
571
563
  #define UPB_LINKARR_SENTINEL UPB_RETAIN __attribute__((weak, used))
572
564
 
@@ -1970,7 +1962,7 @@ const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init = {
1970
1962
 
1971
1963
  const upb_MiniTableEnum google__protobuf__Edition_enum_init = {
1972
1964
  64,
1973
- 10,
1965
+ 11,
1974
1966
  {
1975
1967
  0x7,
1976
1968
  0x0,
@@ -1979,6 +1971,7 @@ const upb_MiniTableEnum google__protobuf__Edition_enum_init = {
1979
1971
  0x3e7,
1980
1972
  0x3e8,
1981
1973
  0x3e9,
1974
+ 0x3ea,
1982
1975
  0x270f,
1983
1976
  0x1869d,
1984
1977
  0x1869e,
@@ -2000,7 +1993,7 @@ const upb_MiniTableEnum google__protobuf__FeatureSet__EnforceNamingStyle_enum_in
2000
1993
  64,
2001
1994
  0,
2002
1995
  {
2003
- 0x7,
1996
+ 0xf,
2004
1997
  0x0,
2005
1998
  },
2006
1999
  };
@@ -2346,10 +2339,15 @@ static int log2ceil(uint64_t v) {
2346
2339
  return UPB_MIN(UPB_MAXARRSIZE, ret);
2347
2340
  }
2348
2341
 
2349
- /* A type to represent the lookup key of either a strtable or an inttable. */
2342
+ /* A type to represent the lookup key of either a strtable, inttable or
2343
+ * exttable. */
2350
2344
  typedef union {
2351
2345
  uintptr_t num;
2352
2346
  upb_StringView str;
2347
+ struct {
2348
+ const void* ptr;
2349
+ uint32_t ext_num;
2350
+ } ext;
2353
2351
  } lookupkey_t;
2354
2352
 
2355
2353
  static lookupkey_t strkey2(const char* str, size_t len) {
@@ -2358,16 +2356,24 @@ static lookupkey_t strkey2(const char* str, size_t len) {
2358
2356
 
2359
2357
  static lookupkey_t intkey(uintptr_t key) { return (lookupkey_t){.num = key}; }
2360
2358
 
2361
- typedef uint32_t hashfunc_t(upb_key key);
2362
- typedef bool eqlfunc_t(upb_key k1, lookupkey_t k2);
2359
+ static lookupkey_t extkey(const void* ptr, uint32_t ext_num) {
2360
+ return (lookupkey_t){.ext = {ptr, ext_num}};
2361
+ }
2362
+
2363
+ // Conceptually the hash and equal functions should only take the key, not the
2364
+ // value, but the extension table stores part of its logical key in the value
2365
+ // slot. This is a sign that we have outgrown the original architecture.
2366
+ typedef uint32_t hashfunc_t(upb_key key, upb_value val);
2367
+ typedef bool eqlfunc_t(upb_key k1, upb_value v1, lookupkey_t k2);
2363
2368
 
2364
2369
  /* Base table (shared code) ***************************************************/
2365
2370
 
2366
2371
  static uint32_t upb_inthash(uintptr_t key) {
2372
+ UPB_STATIC_ASSERT(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8,
2373
+ "Pointers don't fit");
2367
2374
  if (sizeof(uintptr_t) == 8) {
2368
2375
  return (uint32_t)key ^ (uint32_t)(key >> 32);
2369
2376
  } else {
2370
- UPB_ASSERT(sizeof(uintptr_t) == 4);
2371
2377
  return (uint32_t)key;
2372
2378
  }
2373
2379
  }
@@ -2428,7 +2434,7 @@ static const upb_tabent* findentry(const upb_table* t, lookupkey_t key,
2428
2434
  e = upb_getentry(t, hash);
2429
2435
  if (upb_tabent_isempty(e)) return NULL;
2430
2436
  while (1) {
2431
- if (eql(e->key, key)) return e;
2437
+ if (eql(e->key, e->val, key)) return e;
2432
2438
  if ((e = e->next) == NULL) return NULL;
2433
2439
  }
2434
2440
  }
@@ -2468,7 +2474,8 @@ static void insert(upb_table* t, lookupkey_t key, upb_key tabkey, upb_value val,
2468
2474
  /* Collision. */
2469
2475
  upb_tabent* new_e = emptyent(t, mainpos_e);
2470
2476
  /* Head of collider's chain. */
2471
- upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key));
2477
+ upb_tabent* chain =
2478
+ getentry_mutable(t, hashfunc(mainpos_e->key, mainpos_e->val));
2472
2479
  if (chain == mainpos_e) {
2473
2480
  /* Existing ent is in its main position (it has the same hash as us, and
2474
2481
  * is the head of our chain). Insert to new ent and append to this chain.
@@ -2499,7 +2506,7 @@ static bool rm(upb_table* t, lookupkey_t key, upb_value* val, uint32_t hash,
2499
2506
  eqlfunc_t* eql) {
2500
2507
  upb_tabent* chain = getentry_mutable(t, hash);
2501
2508
  if (upb_tabent_isempty(chain)) return false;
2502
- if (eql(chain->key, key)) {
2509
+ if (eql(chain->key, chain->val, key)) {
2503
2510
  /* Element to remove is at the head of its chain. */
2504
2511
  t->count--;
2505
2512
  if (val) *val = chain->val;
@@ -2514,7 +2521,7 @@ static bool rm(upb_table* t, lookupkey_t key, upb_value* val, uint32_t hash,
2514
2521
  } else {
2515
2522
  /* Element to remove is either in a non-head position or not in the
2516
2523
  * table. */
2517
- while (chain->next && !eql(chain->next->key, key)) {
2524
+ while (chain->next && !eql(chain->next->key, chain->next->val, key)) {
2518
2525
  chain = (upb_tabent*)chain->next;
2519
2526
  }
2520
2527
  if (chain->next) {
@@ -2713,11 +2720,13 @@ static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) {
2713
2720
  return _upb_Hash(p, n, _upb_Seed());
2714
2721
  }
2715
2722
 
2716
- static uint32_t strhash(upb_key key) {
2723
+ static uint32_t strhash(upb_key key, upb_value val) {
2724
+ UPB_UNUSED(val);
2717
2725
  return _upb_Hash_NoSeed(key.str->data, key.str->size);
2718
2726
  }
2719
2727
 
2720
- static bool streql(upb_key k1, lookupkey_t k2) {
2728
+ static bool streql(upb_key k1, upb_value v1, lookupkey_t k2) {
2729
+ UPB_UNUSED(v1);
2721
2730
  const upb_SizePrefixString* k1s = k1.str;
2722
2731
  const upb_StringView k2s = k2.str;
2723
2732
  return k1s->size == k2s.size &&
@@ -2881,6 +2890,96 @@ void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v) {
2881
2890
  t->t.entries[iter].val = v;
2882
2891
  }
2883
2892
 
2893
+ /* upb_exttable ***************************************************************/
2894
+
2895
+ static uint32_t _upb_exttable_hash(const void* ptr, uint32_t ext_num) {
2896
+ uint64_t a = (uintptr_t)ptr;
2897
+ uint64_t b = ext_num;
2898
+ return (uint32_t)WyhashMix(a ^ kWyhashSalt[1], b ^ _upb_Seed());
2899
+ }
2900
+
2901
+ static uint32_t exthash(upb_key key, upb_value val) {
2902
+ const void* ptr = (const void*)key.num;
2903
+ uint32_t ext_num = *(const uint32_t*)upb_value_getconstptr(val);
2904
+ return _upb_exttable_hash(ptr, ext_num);
2905
+ }
2906
+
2907
+ static bool exteql(upb_key k1, upb_value v1, lookupkey_t k2) {
2908
+ if ((const void*)k1.num == k2.ext.ptr) {
2909
+ uint32_t ext_num1 = *(const uint32_t*)upb_value_getconstptr(v1);
2910
+ return ext_num1 == k2.ext.ext_num;
2911
+ }
2912
+ return false;
2913
+ }
2914
+
2915
+ bool upb_exttable_init(upb_exttable* t, size_t expected_size, upb_Arena* a) {
2916
+ int size_lg2 = upb_Log2Ceiling(_upb_entries_needed_for(expected_size));
2917
+ return init(&t->t, size_lg2, a);
2918
+ }
2919
+
2920
+ void upb_exttable_clear(upb_exttable* t) {
2921
+ size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent);
2922
+ t->t.count = 0;
2923
+ memset((char*)t->t.entries, 0, bytes);
2924
+ }
2925
+
2926
+ bool upb_exttable_resize(upb_exttable* t, size_t size_lg2, upb_Arena* a) {
2927
+ upb_exttable new_table;
2928
+ if (!init(&new_table.t, size_lg2, a)) return false;
2929
+
2930
+ size_t i;
2931
+ for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
2932
+ const upb_tabent* e = &t->t.entries[i];
2933
+ uint32_t hash = exthash(e->key, e->val);
2934
+ uint32_t ext_num = *(const uint32_t*)upb_value_getconstptr(e->val);
2935
+ lookupkey_t lookupkey = extkey((const void*)e->key.num, ext_num);
2936
+ insert(&new_table.t, lookupkey, e->key, e->val, hash, &exthash, &exteql);
2937
+ }
2938
+
2939
+ *t = new_table;
2940
+ return true;
2941
+ }
2942
+
2943
+ bool upb_exttable_insert(upb_exttable* t, const void* k, const uint32_t* v,
2944
+ upb_Arena* a) {
2945
+ UPB_ASSERT(k != NULL);
2946
+ UPB_ASSERT(v != NULL);
2947
+ UPB_ASSERT(*v != 0);
2948
+
2949
+ if (isfull(&t->t)) {
2950
+ if (!upb_exttable_resize(t, _upb_log2_table_size(&t->t) + 1, a)) {
2951
+ return false;
2952
+ }
2953
+ }
2954
+
2955
+ lookupkey_t lookupkey = extkey(k, *v);
2956
+ upb_key key = {.num = (uintptr_t)k};
2957
+ upb_value val = upb_value_constptr(v);
2958
+ uint32_t hash = _upb_exttable_hash(k, *v);
2959
+ insert(&t->t, lookupkey, key, val, hash, &exthash, &exteql);
2960
+ return true;
2961
+ }
2962
+
2963
+ const uint32_t* upb_exttable_lookup(const upb_exttable* t, const void* k,
2964
+ uint32_t ext_number) {
2965
+ uint32_t hash = _upb_exttable_hash(k, ext_number);
2966
+ upb_value val;
2967
+ if (lookup(&t->t, extkey(k, ext_number), &val, hash, &exteql)) {
2968
+ return (const uint32_t*)upb_value_getconstptr(val);
2969
+ }
2970
+ return NULL;
2971
+ }
2972
+
2973
+ const uint32_t* upb_exttable_remove(upb_exttable* t, const void* k,
2974
+ uint32_t ext_number) {
2975
+ uint32_t hash = _upb_exttable_hash(k, ext_number);
2976
+ upb_value val;
2977
+ if (rm(&t->t, extkey(k, ext_number), &val, hash, &exteql)) {
2978
+ return (const uint32_t*)upb_value_getconstptr(val);
2979
+ }
2980
+ return NULL;
2981
+ }
2982
+
2884
2983
  /* upb_inttable ***************************************************************/
2885
2984
 
2886
2985
  /* For inttables we use a hybrid structure where small keys are kept in an
@@ -2895,9 +2994,15 @@ static uint32_t presence_mask_arr_size(uint32_t array_size) {
2895
2994
  return (array_size + 7) / 8; // sizeof(uint8_t) is always 1.
2896
2995
  }
2897
2996
 
2898
- static uint32_t inthash(upb_key key) { return upb_inthash(key.num); }
2997
+ static uint32_t inthash(upb_key key, upb_value val) {
2998
+ UPB_UNUSED(val);
2999
+ return upb_inthash(key.num);
3000
+ }
2899
3001
 
2900
- static bool inteql(upb_key k1, lookupkey_t k2) { return k1.num == k2.num; }
3002
+ static bool inteql(upb_key k1, upb_value v1, lookupkey_t k2) {
3003
+ UPB_UNUSED(v1);
3004
+ return k1.num == k2.num;
3005
+ }
2901
3006
 
2902
3007
  static upb_value* mutable_array(upb_inttable* t) {
2903
3008
  return (upb_value*)t->array;
@@ -3003,8 +3108,8 @@ bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val,
3003
3108
 
3004
3109
  for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
3005
3110
  const upb_tabent* e = &t->t.entries[i];
3006
- insert(&new_table, intkey(e->key.num), e->key, e->val, inthash(e->key),
3007
- &inthash, &inteql);
3111
+ insert(&new_table, intkey(e->key.num), e->key, e->val,
3112
+ inthash(e->key, e->val), &inthash, &inteql);
3008
3113
  }
3009
3114
 
3010
3115
  UPB_ASSERT(t->t.count == new_table.count);
@@ -5663,24 +5768,33 @@ static int GetLocaleRadix(char *data, size_t capacity) {
5663
5768
  const int size = snprintf(temp, sizeof(temp), "%.1f", 1.5);
5664
5769
  UPB_ASSERT(temp[0] == '1');
5665
5770
  UPB_ASSERT(temp[size - 1] == '5');
5666
- UPB_ASSERT(size < capacity);
5771
+ if (size < capacity) {
5772
+ return 0;
5773
+ }
5667
5774
  temp[size - 1] = '\0';
5668
- strcpy(data, temp + 1);
5775
+ strncpy(data, temp + 1, size);
5669
5776
  return size - 2;
5670
5777
  }
5671
5778
 
5672
5779
  // Populates a string identical to *input except that the character pointed to
5673
5780
  // by pos (which should be '.') is replaced with the locale-specific radix.
5674
5781
 
5675
- static void LocalizeRadix(const char *input, const char *pos, char *output) {
5782
+ static void LocalizeRadix(const char *input, const char *pos, char *output,
5783
+ int output_size) {
5676
5784
  const int len1 = pos - input;
5677
5785
 
5678
5786
  char radix[8];
5679
5787
  const int len2 = GetLocaleRadix(radix, sizeof(radix));
5680
5788
 
5789
+ const int n = output_size - len1 - len2 - 1;
5790
+ if (n < 0) {
5791
+ return;
5792
+ }
5793
+
5681
5794
  memcpy(output, input, len1);
5682
5795
  memcpy(output + len1, radix, len2);
5683
- strcpy(output + len1 + len2, input + len1 + 1);
5796
+ strncpy(output + len1 + len2, input + len1 + 1, n);
5797
+ output[output_size - 1] = '\0';
5684
5798
  }
5685
5799
 
5686
5800
  double _upb_NoLocaleStrtod(const char *str, char **endptr) {
@@ -5700,7 +5814,7 @@ double _upb_NoLocaleStrtod(const char *str, char **endptr) {
5700
5814
  // try again.
5701
5815
 
5702
5816
  char localized[80];
5703
- LocalizeRadix(str, temp_endptr, localized);
5817
+ LocalizeRadix(str, temp_endptr, localized, sizeof localized);
5704
5818
  char *localized_endptr;
5705
5819
  result = strtod(localized, &localized_endptr);
5706
5820
  if ((localized_endptr - &localized[0]) > (temp_endptr - str)) {
@@ -5782,6 +5896,7 @@ upb_alloc upb_alloc_global = {&upb_global_allocfunc};
5782
5896
  static UPB_ATOMIC(size_t) g_max_block_size = UPB_DEFAULT_MAX_BLOCK_SIZE;
5783
5897
 
5784
5898
  void upb_Arena_SetMaxBlockSize(size_t max) {
5899
+ UPB_ASSERT(max <= UINT32_MAX);
5785
5900
  upb_Atomic_Store(&g_max_block_size, max, memory_order_relaxed);
5786
5901
  }
5787
5902
 
@@ -5818,8 +5933,14 @@ typedef struct upb_ArenaInternal {
5818
5933
  UPB_ATOMIC(const upb_ArenaRef*) refs;
5819
5934
  #endif
5820
5935
 
5821
- // A growing hint of what the *next* block should be sized
5822
- size_t size_hint;
5936
+ // Size of the last block we allocated in the normal exponential scheme.
5937
+ uint32_t last_block_size;
5938
+
5939
+ // A hint that grows whenever we perform a "one-off" allocation into a a
5940
+ // dedicated block. This helps us determine if these outlier blocks are
5941
+ // actually common enough that we should switch back to the normal exponential
5942
+ // scheme at the larger size.
5943
+ uint32_t size_hint;
5823
5944
 
5824
5945
  // All non atomic members used during allocation must be above this point, and
5825
5946
  // are used by _SwapIn/_SwapOut
@@ -6115,23 +6236,60 @@ bool upb_Arena_HasRefChain(const upb_Arena* from, const upb_Arena* to) {
6115
6236
 
6116
6237
  #endif
6117
6238
 
6118
- // Adds an allocated block to the head of the list.
6119
- static void _upb_Arena_AddBlock(upb_Arena* a, void* ptr, size_t offset,
6120
- size_t block_size) {
6239
+ static upb_MemBlock* _upb_Arena_AllocBlockInternal(upb_alloc* alloc,
6240
+ size_t size) {
6241
+ UPB_ASSERT(size >= kUpb_MemblockReserve);
6242
+ upb_SizedPtr alloc_result = upb_SizeReturningMalloc(alloc, size);
6243
+ if (!alloc_result.p) return NULL;
6244
+ upb_MemBlock* block = alloc_result.p;
6245
+ block->size = alloc_result.n;
6246
+ return block;
6247
+ }
6248
+
6249
+ static upb_MemBlock* _upb_Arena_AllocBlock(upb_Arena* a, size_t size) {
6250
+ upb_ArenaInternal* ai = upb_Arena_Internal(a);
6251
+ return _upb_Arena_AllocBlockInternal(_upb_ArenaInternal_BlockAlloc(ai), size);
6252
+ }
6253
+
6254
+ static void _upb_Arena_AddBlock(upb_Arena* a, upb_MemBlock* block) {
6121
6255
  upb_ArenaInternal* ai = upb_Arena_Internal(a);
6122
- upb_MemBlock* block = ptr;
6123
6256
 
6124
- block->size = block_size;
6125
- UPB_ASSERT(offset >= kUpb_MemblockReserve);
6126
- char* start = UPB_PTR_AT(block, offset, char);
6127
- upb_MemBlock* head = ai->blocks;
6128
- block->next = head;
6257
+ // Atomic add not required here, as threads won't race allocating blocks, plus
6258
+ // atomic fetch-add is slower than load/add/store on arm devices compiled
6259
+ // targeting pre-v8.1. Relaxed order is safe as nothing depends on order of
6260
+ // size allocated.
6261
+ uintptr_t old_space_allocated =
6262
+ upb_Atomic_Load(&ai->space_allocated, memory_order_relaxed);
6263
+ upb_Atomic_Store(&ai->space_allocated, old_space_allocated + block->size,
6264
+ memory_order_relaxed);
6265
+
6266
+ block->next = ai->blocks;
6129
6267
  ai->blocks = block;
6130
- UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(a));
6268
+ }
6269
+
6270
+ static void _upb_Arena_UseBlockInternal(upb_Arena* a, upb_MemBlock* block,
6271
+ size_t offset) {
6272
+ size_t block_size = block->size;
6273
+ char* start = UPB_PTR_AT(block, kUpb_MemblockReserve + offset, char);
6131
6274
  a->UPB_PRIVATE(ptr) = start;
6132
6275
  a->UPB_PRIVATE(end) = UPB_PTR_AT(block, block_size, char);
6133
6276
  UPB_PRIVATE(upb_Xsan_PoisonRegion)(start, a->UPB_PRIVATE(end) - start);
6134
- UPB_ASSERT(UPB_PRIVATE(_upb_ArenaHas)(a) >= block_size - offset);
6277
+ UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(a));
6278
+ UPB_ASSERT(UPB_PRIVATE(_upb_ArenaHas)(a) >=
6279
+ block_size - kUpb_MemblockReserve - offset);
6280
+ }
6281
+
6282
+ static void _upb_Arena_UseBlock(upb_Arena* a, upb_MemBlock* block) {
6283
+ _upb_Arena_UseBlockInternal(a, block, 0);
6284
+ }
6285
+
6286
+ static bool _upb_Arena_WouldReduceFreeSpace(upb_Arena* a, size_t size,
6287
+ size_t block_size) {
6288
+ upb_ArenaInternal* ai = upb_Arena_Internal(a);
6289
+ size_t current_free =
6290
+ ai->blocks ? a->UPB_PRIVATE(end) - a->UPB_PRIVATE(ptr) : 0;
6291
+ size_t future_free = block_size - kUpb_MemblockReserve - size;
6292
+ return current_free >= future_free;
6135
6293
  }
6136
6294
 
6137
6295
  // Fulfills the allocation request by allocating a new block. Returns NULL on
@@ -6139,84 +6297,60 @@ static void _upb_Arena_AddBlock(upb_Arena* a, void* ptr, size_t offset,
6139
6297
  void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(upb_Arena* a, size_t size) {
6140
6298
  upb_ArenaInternal* ai = upb_Arena_Internal(a);
6141
6299
  if (!ai->block_alloc) return NULL;
6142
- size_t last_size = 128;
6143
- size_t current_free = 0;
6144
- upb_MemBlock* last_block = ai->blocks;
6145
- if (last_block) {
6146
- last_size = last_block->size;
6147
- current_free = a->UPB_PRIVATE(end) - a->UPB_PRIVATE(ptr);
6148
- }
6300
+
6301
+ // Whether to satisfy the allocation from a one-off block which is right-sized
6302
+ // for the current allocation. We do this if we suspect that the current
6303
+ // allocation is an outlier that does not represent the typical size of
6304
+ // allocations from this arena, or if we would reduce free space by
6305
+ // using exponential growth.
6306
+ bool one_off = false;
6149
6307
 
6150
6308
  // Relaxed order is safe here as we don't need any ordering with the setter.
6151
6309
  size_t max_block_size =
6152
6310
  upb_Atomic_Load(&g_max_block_size, memory_order_relaxed);
6153
-
6154
- // Don't naturally grow beyond the max block size.
6155
- size_t target_size = UPB_MIN(last_size * 2, max_block_size);
6156
- size_t future_free = UPB_MAX(size, target_size - kUpb_MemblockReserve) - size;
6157
- // We want to preserve exponential growth in block size without wasting too
6158
- // much unused space at the end of blocks. Once the head of our blocks list is
6159
- // large enough to always trigger a max-sized block for all subsequent
6160
- // allocations, allocate blocks that would net reduce free space behind it.
6161
- if (last_block && current_free > future_free &&
6162
- target_size < max_block_size) {
6163
- last_size = ai->size_hint;
6164
- // Recalculate sizes with possibly larger last_size
6165
- target_size = UPB_MIN(last_size * 2, max_block_size);
6166
- future_free = UPB_MAX(size, target_size - kUpb_MemblockReserve) - size;
6167
- }
6168
- bool insert_after_head = false;
6169
- // Only insert after head if an allocated block is present; we don't want to
6170
- // continue allocating out of the initial block because we'll have no way of
6171
- // restoring the size of our allocated block if we add another.
6172
- if (last_block && current_free >= future_free) {
6173
- // If we're still going to net reduce free space with this new block, then
6174
- // only allocate the precise size requested and keep the current last block
6175
- // as the active block for future allocations.
6176
- insert_after_head = true;
6177
- target_size = size + kUpb_MemblockReserve;
6178
- // Add something to our previous size each time, so that eventually we
6179
- // will reach the max block size. Allocations larger than the max block size
6180
- // will always get their own backing allocation, so don't include them.
6181
- if (target_size <= max_block_size) {
6182
- ai->size_hint = UPB_MIN(ai->size_hint + (size >> 1), max_block_size >> 1);
6311
+ size_t block_size = UPB_MIN(ai->last_block_size * 2, max_block_size);
6312
+
6313
+ if (size + kUpb_MemblockReserve > block_size) {
6314
+ // A regular doubling would not yield a large enough block. Does size_hint
6315
+ // indicate that we have consistently needed large blocks?
6316
+ block_size = UPB_MIN(ai->size_hint * 2, max_block_size);
6317
+ if (size + kUpb_MemblockReserve > block_size) {
6318
+ // Even size_hint is not large enough, we will have to do a one-off.
6319
+ one_off = true;
6183
6320
  }
6184
6321
  }
6185
- // We may need to exceed the max block size if the user requested a large
6186
- // allocation.
6187
- size_t block_size = UPB_MAX(kUpb_MemblockReserve + size, target_size);
6188
- upb_alloc* block_alloc = _upb_ArenaInternal_BlockAlloc(ai);
6189
- upb_SizedPtr alloc_result = upb_SizeReturningMalloc(block_alloc, block_size);
6190
6322
 
6191
- if (!alloc_result.p) return NULL;
6323
+ // If switching to a block of this size would *reduce* available free space,
6324
+ // we might as well make a one-off block instead.
6325
+ one_off = one_off || _upb_Arena_WouldReduceFreeSpace(a, size, block_size);
6192
6326
 
6193
- upb_MemBlock* block = alloc_result.p;
6194
- size_t actual_block_size = alloc_result.n;
6327
+ if (one_off) {
6328
+ // Note: this may exceed the max block size, but that's okay.
6329
+ block_size = size + kUpb_MemblockReserve;
6330
+ }
6195
6331
 
6196
- // Atomic add not required here, as threads won't race allocating blocks, plus
6197
- // atomic fetch-add is slower than load/add/store on arm devices compiled
6198
- // targetting pre-v8.1. Relaxed order is safe as nothing depends on order of
6199
- // size allocated.
6332
+ upb_MemBlock* block = _upb_Arena_AllocBlock(a, block_size);
6333
+ if (!block) return NULL;
6200
6334
 
6201
- uintptr_t old_space_allocated =
6202
- upb_Atomic_Load(&ai->space_allocated, memory_order_relaxed);
6203
- upb_Atomic_Store(&ai->space_allocated,
6204
- old_space_allocated + actual_block_size,
6205
- memory_order_relaxed);
6206
- if (UPB_UNLIKELY(insert_after_head)) {
6207
- upb_ArenaInternal* ai = upb_Arena_Internal(a);
6208
- block->size = actual_block_size;
6209
- upb_MemBlock* head = ai->blocks;
6210
- block->next = head->next;
6211
- head->next = block;
6335
+ _upb_Arena_AddBlock(a, block);
6212
6336
 
6337
+ // Recheck size, in case the allocator gave us a much larger block than we
6338
+ // requested and we want to make it the new allocating region.
6339
+ if (UPB_UNLIKELY(one_off) &&
6340
+ _upb_Arena_WouldReduceFreeSpace(a, size, block->size)) {
6341
+ // Increase size_hint, so that a series of one-off allocations will
6342
+ // eventually convince us to switch to exponential growth at the larger
6343
+ // size.
6344
+ ai->size_hint = UPB_MIN(ai->size_hint + (size >> 1), max_block_size >> 1);
6213
6345
  char* allocated = UPB_PTR_AT(block, kUpb_MemblockReserve, char);
6214
- UPB_PRIVATE(upb_Xsan_PoisonRegion)(allocated + size,
6215
- UPB_PRIVATE(kUpb_Asan_GuardSize));
6346
+ char* poison_start = allocated + size - UPB_PRIVATE(kUpb_Asan_GuardSize);
6347
+ UPB_PRIVATE(upb_Xsan_PoisonRegion)(
6348
+ poison_start, UPB_PTR_AT(block, block->size, char) - poison_start);
6216
6349
  return allocated;
6217
6350
  } else {
6218
- ai->size_hint = actual_block_size;
6219
- _upb_Arena_AddBlock(a, block, kUpb_MemblockReserve, actual_block_size);
6351
+ ai->last_block_size = UPB_MIN(block->size, UINT32_MAX);
6352
+ ai->size_hint = ai->last_block_size;
6353
+ _upb_Arena_UseBlock(a, block);
6220
6354
  UPB_ASSERT(UPB_PRIVATE(_upb_ArenaHas)(a) >= size);
6221
6355
  return upb_Arena_Malloc(a, size - UPB_PRIVATE(kUpb_Asan_GuardSize));
6222
6356
  }
@@ -6227,27 +6361,26 @@ static upb_Arena* _upb_Arena_InitSlow(upb_alloc* alloc, size_t first_size) {
6227
6361
  UPB_ALIGN_MALLOC(kUpb_MemblockReserve + sizeof(upb_ArenaState));
6228
6362
  upb_ArenaState* a;
6229
6363
 
6230
- // We need to malloc the initial block.
6364
+ if (!alloc) return NULL;
6231
6365
 
6366
+ // We need to malloc the initial block.
6232
6367
  size_t block_size =
6233
6368
  first_block_overhead + UPB_MAX(256, UPB_ALIGN_MALLOC(first_size) +
6234
6369
  UPB_PRIVATE(kUpb_Asan_GuardSize));
6235
- upb_SizedPtr alloc_result;
6236
- if (!alloc ||
6237
- !(alloc_result = upb_SizeReturningMalloc(alloc, block_size)).p) {
6238
- return NULL;
6239
- }
6240
- char* mem = alloc_result.p;
6241
- size_t actual_block_size = alloc_result.n;
6370
+ upb_MemBlock* block = _upb_Arena_AllocBlockInternal(alloc, block_size);
6371
+ if (!block) return NULL;
6242
6372
 
6243
- a = UPB_PTR_AT(mem, kUpb_MemblockReserve, upb_ArenaState);
6373
+ // Initialize the arena state in the first block. We "borrow" the memory from
6374
+ // the block, because we can't yet call upb_Arena_Malloc.
6375
+ a = UPB_PTR_AT(block, kUpb_MemblockReserve, upb_ArenaState);
6244
6376
  a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 0);
6245
- a->body.size_hint = actual_block_size;
6377
+ a->body.last_block_size = UPB_MIN(block->size, UINT32_MAX);
6378
+ a->body.size_hint = UPB_MIN(block->size, UINT32_MAX);
6246
6379
  upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1));
6247
6380
  upb_Atomic_Init(&a->body.next, NULL);
6248
6381
  upb_Atomic_Init(&a->body.previous_or_tail,
6249
6382
  _upb_Arena_TaggedFromTail(&a->body));
6250
- upb_Atomic_Init(&a->body.space_allocated, actual_block_size);
6383
+ upb_Atomic_Init(&a->body.space_allocated, 0);
6251
6384
  a->body.blocks = NULL;
6252
6385
  #ifndef NDEBUG
6253
6386
  a->body.refs = NULL;
@@ -6255,15 +6388,16 @@ static upb_Arena* _upb_Arena_InitSlow(upb_alloc* alloc, size_t first_size) {
6255
6388
  a->body.upb_alloc_cleanup = NULL;
6256
6389
  UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body));
6257
6390
 
6258
- _upb_Arena_AddBlock(&a->head, mem, first_block_overhead, actual_block_size);
6391
+ _upb_Arena_AddBlock(&a->head, block);
6392
+ _upb_Arena_UseBlockInternal(&a->head, block,
6393
+ UPB_ALIGN_MALLOC(sizeof(upb_ArenaState)));
6259
6394
 
6260
6395
  return &a->head;
6261
6396
  }
6262
6397
 
6263
6398
  upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) {
6264
- UPB_STATIC_ASSERT(
6265
- sizeof(void*) * UPB_ARENA_SIZE_HACK >= sizeof(upb_ArenaState),
6266
- "Need to update UPB_ARENA_SIZE_HACK");
6399
+ UPB_STATIC_ASSERT(UPB_ARENA_SIZE_HACK >= sizeof(upb_ArenaState),
6400
+ "Need to update UPB_ARENA_SIZE_HACK");
6267
6401
  upb_ArenaState* a;
6268
6402
 
6269
6403
  if (mem) {
@@ -6293,6 +6427,7 @@ upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) {
6293
6427
  a->body.refs = NULL;
6294
6428
  #endif
6295
6429
  a->body.size_hint = 128;
6430
+ a->body.last_block_size = 128;
6296
6431
  a->body.upb_alloc_cleanup = NULL;
6297
6432
  a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 1);
6298
6433
  a->head.UPB_PRIVATE(ptr) = (void*)UPB_ALIGN_MALLOC((uintptr_t)(a + 1));
@@ -6739,14 +6874,11 @@ void UPB_PRIVATE(_upb_Arena_SwapOut)(upb_Arena* des, const upb_Arena* src) {
6739
6874
  bool _upb_Arena_WasLastAlloc(struct upb_Arena* a, void* ptr, size_t oldsize) {
6740
6875
  upb_ArenaInternal* ai = upb_Arena_Internal(a);
6741
6876
  upb_MemBlock* block = ai->blocks;
6742
- if (block == NULL) return false;
6743
6877
  // Skip any arena refs.
6744
6878
  while (block != NULL && block->size == 0) {
6745
6879
  block = block->next;
6746
6880
  }
6747
6881
  if (block == NULL) return false;
6748
- block = block->next;
6749
- if (block == NULL) return false;
6750
6882
  char* start = UPB_PTR_AT(block, kUpb_MemblockReserve, char);
6751
6883
  return UPB_PRIVATE(upb_Xsan_PtrEq)(ptr, start) &&
6752
6884
  UPB_PRIVATE(_upb_Arena_AllocSpan)(oldsize) ==
@@ -6828,6 +6960,46 @@ bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) {
6828
6960
  return true;
6829
6961
  }
6830
6962
 
6963
+ bool upb_Array_Copy(upb_Array* dst, const upb_Array* src, upb_Arena* arena) {
6964
+ UPB_ASSERT(dst);
6965
+ UPB_ASSERT(src);
6966
+ UPB_ASSERT(!upb_Array_IsFrozen(dst));
6967
+ if (dst == src) return true;
6968
+ size_t len = upb_Array_Size(src);
6969
+ if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(dst, len, arena)) {
6970
+ return false;
6971
+ }
6972
+ if (len == 0) return true;
6973
+ const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(dst);
6974
+ const int src_lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(src);
6975
+ UPB_ASSERT(lg2 == src_lg2);
6976
+ char* dst_data = upb_Array_MutableDataPtr(dst);
6977
+ const char* src_data = upb_Array_DataPtr(src);
6978
+ memcpy(dst_data, src_data, len << lg2);
6979
+ return true;
6980
+ }
6981
+
6982
+ bool upb_Array_AppendAll(upb_Array* dst, const upb_Array* src,
6983
+ upb_Arena* arena) {
6984
+ UPB_ASSERT(!upb_Array_IsFrozen(dst));
6985
+ UPB_ASSERT(src);
6986
+ size_t src_len = upb_Array_Size(src);
6987
+ if (src_len == 0) return true;
6988
+ size_t dst_len = upb_Array_Size(dst);
6989
+ size_t len = dst_len + src_len;
6990
+ if (UPB_UNLIKELY(len < dst_len)) return false;
6991
+ if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(dst, len, arena)) {
6992
+ return false;
6993
+ }
6994
+ const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(dst);
6995
+ const int src_lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(src);
6996
+ UPB_ASSERT(lg2 == src_lg2);
6997
+ char* dst_data = upb_Array_MutableDataPtr(dst);
6998
+ const char* src_data = upb_Array_DataPtr(src);
6999
+ memcpy(dst_data + (dst_len << lg2), src_data, src_len << lg2);
7000
+ return true;
7001
+ }
7002
+
6831
7003
  void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx,
6832
7004
  size_t count) {
6833
7005
  UPB_ASSERT(!upb_Array_IsFrozen(arr));
@@ -6888,9 +7060,17 @@ bool UPB_PRIVATE(_upb_Array_Realloc)(upb_Array* array, size_t min_capacity,
6888
7060
  void* ptr = upb_Array_MutableDataPtr(array);
6889
7061
 
6890
7062
  // Log2 ceiling of size.
6891
- while (new_capacity < min_capacity) new_capacity *= 2;
7063
+ while (new_capacity < min_capacity) {
7064
+ if (upb_ShlOverflow(&new_capacity, 1)) {
7065
+ new_capacity = SIZE_MAX;
7066
+ break;
7067
+ }
7068
+ }
6892
7069
 
6893
- const size_t new_bytes = new_capacity << lg2;
7070
+ size_t new_bytes = new_capacity;
7071
+ if (upb_ShlOverflow(&new_bytes, lg2)) {
7072
+ return false;
7073
+ }
6894
7074
  ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes);
6895
7075
  if (!ptr) return false;
6896
7076
 
@@ -7348,6 +7528,7 @@ UPB_NOINLINE bool UPB_PRIVATE(_upb_Message_AddUnknownSlowPath)(upb_Message* msg,
7348
7528
  if (!view) return false;
7349
7529
  view->data = data;
7350
7530
  } else {
7531
+ if (SIZE_MAX - sizeof(upb_StringView) < len) return false;
7351
7532
  view = upb_Arena_Malloc(arena, sizeof(upb_StringView) + len);
7352
7533
  if (!view) return false;
7353
7534
  char* copy = UPB_PTR_AT(view, sizeof(upb_StringView), char);
@@ -8124,7 +8305,7 @@ static bool upb_Clone_MessageValue(void* value, upb_CType value_type,
8124
8305
  case kUpb_CType_String:
8125
8306
  case kUpb_CType_Bytes: {
8126
8307
  upb_StringView source = *(upb_StringView*)value;
8127
- int size = source.size;
8308
+ size_t size = source.size;
8128
8309
  void* cloned_data = upb_Arena_Malloc(arena, size);
8129
8310
  if (cloned_data == NULL) {
8130
8311
  return false;
@@ -8504,8 +8685,15 @@ bool UPB_PRIVATE(_upb_Message_ReserveSlot)(struct upb_Message* msg,
8504
8685
  in->capacity = capacity;
8505
8686
  UPB_PRIVATE(_upb_Message_SetInternal)(msg, in);
8506
8687
  } else if (in->capacity == in->size) {
8688
+ if (in->size == UINT32_MAX) return false;
8507
8689
  // Internal data is too small, reallocate.
8508
- uint32_t new_capacity = upb_RoundUpToPowerOfTwo(in->size + 1);
8690
+ size_t needed_pow2 = upb_RoundUpToPowerOfTwo(in->size + 1);
8691
+ if (needed_pow2 > UINT32_MAX) return false;
8692
+ uint32_t new_capacity = needed_pow2;
8693
+ if (UPB_SIZEOF_FLEX_WOULD_OVERFLOW(upb_Message_Internal, aux_data,
8694
+ new_capacity)) {
8695
+ return false;
8696
+ }
8509
8697
  in = upb_Arena_Realloc(a, in, _upb_Message_SizeOfInternal(in->capacity),
8510
8698
  _upb_Message_SizeOfInternal(new_capacity));
8511
8699
  if (!in) return false;
@@ -8710,7 +8898,6 @@ upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len,
8710
8898
 
8711
8899
 
8712
8900
  #include <inttypes.h>
8713
- #include <stdalign.h>
8714
8901
  #include <stddef.h>
8715
8902
  #include <stdint.h>
8716
8903
  #include <stdlib.h>
@@ -10117,28 +10304,25 @@ char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) {
10117
10304
 
10118
10305
  // Must be last.
10119
10306
 
10120
- #define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t))
10121
-
10122
10307
  struct upb_ExtensionRegistry {
10308
+ upb_exttable exts;
10123
10309
  upb_Arena* arena;
10124
- upb_strtable exts; // Key is upb_MiniTable* concatenated with fieldnum.
10125
10310
  };
10126
10311
 
10127
- static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) {
10128
- memcpy(buf, &l, sizeof(l));
10129
- memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum));
10130
- }
10131
-
10132
10312
  upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) {
10133
10313
  upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r));
10134
10314
  if (!r) return NULL;
10135
10315
  r->arena = arena;
10136
- if (!upb_strtable_init(&r->exts, 8, arena)) return NULL;
10316
+ if (!upb_exttable_init(&r->exts, 8, arena)) return NULL;
10137
10317
  return r;
10138
10318
  }
10139
10319
 
10140
10320
  UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add(
10141
10321
  upb_ExtensionRegistry* r, const upb_MiniTableExtension* e) {
10322
+ UPB_STATIC_ASSERT(
10323
+ offsetof(upb_MiniTableExtension,
10324
+ UPB_PRIVATE(field).UPB_PRIVATE(number)) == 0,
10325
+ "Extension must be first-member-of-struct convertable with uint32_t");
10142
10326
  uint32_t fieldnum = upb_MiniTableExtension_Number(e);
10143
10327
  const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(e);
10144
10328
 
@@ -10148,15 +10332,11 @@ UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add(
10148
10332
  return kUpb_ExtensionRegistryStatus_InvalidExtension;
10149
10333
  }
10150
10334
 
10151
- char buf[EXTREG_KEY_SIZE];
10152
- extreg_key(buf, extendee, fieldnum);
10153
-
10154
- if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, NULL)) {
10335
+ if (upb_exttable_lookup(&r->exts, extendee, fieldnum) != NULL) {
10155
10336
  return kUpb_ExtensionRegistryStatus_DuplicateEntry;
10156
10337
  }
10157
10338
 
10158
- if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE,
10159
- upb_value_constptr(e), r->arena)) {
10339
+ if (!upb_exttable_insert(&r->exts, extendee, (const uint32_t*)e, r->arena)) {
10160
10340
  return kUpb_ExtensionRegistryStatus_OutOfMemory;
10161
10341
  }
10162
10342
  return kUpb_ExtensionRegistryStatus_Ok;
@@ -10177,10 +10357,8 @@ failure:
10177
10357
  // Back out the entries previously added.
10178
10358
  for (end = e, e = start; e < end; e++) {
10179
10359
  const upb_MiniTableExtension* ext = *e;
10180
- char buf[EXTREG_KEY_SIZE];
10181
- extreg_key(buf, ext->UPB_PRIVATE(extendee),
10182
- upb_MiniTableExtension_Number(ext));
10183
- upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL);
10360
+ upb_exttable_remove(&r->exts, upb_MiniTableExtension_Extendee(ext),
10361
+ upb_MiniTableExtension_Number(ext));
10184
10362
  }
10185
10363
  UPB_ASSERT(status != kUpb_ExtensionRegistryStatus_Ok);
10186
10364
  return status;
@@ -10188,22 +10366,11 @@ failure:
10188
10366
 
10189
10367
  const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup(
10190
10368
  const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) {
10191
- char buf[EXTREG_KEY_SIZE];
10192
- upb_value v;
10193
- extreg_key(buf, t, num);
10194
- if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) {
10195
- return upb_value_getconstptr(v);
10196
- } else {
10197
- return NULL;
10198
- }
10199
- }
10200
-
10201
- size_t upb_ExtensionRegistry_Size(const upb_ExtensionRegistry* r) {
10202
- return upb_strtable_count(&r->exts);
10369
+ const uint32_t* v = upb_exttable_lookup(&r->exts, t, num);
10370
+ return (const upb_MiniTableExtension*)v;
10203
10371
  }
10204
10372
 
10205
10373
 
10206
- #include <stddef.h>
10207
10374
  #include <stdint.h>
10208
10375
 
10209
10376
 
@@ -10231,17 +10398,21 @@ static bool _upb_GeneratedRegistry_AddAllLinkedExtensions(
10231
10398
  const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* entry =
10232
10399
  UPB_PRIVATE(upb_generated_extension_list);
10233
10400
  while (entry != NULL) {
10234
- const upb_MiniTableExtension** current = entry->start;
10235
- for (current = entry->start; current != entry->stop; ++current) {
10236
- const upb_MiniTableExtension* ext = *current;
10401
+ // Comparing pointers to different objects is undefined behavior, so we
10402
+ // convert them to uintptr_t and compare their values.
10403
+ uintptr_t begin = (uintptr_t)entry->start;
10404
+ uintptr_t end = (uintptr_t)entry->stop;
10405
+ uintptr_t current = begin;
10406
+ while (current < end) {
10407
+ const upb_MiniTableExtension* ext =
10408
+ (const upb_MiniTableExtension*)current;
10237
10409
  // Sentinels and padding introduced by the linker can result in zeroed
10238
10410
  // entries, so simply skip them.
10239
- if (*current == NULL) {
10411
+ if (upb_MiniTableExtension_Number(ext) == 0) {
10240
10412
  // MSVC introduces padding that might not be sized exactly the same as
10241
- // the linker array element, but it should be properly aligned, so just
10242
- // skipping empty elements should be safe. (If the size and align of
10243
- // the array elements was different, we'd have to do something more
10244
- // complicated).
10413
+ // upb_MiniTableExtension, so we can't iterate by sizeof. This is a
10414
+ // valid thing for any linker to do, so it's safer to just always do it.
10415
+ current += UPB_ALIGN_OF(upb_MiniTableExtension);
10245
10416
  continue;
10246
10417
  }
10247
10418
 
@@ -10249,6 +10420,7 @@ static bool _upb_GeneratedRegistry_AddAllLinkedExtensions(
10249
10420
  kUpb_ExtensionRegistryStatus_Ok) {
10250
10421
  return false;
10251
10422
  }
10423
+ current += sizeof(upb_MiniTableExtension);
10252
10424
  }
10253
10425
  entry = entry->next;
10254
10426
  }
@@ -10448,6 +10620,7 @@ struct upb_DefPool {
10448
10620
  size_t scratch_size;
10449
10621
  size_t bytes_loaded;
10450
10622
  bool disable_closed_enum_checking;
10623
+ bool disable_implicit_field_presence;
10451
10624
  };
10452
10625
 
10453
10626
  void upb_DefPool_Free(upb_DefPool* s) {
@@ -10466,6 +10639,7 @@ upb_DefPool* upb_DefPool_New(void) {
10466
10639
  s->arena = upb_Arena_New();
10467
10640
  s->bytes_loaded = 0;
10468
10641
  s->disable_closed_enum_checking = false;
10642
+ s->disable_implicit_field_presence = false;
10469
10643
 
10470
10644
  s->scratch_size = 240;
10471
10645
  s->scratch_data = upb_gmalloc(s->scratch_size);
@@ -10507,6 +10681,15 @@ bool upb_DefPool_ClosedEnumCheckingDisabled(const upb_DefPool* s) {
10507
10681
  return s->disable_closed_enum_checking;
10508
10682
  }
10509
10683
 
10684
+ void upb_DefPool_DisableImplicitFieldPresence(upb_DefPool* s) {
10685
+ UPB_ASSERT(upb_strtable_count(&s->files) == 0);
10686
+ s->disable_implicit_field_presence = true;
10687
+ }
10688
+
10689
+ bool upb_DefPool_ImplicitFieldPresenceDisabled(const upb_DefPool* s) {
10690
+ return s->disable_implicit_field_presence;
10691
+ }
10692
+
10510
10693
  const google_protobuf_FeatureSetDefaults* upb_DefPool_FeatureSetDefaults(
10511
10694
  const upb_DefPool* s) {
10512
10695
  return s->feature_set_defaults;
@@ -10616,7 +10799,7 @@ void _upb_DefPool_SetPlatform(upb_DefPool* s, upb_MiniTablePlatform platform) {
10616
10799
 
10617
10800
  const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s,
10618
10801
  const char* sym) {
10619
- return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG);
10802
+ return upb_DefPool_FindMessageByNameWithSize(s, sym, strlen(sym));
10620
10803
  }
10621
10804
 
10622
10805
  const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize(
@@ -10626,12 +10809,23 @@ const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize(
10626
10809
 
10627
10810
  const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s,
10628
10811
  const char* sym) {
10629
- return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM);
10812
+ return upb_DefPool_FindEnumByNameWithSize(s, sym, strlen(sym));
10813
+ }
10814
+
10815
+ const upb_EnumDef* upb_DefPool_FindEnumByNameWithSize(const upb_DefPool* s,
10816
+ const char* sym,
10817
+ size_t len) {
10818
+ return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_ENUM);
10819
+ }
10820
+
10821
+ const upb_EnumValueDef* upb_DefPool_FindEnumValueByName(const upb_DefPool* s,
10822
+ const char* sym) {
10823
+ return upb_DefPool_FindEnumValueByNameWithSize(s, sym, strlen(sym));
10630
10824
  }
10631
10825
 
10632
- const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s,
10633
- const char* sym) {
10634
- return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL);
10826
+ const upb_EnumValueDef* upb_DefPool_FindEnumValueByNameWithSize(
10827
+ const upb_DefPool* s, const char* sym, size_t len) {
10828
+ return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_ENUMVAL);
10635
10829
  }
10636
10830
 
10637
10831
  const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s,
@@ -12248,7 +12442,7 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
12248
12442
 
12249
12443
  f->has_presence =
12250
12444
  (!upb_FieldDef_IsRepeated(f)) &&
12251
- (f->is_extension ||
12445
+ (f->is_extension || _upb_FileDef_ImplicitFieldPresenceDisabled(f->file) ||
12252
12446
  (f->type_ == kUpb_FieldType_Message ||
12253
12447
  f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) ||
12254
12448
  google_protobuf_FeatureSet_field_presence(f->resolved_features) !=
@@ -12652,6 +12846,10 @@ bool _upb_FileDef_ClosedEnumCheckingDisabled(const upb_FileDef* f) {
12652
12846
  return upb_DefPool_ClosedEnumCheckingDisabled(f->symtab);
12653
12847
  }
12654
12848
 
12849
+ bool _upb_FileDef_ImplicitFieldPresenceDisabled(const upb_FileDef* f) {
12850
+ return upb_DefPool_ImplicitFieldPresenceDisabled(f->symtab);
12851
+ }
12852
+
12655
12853
  int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) {
12656
12854
  return f->top_lvl_enum_count;
12657
12855
  }
@@ -14540,6 +14738,7 @@ static void create_method(upb_DefBuilder* ctx,
14540
14738
  m->output_type = _upb_DefBuilder_Resolve(
14541
14739
  ctx, m->full_name, m->full_name,
14542
14740
  google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG);
14741
+ _upb_ServiceDef_InsertMethod(ctx, s, m);
14543
14742
  }
14544
14743
 
14545
14744
  // Allocate and initialize an array of |n| method defs belonging to |s|.
@@ -14771,6 +14970,7 @@ struct upb_ServiceDef {
14771
14970
  upb_MethodDef* methods;
14772
14971
  int method_count;
14773
14972
  int index;
14973
+ upb_strtable ntom;
14774
14974
  };
14775
14975
 
14776
14976
  upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) {
@@ -14815,13 +15015,18 @@ const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) {
14815
15015
 
14816
15016
  const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s,
14817
15017
  const char* name) {
14818
- for (int i = 0; i < s->method_count; i++) {
14819
- const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i);
14820
- if (strcmp(name, upb_MethodDef_Name(m)) == 0) {
14821
- return m;
14822
- }
15018
+ return upb_ServiceDef_FindMethodByNameWithSize(s, name, strlen(name));
15019
+ }
15020
+
15021
+ const upb_MethodDef* upb_ServiceDef_FindMethodByNameWithSize(
15022
+ const upb_ServiceDef* s, const char* name, size_t len) {
15023
+ upb_value val;
15024
+
15025
+ if (!upb_strtable_lookup2(&s->ntom, name, len, &val)) {
15026
+ return NULL;
14823
15027
  }
14824
- return NULL;
15028
+
15029
+ return _upb_DefType_Unpack(val, UPB_DEFTYPE_METHOD);
14825
15030
  }
14826
15031
 
14827
15032
  static void create_service(upb_DefBuilder* ctx,
@@ -14846,6 +15051,8 @@ static void create_service(upb_DefBuilder* ctx,
14846
15051
  const google_protobuf_MethodDescriptorProto* const* methods =
14847
15052
  google_protobuf_ServiceDescriptorProto_method(svc_proto, &n);
14848
15053
  s->method_count = n;
15054
+ bool ok = upb_strtable_init(&s->ntom, n, ctx->arena);
15055
+ if (!ok) _upb_DefBuilder_OomErr(ctx);
14849
15056
  s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s);
14850
15057
  }
14851
15058
 
@@ -14863,6 +15070,20 @@ upb_ServiceDef* _upb_ServiceDefs_New(
14863
15070
  return s;
14864
15071
  }
14865
15072
 
15073
+ void _upb_ServiceDef_InsertMethod(upb_DefBuilder* ctx, upb_ServiceDef* s,
15074
+ const upb_MethodDef* m) {
15075
+ const char* shortname = upb_MethodDef_Name(m);
15076
+ const size_t shortnamelen = strlen(shortname);
15077
+ upb_value existing_v;
15078
+ if (upb_strtable_lookup(&s->ntom, shortname, &existing_v)) {
15079
+ _upb_DefBuilder_Errf(ctx, "duplicate method name (%s)", shortname);
15080
+ }
15081
+ const upb_value method_v = _upb_DefType_Pack(m, UPB_DEFTYPE_METHOD);
15082
+ bool ok = upb_strtable_insert(&s->ntom, shortname, shortnamelen, method_v,
15083
+ ctx->arena);
15084
+ if (!ok) _upb_DefBuilder_OomErr(ctx);
15085
+ }
15086
+
14866
15087
 
14867
15088
  #include <inttypes.h>
14868
15089
  #include <math.h>
@@ -16470,6 +16691,7 @@ const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr,
16470
16691
  *op = kUpb_DecodeOp_UnknownField;
16471
16692
  return ptr;
16472
16693
  }
16694
+ _upb_Decoder_MungeInt32(val);
16473
16695
  } else {
16474
16696
  _upb_Decoder_Munge(field, val);
16475
16697
  }
@@ -16512,7 +16734,6 @@ const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr,
16512
16734
  UPB_FORCEINLINE
16513
16735
  const char* _upb_Decoder_DecodeKnownField(upb_Decoder* d, const char* ptr,
16514
16736
  upb_Message* msg,
16515
- const upb_MiniTable* layout,
16516
16737
  const upb_MiniTableField* field,
16517
16738
  int op, wireval* val) {
16518
16739
  uint8_t mode = field->UPB_PRIVATE(mode);
@@ -16541,67 +16762,13 @@ const char* _upb_Decoder_DecodeKnownField(upb_Decoder* d, const char* ptr,
16541
16762
  }
16542
16763
  }
16543
16764
 
16544
- static const char* _upb_Decoder_FindFieldStart(upb_Decoder* d, const char* ptr,
16545
- uint32_t field_number,
16546
- uint32_t wire_type) {
16547
- // Since unknown fields are the uncommon case, we do a little extra work here
16548
- // to walk backwards through the buffer to find the field start. This frees
16549
- // up a register in the fast paths (when the field is known), which leads to
16550
- // significant speedups in benchmarks. Note that ptr may point into the slop
16551
- // space, beyond the normal end of the input buffer.
16552
- const char* start = ptr;
16553
-
16554
- switch (wire_type) {
16555
- case kUpb_WireType_Varint:
16556
- case kUpb_WireType_Delimited:
16557
- // Skip the last byte
16558
- start--;
16559
- // Skip bytes until we encounter the final byte of the tag varint.
16560
- while (start[-1] & 0x80) start--;
16561
- break;
16562
- case kUpb_WireType_32Bit:
16563
- start -= 4;
16564
- break;
16565
- case kUpb_WireType_64Bit:
16566
- start -= 8;
16567
- break;
16568
- default:
16569
- break;
16570
- }
16571
- assert(start == d->debug_valstart);
16572
-
16573
- {
16574
- // The varint parser does not enforce that integers are encoded with their
16575
- // minimum size; for example the value 1 could be encoded with three
16576
- // bytes: 0x81, 0x80, 0x00. These unnecessary trailing zeroes mean that we
16577
- // cannot skip backwards by the minimum encoded size of the tag; and
16578
- // unlike the loop for delimited or varint fields, we can't stop at a
16579
- // sentinel value because anything can precede a tag. Instead, parse back
16580
- // one byte at a time until we read the same tag value that was parsed
16581
- // earlier.
16582
- uint32_t tag = ((uint32_t)field_number << 3) | wire_type;
16583
- uint32_t seen = 0;
16584
- do {
16585
- start--;
16586
- seen <<= 7;
16587
- seen |= *start & 0x7f;
16588
- } while (seen != tag);
16589
- }
16590
- assert(start == d->debug_tagstart);
16591
-
16592
- return start;
16593
- }
16594
-
16595
16765
  static const char* _upb_Decoder_DecodeUnknownField(
16596
16766
  upb_Decoder* d, const char* ptr, upb_Message* msg, uint32_t field_number,
16597
- uint32_t wire_type, wireval val) {
16767
+ uint32_t wire_type, wireval val, const char* start) {
16598
16768
  if (field_number == 0) {
16599
16769
  upb_ErrorHandler_ThrowError(&d->err, kUpb_DecodeStatus_Malformed);
16600
16770
  }
16601
16771
 
16602
- const char* start =
16603
- _upb_Decoder_FindFieldStart(d, ptr, field_number, wire_type);
16604
-
16605
16772
  upb_EpsCopyInputStream_StartCapture(&d->input, start);
16606
16773
 
16607
16774
  if (wire_type == kUpb_WireType_Delimited) {
@@ -16640,10 +16807,6 @@ UPB_FORCEINLINE
16640
16807
  const char* _upb_Decoder_DecodeFieldTag(upb_Decoder* d, const char* ptr,
16641
16808
  uint32_t* field_number,
16642
16809
  uint32_t* wire_type) {
16643
- #ifndef NDEBUG
16644
- d->debug_tagstart = ptr;
16645
- #endif
16646
-
16647
16810
  uint32_t tag;
16648
16811
  UPB_ASSERT(ptr < d->input.limit_ptr);
16649
16812
  ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d));
@@ -16653,15 +16816,9 @@ const char* _upb_Decoder_DecodeFieldTag(upb_Decoder* d, const char* ptr,
16653
16816
  }
16654
16817
 
16655
16818
  UPB_FORCEINLINE
16656
- const char* _upb_Decoder_DecodeFieldData(upb_Decoder* d, const char* ptr,
16657
- upb_Message* msg,
16658
- const upb_MiniTable* mt,
16659
- uint32_t field_number,
16660
- uint32_t wire_type) {
16661
- #ifndef NDEBUG
16662
- d->debug_valstart = ptr;
16663
- #endif
16664
-
16819
+ const char* _upb_Decoder_DecodeFieldData(
16820
+ upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable* mt,
16821
+ uint32_t field_number, uint32_t wire_type, const char* start) {
16665
16822
  int op;
16666
16823
  wireval val;
16667
16824
 
@@ -16670,12 +16827,12 @@ const char* _upb_Decoder_DecodeFieldData(upb_Decoder* d, const char* ptr,
16670
16827
  ptr = _upb_Decoder_DecodeWireValue(d, ptr, mt, field, wire_type, &val, &op);
16671
16828
 
16672
16829
  if (op >= 0) {
16673
- return _upb_Decoder_DecodeKnownField(d, ptr, msg, mt, field, op, &val);
16830
+ return _upb_Decoder_DecodeKnownField(d, ptr, msg, field, op, &val);
16674
16831
  } else {
16675
16832
  switch (op) {
16676
16833
  case kUpb_DecodeOp_UnknownField:
16677
16834
  return _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number,
16678
- wire_type, val);
16835
+ wire_type, val, start);
16679
16836
  case kUpb_DecodeOp_MessageSetItem:
16680
16837
  return upb_Decoder_DecodeMessageSetItem(d, ptr, msg, mt);
16681
16838
  default:
@@ -16696,6 +16853,7 @@ const char* _upb_Decoder_DecodeFieldNoFast(upb_Decoder* d, const char* ptr,
16696
16853
  uint32_t field_number;
16697
16854
  uint32_t wire_type;
16698
16855
 
16856
+ const char* start = ptr;
16699
16857
  ptr = _upb_Decoder_DecodeFieldTag(d, ptr, &field_number, &wire_type);
16700
16858
 
16701
16859
  if (wire_type == kUpb_WireType_EndGroup) {
@@ -16703,7 +16861,8 @@ const char* _upb_Decoder_DecodeFieldNoFast(upb_Decoder* d, const char* ptr,
16703
16861
  return _upb_Decoder_EndMessage(d, ptr);
16704
16862
  }
16705
16863
 
16706
- ptr = _upb_Decoder_DecodeFieldData(d, ptr, msg, mt, field_number, wire_type);
16864
+ ptr = _upb_Decoder_DecodeFieldData(d, ptr, msg, mt, field_number, wire_type,
16865
+ start);
16707
16866
  _upb_Decoder_Trace(d, 'M');
16708
16867
  return ptr;
16709
16868
  }
@@ -16922,14 +17081,6 @@ typedef struct {
16922
17081
  _upb_mapsorter sorter;
16923
17082
  } upb_encstate;
16924
17083
 
16925
- static size_t upb_roundup_pow2(size_t bytes) {
16926
- size_t ret = 128;
16927
- while (ret < bytes) {
16928
- ret *= 2;
16929
- }
16930
- return ret;
16931
- }
16932
-
16933
17084
  UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) {
16934
17085
  UPB_ASSERT(s != kUpb_EncodeStatus_Ok);
16935
17086
  e->status = s;
@@ -16945,7 +17096,9 @@ UPB_NOINLINE static char* encode_growbuffer(char* ptr, upb_encstate* e,
16945
17096
  size_t bytes) {
16946
17097
  size_t old_size = e->limit - e->buf;
16947
17098
  size_t needed_size = bytes + (e->limit - ptr);
16948
- size_t new_size = upb_roundup_pow2(needed_size);
17099
+ if (needed_size < bytes) encode_err(e, kUpb_EncodeStatus_OutOfMemory);
17100
+ size_t new_size = upb_RoundUpToPowerOfTwo(UPB_MAX(128, needed_size));
17101
+ if (new_size == old_size) encode_err(e, kUpb_EncodeStatus_OutOfMemory);
16949
17102
  void* old_buf = e->buf == &initial_buf_sentinel ? NULL : (void*)e->buf;
16950
17103
  char* new_buf = upb_Arena_Realloc(e->arena, old_buf, old_size, new_size);
16951
17104