The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) https://grpc.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
5.9 KiB

#include "upbc/message_layout.h"
Squashed 'third_party/upb/' changes from d8f3d6f9d4..ce1a399a19 ce1a399a19 Text format serializer for upb_msg (#242) 888f35cae6 Merge pull request #241 from haberman/conformance-fixes 46b93f8cea A bit more cleanup in the decoder. ad2eb65a4b Refactored conformance_upb to use reflection, and fixed a decoder bug. a202c5f84d Merge pull request #234 from haberman/parser 4c974cf72d Fixed generated files. 9a870d957f Removed upb_decframe and made ptr an explicit parameter and return. a6c54729df Added UPB_ASSUME(), to work around warnings when optimization is enabled: 9e1f89ef2c Merge pull request #224 from haberman/maps ce0496eb86 Merge branch 'master' into maps e911aae5f6 Factored upb_map_entry into a shared place. 4c1a97ae9c Merge branch 'master' into maps 59fe620fa0 Merge branch 'maps' of github.com:haberman/upb into maps 744f8588da Cleanup to remove END_GROUP from descriptortype -> type tables. f9efbcd5d6 Added missing append fallback. c4b64e6a20 Slight simplification: NULL arena will avoid creating a new sub-object. d541566a7b Moved upb_array_new() to upb/reflection.h where it belongs. 059f226d41 Unit tests for maps generated code. 520ddc1f11 c89 fixes. 806c8c9c6e Removed obsolete testing files. 2a85bef825 Generated code interface for maps is complete, though not yet tested. 7f5fe52dfa Fixes for non-C89 code. 6c2d732082 Fixed upb's map parsing to overwrite existing elements. 090a0c33a4 Fixed VLA error and rewrote the map parsing code to be clearer. 0fbae939d2 Removed stray fprintf(). 572ba75d1c Removed comma after final enumerator. c9135e5276 Fixed the build. d040aa1302 Merge branch 'master' into maps e18541a9dd Added some missing files. 92509cc3b2 Rename lua_test. 382f92a87f Maps encode and decode successfully! 4c57b1fefd More progress on Lua extension. d6c3152c0b Added more Lua tests that are passing. ae66e571d4 Fixed some bugs and added a few more tests. bfc86d3577 Fixed many bugs, basic Lua test passes! b518b06d75 Lua test program is loaded successfully. 6ae4a2694c Merge branch 'maps' of github.com:haberman/upb into maps cc6db9fb0b Fixed crash bug. 88d996132e Added Lua main.c test driver program. 626ec4bfcf Everything builds, test pass except test_decoder. 5239655b99 WIP. 23825332e1 WIP. 27b95c969a WIP. 9a360ad43d Moved legacy_msg_reflection.{c,h} -> reflection.{c.h}. dc58b657ee New reflection API doesn't need types as parameters for map/array. c486da3970 WIP. b76040cfcc Merge branch 'maps' of github.com:haberman/upb into maps cc8e894b63 Merge branch 'master' into maps 946880c105 Merge branch 'master' into maps 1461da5056 WIP. 0a07f2714b Merge branch 'master' into maps 18de110b00 Merge branch 'master' into maps 283857f308 WIP. 5dea3f8486 Merge branch 'master' into maps 07ac6f0e8e Merge branch 'master' into maps 0c64c4b594 WIP. git-subtree-dir: third_party/upb git-subtree-split: ce1a399a19f11683d58ba4c2569ec3fdd5a67621
5 years ago
#include "google/protobuf/descriptor.pb.h"
namespace upbc {
namespace protobuf = ::google::protobuf;
static int64_t DivRoundUp(int64_t a, int64_t b) {
ABSL_ASSERT(a >= 0);
ABSL_ASSERT(b > 0);
return (a + b - 1) / b;
}
MessageLayout::Size MessageLayout::Place(
MessageLayout::SizeAndAlign size_and_align) {
Size offset = size_;
offset.AlignUp(size_and_align.align);
size_ = offset;
size_.Add(size_and_align.size);
//maxalign_.MaxFrom(size_and_align.align);
maxalign_.MaxFrom(size_and_align.size);
return offset;
}
bool MessageLayout::HasHasbit(const protobuf::FieldDescriptor* field) {
return field->file()->syntax() == protobuf::FileDescriptor::SYNTAX_PROTO2 &&
field->label() != protobuf::FieldDescriptor::LABEL_REPEATED &&
Squashed 'third_party/upb/' changes from d8f3d6f9d4..ce1a399a19 ce1a399a19 Text format serializer for upb_msg (#242) 888f35cae6 Merge pull request #241 from haberman/conformance-fixes 46b93f8cea A bit more cleanup in the decoder. ad2eb65a4b Refactored conformance_upb to use reflection, and fixed a decoder bug. a202c5f84d Merge pull request #234 from haberman/parser 4c974cf72d Fixed generated files. 9a870d957f Removed upb_decframe and made ptr an explicit parameter and return. a6c54729df Added UPB_ASSUME(), to work around warnings when optimization is enabled: 9e1f89ef2c Merge pull request #224 from haberman/maps ce0496eb86 Merge branch 'master' into maps e911aae5f6 Factored upb_map_entry into a shared place. 4c1a97ae9c Merge branch 'master' into maps 59fe620fa0 Merge branch 'maps' of github.com:haberman/upb into maps 744f8588da Cleanup to remove END_GROUP from descriptortype -> type tables. f9efbcd5d6 Added missing append fallback. c4b64e6a20 Slight simplification: NULL arena will avoid creating a new sub-object. d541566a7b Moved upb_array_new() to upb/reflection.h where it belongs. 059f226d41 Unit tests for maps generated code. 520ddc1f11 c89 fixes. 806c8c9c6e Removed obsolete testing files. 2a85bef825 Generated code interface for maps is complete, though not yet tested. 7f5fe52dfa Fixes for non-C89 code. 6c2d732082 Fixed upb's map parsing to overwrite existing elements. 090a0c33a4 Fixed VLA error and rewrote the map parsing code to be clearer. 0fbae939d2 Removed stray fprintf(). 572ba75d1c Removed comma after final enumerator. c9135e5276 Fixed the build. d040aa1302 Merge branch 'master' into maps e18541a9dd Added some missing files. 92509cc3b2 Rename lua_test. 382f92a87f Maps encode and decode successfully! 4c57b1fefd More progress on Lua extension. d6c3152c0b Added more Lua tests that are passing. ae66e571d4 Fixed some bugs and added a few more tests. bfc86d3577 Fixed many bugs, basic Lua test passes! b518b06d75 Lua test program is loaded successfully. 6ae4a2694c Merge branch 'maps' of github.com:haberman/upb into maps cc6db9fb0b Fixed crash bug. 88d996132e Added Lua main.c test driver program. 626ec4bfcf Everything builds, test pass except test_decoder. 5239655b99 WIP. 23825332e1 WIP. 27b95c969a WIP. 9a360ad43d Moved legacy_msg_reflection.{c,h} -> reflection.{c.h}. dc58b657ee New reflection API doesn't need types as parameters for map/array. c486da3970 WIP. b76040cfcc Merge branch 'maps' of github.com:haberman/upb into maps cc8e894b63 Merge branch 'master' into maps 946880c105 Merge branch 'master' into maps 1461da5056 WIP. 0a07f2714b Merge branch 'master' into maps 18de110b00 Merge branch 'master' into maps 283857f308 WIP. 5dea3f8486 Merge branch 'master' into maps 07ac6f0e8e Merge branch 'master' into maps 0c64c4b594 WIP. git-subtree-dir: third_party/upb git-subtree-split: ce1a399a19f11683d58ba4c2569ec3fdd5a67621
5 years ago
!field->containing_oneof() &&
!field->containing_type()->options().map_entry();
}
MessageLayout::SizeAndAlign MessageLayout::SizeOf(
const protobuf::FieldDescriptor* field) {
if (field->is_repeated()) {
return {{4, 8}, {4, 8}}; // Pointer to array object.
} else {
return SizeOfUnwrapped(field);
}
}
MessageLayout::SizeAndAlign MessageLayout::SizeOfUnwrapped(
const protobuf::FieldDescriptor* field) {
switch (field->cpp_type()) {
case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
return {{4, 8}, {4, 8}}; // Pointer to message.
case protobuf::FieldDescriptor::CPPTYPE_STRING:
return {{8, 16}, {4, 8}}; // upb_strview
case protobuf::FieldDescriptor::CPPTYPE_BOOL:
return {{1, 1}, {1, 1}};
case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
case protobuf::FieldDescriptor::CPPTYPE_INT32:
case protobuf::FieldDescriptor::CPPTYPE_UINT32:
return {{4, 4}, {4, 4}};
default:
return {{8, 8}, {8, 8}};
}
}
int64_t MessageLayout::FieldLayoutRank(const protobuf::FieldDescriptor* field) {
// Order:
// 1, 2, 3. primitive fields (8, 4, 1 byte)
// 4. string fields
// 5. submessage fields
// 6. repeated fields
//
// This has the following nice properties:
//
// 1. padding alignment is (nearly) minimized.
// 2. fields that might have defaults (1-4) are segregated
// from fields that are always zero-initialized (5-7).
//
// We skip oneof fields, because they are emitted in a separate pass.
int64_t rank;
if (field->containing_oneof()) {
fprintf(stderr, "shouldn't have oneofs here.\n");
abort();
} else if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED) {
rank = 6;
} else {
switch (field->cpp_type()) {
case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
rank = 5;
break;
case protobuf::FieldDescriptor::CPPTYPE_STRING:
rank = 4;
break;
case protobuf::FieldDescriptor::CPPTYPE_BOOL:
rank = 3;
break;
case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
case protobuf::FieldDescriptor::CPPTYPE_INT32:
case protobuf::FieldDescriptor::CPPTYPE_UINT32:
rank = 2;
break;
default:
rank = 1;
break;
}
}
// Break ties with field number.
return (rank << 29) | field->number();
}
void MessageLayout::ComputeLayout(const protobuf::Descriptor* descriptor) {
size_ = Size{0, 0};
maxalign_ = Size{0, 0};
if (descriptor->options().map_entry()) {
// Map entries aren't actually stored, they are only used during parsing.
// For parsing, it helps a lot if all map entry messages have the same
// layout.
SizeAndAlign size{{8, 16}, {4, 8}}; // upb_strview
field_offsets_[descriptor->FindFieldByNumber(1)] = Place(size);
field_offsets_[descriptor->FindFieldByNumber(2)] = Place(size);
} else {
PlaceNonOneofFields(descriptor);
PlaceOneofFields(descriptor);
}
// Align overall size up to max size.
size_.AlignUp(maxalign_);
}
void MessageLayout::PlaceNonOneofFields(
const protobuf::Descriptor* descriptor) {
std::vector<const protobuf::FieldDescriptor*> field_order;
for (int i = 0; i < descriptor->field_count(); i++) {
const protobuf::FieldDescriptor* field = descriptor->field(i);
if (!field->containing_oneof()) {
field_order.push_back(descriptor->field(i));
}
}
std::sort(field_order.begin(), field_order.end(),
[](const protobuf::FieldDescriptor* a,
const protobuf::FieldDescriptor* b) {
return FieldLayoutRank(a) < FieldLayoutRank(b);
});
// Place/count hasbits.
int hasbit_count = 0;
for (auto field : field_order) {
if (HasHasbit(field)) {
// We don't use hasbit 0, so that 0 can indicate "no presence" in the
// table. This wastes one hasbit, but we don't worry about it for now.
hasbit_indexes_[field] = ++hasbit_count;
}
}
// Place hasbits at the beginning.
int64_t hasbit_bytes = DivRoundUp(hasbit_count, 8);
Place(SizeAndAlign{{hasbit_bytes, hasbit_bytes}, {1, 1}});
// Place non-oneof fields.
for (auto field : field_order) {
field_offsets_[field] = Place(SizeOf(field));
}
}
void MessageLayout::PlaceOneofFields(const protobuf::Descriptor* descriptor) {
std::vector<const protobuf::OneofDescriptor*> oneof_order;
for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
oneof_order.push_back(descriptor->oneof_decl(i));
}
std::sort(oneof_order.begin(), oneof_order.end(),
[](const protobuf::OneofDescriptor* a,
const protobuf::OneofDescriptor* b) {
return a->full_name() < b->full_name();
});
for (auto oneof : oneof_order) {
SizeAndAlign oneof_maxsize{{0, 0}, {0, 0}};
// Calculate max size.
for (int i = 0; i < oneof->field_count(); i++) {
oneof_maxsize.MaxFrom(SizeOf(oneof->field(i)));
}
// Place discriminator enum and data.
Size data = Place(oneof_maxsize);
Size discriminator = Place(SizeAndAlign{{4, 4}, {4, 4}});
oneof_case_offsets_[oneof] = discriminator;
for (int i = 0; i < oneof->field_count(); i++) {
field_offsets_[oneof->field(i)] = data;
}
}
}
} // namespace upbc