* Allocates slightly less than a power-of-two buffer size when encoding, which avoids pathological sizes when combined with arena overhead.
* Takes the whole available block, minimizing intermediate allocations and copying
* Frees intermediate block allocations, which results in retaining about 45% less memory on average
* Returns unused memory from the last block back to the arena for future use
* Does not align the arena `end` pointer, so repeatedly serializing small protos or proto fields does not pay an up-to-7-byte overhead each
PiperOrigin-RevId: 912234452
The pyi generator now includes Kythe annotations for:
* Extension field constants (e.g., `EXTENSION_FIELD`).
* Field number constants (e.g., `STRING_FIELD_FIELD_NUMBER`).
* `Create` methods in generated Stubby client classes.
These annotations allow the Python indexer to link these generated symbols back to their definitions in the `.proto` files.
PiperOrigin-RevId: 852971617
This works around llvm/llvm-project#47432 which is causing crashes during compilation for some users, by not aligning the indirect branch target when SEH is enabled.
Fixes#24758
PiperOrigin-RevId: 845310735
Prior to this CL, whenever we parsed a size we would immediately verify that size against the current EpsCopyInputStream limit. This was correct but was unnecessarily expensive, especially since it was redundant with other checks we perform when parsing sub-messages or strings.
In this CL, we remove the eager check when parsing a size, and we perform more targeted and optimized bounds checks at the points where these checks are actually needed. This brings us more into line with how EpsCopyInputStream works in C++.
In particular:
- We never need to check against the pushed limit, because `IsDone()` is already checking to make sure we ended at the correct limit.
- When reading a string (either to alias or to copy), we only need to check against the buffer end, not the limit. This could result in us reading a string that extends beyond the current limit, but the parse will then fail, and the string fields will still be safe to read (even if nonsense).
PiperOrigin-RevId: 834415733
https://github.com/protocolbuffers/protobuf/issues/23306
Since there's a measurable performance cost (~12% for a long varint heavy message) on little and mid size cores, these instructions aren't unconditionally emitted even though they're compatible (CPUs lacking FEAT_BTI interpret them as HINT/NOP). Even with these extra instructions, the assembly path is still much faster than the generic one.
PiperOrigin-RevId: 834093313
Instead of giving every MiniTable two parallel arrays (fields and subs), we now have one block of memory that contains both lists.
For sub-message or enum fields, the `upb_MiniTableField` now contains a byte offset to where the `upb_MiniTable*` or `upb_MiniTableEnum*` can be found.
The new design offers several benefits:
1. The sub-table requires fewer pointer-chasing indirections to find.
2. We no longer need the `upb_MiniTable*` to find the sub-MiniTable -- the `upb_MiniTableField*` is enough now. So APIs like `upb_MiniTable_GetSubMessageTable()` now require fewer parameters.
3. This unifies fields and extensions -- both can now find a sub-table using exactly the same code, with no need to distinguish between them.
We still benefit from having two lists. If we tried to put the sub-table pointer directly into `upb_MiniTableField`, it would double the size of `upb_MiniTableField` from 12 to 24 bytes, due to alignment. Using the current design, sub-message fields only take 20 bytes, while others take 12, so this design is an improvement even if 100% of fields are sub-message fields.
PiperOrigin-RevId: 833329706
The previous CL's approach of using `__attribute__((weakref()))` was not actually behaving as expected, and the unit tests were not sufficient to catch this.
We now use inline assembly to achieve the functionality that we thought we were getting with `__attribute__((weakref()))`. From assembly, we can create a weak symbol whose value is the same as another "stub" symbol in the same file.
Unfortunately we cannot have all of our weak symbols reference a single placeholder "empty" message, due to a bug I discovered in the LLVM linker and reported in https://github.com/llvm/llvm-project/issues/167262
If and when that bug is fixed, we should be able to get optimal tree shaking behavior, even on iOS.
PiperOrigin-RevId: 831396179
To do this, we use `__attribute__((weakref()))` to weakly reference a placeholder definition for tree shaken sub-messages. This provides the same tree shaking behavior we had before, but without needing an extra indirection. If we had discovered this technique before, we would have had no reason to add the indirection in cl/640369522.
This will reduce the code size and memory overhead of any MiniTables with sub-messages in them, because we no longer need an extra `void*` per sub-message field to store the extra indirect pointer.
It also should improve efficiency a bit since there is one fewer indirection when recursing into a sub-message field.
PiperOrigin-RevId: 829022414
I couldn't get the compiler to emit the jump table I wanted so it's written as inline asm. This benchmarked as 1% faster in the overall encode benchmarks than doing the same size calculation and a normal loop.
PiperOrigin-RevId: 767814597
1. The unknown field depth comparison had an off by one error compared with the logic in decode/encode.
2. The functions to limit encode/decode depth were not working properly when the max depth was unset, because the "default" depth was represented as 0 which did not trigger the min operation.
3. The regular (non-"effective") functions `upb_DecodeOptions_GetMaxDepth()` and `upb_EncodeOptions_GetMaxDepth()` are footguns that do not belong in the header (as illustrated by the bug in (2). So moved them to the source file.
PiperOrigin-RevId: 760911128
- Remove the unnecessary distinct types of upb_value vs upb_tabvalue (notably contrasted with upb_MessageValue which is widely used and very different). Presumably there was legacy where it was expected we might evolve these separately, but in practice we just have noise converting between the two structs which have identical definitions.
- Rename upb_tabkey to "upb_key" as a clear parallel to "upb_value"
- Just do normal assignment for one upb_value to another upb_value (I think some of these were C89 remnants, others cleaned up from the unnecessary type duality).
- Make the sentinel value handling in inttable more explicit, including rename upb_arrhas() with is_inttable_sentinel() since we eg check it in an assert of something before we were going to insert it into the table where we're checking for sentinel of a thing thats not in an array, so arrhas didn't really make sense.
PiperOrigin-RevId: 734933132
When the kUpb_EncodeOption_Deterministic option is set, inttable entries will be encoded in a deterministic order but not necessarily in a sorted order by its key.
PiperOrigin-RevId: 734614535
Prior to this change, the asan guard size meant that the fast path for realloc never triggered in asan mode, masking the fact that the realloc fast path did not unpoison the newly extended memory region. This change also poisons the "previous" memory area if an alloc+copy is performed, to match the C realloc behavior of freeing the previous memory.
PiperOrigin-RevId: 734278556
This is a no-op change, but would prepare us to add the int table as an alternative data structure for primitive map keys.
PiperOrigin-RevId: 726536300
Previously, extensions and unknown fields were stored on opposite ends of a growing buffer:
```
|------unknown fields-------|---------unallocated space------|--extensions---|
```
Unknown fields were appended and extensions were prepended during parse. When either side ran into the other, the buffer was reallocated to fit, rounding up to the nearest power of 2. This meant that for a proto with 70,000 bytes of unknown fields, the total memory consumed could be up to 128+256+512+1024+2048+4096+8192+16384+32768+65536+131072=262016 bytes allocated in the arena. In the more common case of a large, length-delimited field it'd be just 131072 bytes; but as a 3.74x increase or a 1.87x increase, that's a lot of extra memory.
The new representation still does exponential reallocation, but only for pointers to normal arena allocations. We exploit the fact that arena allocations are aligned to store data about whether the pointer is to an extension or a `upb_StringView` of unknown fields in the low bits of the pointer itself. This costs three pointers of overhead per unknown field and one pointer of overhead per extension, but that's a fixed overhead - we won't over-allocate large buffers for large unknown fields. If this overhead proves to be a problem, more compact representations could be implemented.
In addition, because unknown field bytes are now in their own allocations, they are pointer stable - in the future, this will allow us to exploit aliasing (when enabled during parse) for both unknown fields and lazy extensions (parsed from unknown fields), which can greatly reduce memory use for messages with a lot of unknown, string, or bytes fields.
PiperOrigin-RevId: 708058272
Before we were trying to work around the fact that we don't know the default depth limit. The logic is simpler and more robust if we take the default into account.
PiperOrigin-RevId: 698856552