message_layout.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright (c) 2009-2021, Google LLC
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are met:
  6. // * Redistributions of source code must retain the above copyright
  7. // notice, this list of conditions and the following disclaimer.
  8. // * Redistributions in binary form must reproduce the above copyright
  9. // notice, this list of conditions and the following disclaimer in the
  10. // documentation and/or other materials provided with the distribution.
  11. // * Neither the name of Google LLC nor the
  12. // names of its contributors may be used to endorse or promote products
  13. // derived from this software without specific prior written permission.
  14. //
  15. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. // ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
  19. // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. #include "upbc/message_layout.h"
  26. #include "google/protobuf/descriptor.pb.h"
  27. namespace upbc {
  28. namespace protobuf = ::google::protobuf;
  29. static int64_t DivRoundUp(int64_t a, int64_t b) {
  30. ABSL_ASSERT(a >= 0);
  31. ABSL_ASSERT(b > 0);
  32. return (a + b - 1) / b;
  33. }
  34. MessageLayout::Size MessageLayout::Place(
  35. MessageLayout::SizeAndAlign size_and_align) {
  36. Size offset = size_;
  37. offset.AlignUp(size_and_align.align);
  38. size_ = offset;
  39. size_.Add(size_and_align.size);
  40. // maxalign_.MaxFrom(size_and_align.align);
  41. maxalign_.MaxFrom(size_and_align.size);
  42. return offset;
  43. }
  44. bool MessageLayout::HasHasbit(const protobuf::FieldDescriptor* field) {
  45. return field->has_presence() && !field->real_containing_oneof() &&
  46. !field->containing_type()->options().map_entry();
  47. }
  48. MessageLayout::SizeAndAlign MessageLayout::SizeOf(
  49. const protobuf::FieldDescriptor* field) {
  50. if (field->is_repeated()) {
  51. return {{4, 8}, {4, 8}}; // Pointer to array object.
  52. } else {
  53. return SizeOfUnwrapped(field);
  54. }
  55. }
  56. MessageLayout::SizeAndAlign MessageLayout::SizeOfUnwrapped(
  57. const protobuf::FieldDescriptor* field) {
  58. switch (field->cpp_type()) {
  59. case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
  60. return {{4, 8}, {4, 8}}; // Pointer to message.
  61. case protobuf::FieldDescriptor::CPPTYPE_STRING:
  62. return {{8, 16}, {4, 8}}; // upb_StringView
  63. case protobuf::FieldDescriptor::CPPTYPE_BOOL:
  64. return {{1, 1}, {1, 1}};
  65. case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
  66. case protobuf::FieldDescriptor::CPPTYPE_INT32:
  67. case protobuf::FieldDescriptor::CPPTYPE_UINT32:
  68. case protobuf::FieldDescriptor::CPPTYPE_ENUM:
  69. return {{4, 4}, {4, 4}};
  70. case protobuf::FieldDescriptor::CPPTYPE_INT64:
  71. case protobuf::FieldDescriptor::CPPTYPE_UINT64:
  72. case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
  73. return {{8, 8}, {8, 8}};
  74. }
  75. assert(false);
  76. return {{-1, -1}, {-1, -1}};
  77. }
  78. int64_t MessageLayout::FieldLayoutRank(const protobuf::FieldDescriptor* field) {
  79. // Order:
  80. // 1, 2, 3. primitive fields (8, 4, 1 byte)
  81. // 4. string fields
  82. // 5. submessage fields
  83. // 6. repeated fields
  84. //
  85. // This has the following nice properties:
  86. //
  87. // 1. padding alignment is (nearly) minimized.
  88. // 2. fields that might have defaults (1-4) are segregated
  89. // from fields that are always zero-initialized (5-7).
  90. //
  91. // We skip oneof fields, because they are emitted in a separate pass.
  92. int64_t rank;
  93. if (field->containing_oneof()) {
  94. fprintf(stderr, "shouldn't have oneofs here.\n");
  95. abort();
  96. } else if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED) {
  97. rank = 6;
  98. } else {
  99. switch (field->cpp_type()) {
  100. case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
  101. rank = 5;
  102. break;
  103. case protobuf::FieldDescriptor::CPPTYPE_STRING:
  104. rank = 4;
  105. break;
  106. case protobuf::FieldDescriptor::CPPTYPE_BOOL:
  107. rank = 3;
  108. break;
  109. case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
  110. case protobuf::FieldDescriptor::CPPTYPE_INT32:
  111. case protobuf::FieldDescriptor::CPPTYPE_UINT32:
  112. rank = 2;
  113. break;
  114. default:
  115. rank = 1;
  116. break;
  117. }
  118. }
  119. // Break ties with field number.
  120. return (rank << 29) | field->number();
  121. }
  122. void MessageLayout::ComputeLayout(const protobuf::Descriptor* descriptor) {
  123. size_ = Size{0, 0};
  124. maxalign_ = Size{8, 8};
  125. if (descriptor->options().map_entry()) {
  126. // Map entries aren't actually stored, they are only used during parsing.
  127. // For parsing, it helps a lot if all map entry messages have the same
  128. // layout.
  129. SizeAndAlign size{{8, 16}, {4, 8}}; // upb_StringView
  130. field_offsets_[descriptor->FindFieldByNumber(1)] = Place(size);
  131. field_offsets_[descriptor->FindFieldByNumber(2)] = Place(size);
  132. } else {
  133. PlaceNonOneofFields(descriptor);
  134. PlaceOneofFields(descriptor);
  135. }
  136. // Align overall size up to max size.
  137. size_.AlignUp(maxalign_);
  138. }
  139. void MessageLayout::PlaceNonOneofFields(
  140. const protobuf::Descriptor* descriptor) {
  141. std::vector<const protobuf::FieldDescriptor*> field_order;
  142. for (int i = 0; i < descriptor->field_count(); i++) {
  143. const protobuf::FieldDescriptor* field = descriptor->field(i);
  144. if (!field->containing_oneof()) {
  145. field_order.push_back(descriptor->field(i));
  146. }
  147. }
  148. std::sort(field_order.begin(), field_order.end(),
  149. [](const protobuf::FieldDescriptor* a,
  150. const protobuf::FieldDescriptor* b) {
  151. return FieldLayoutRank(a) < FieldLayoutRank(b);
  152. });
  153. // Place/count hasbits.
  154. hasbit_count_ = 0;
  155. required_count_ = 0;
  156. for (auto field : FieldHotnessOrder(descriptor)) {
  157. if (HasHasbit(field)) {
  158. // We don't use hasbit 0, so that 0 can indicate "no presence" in the
  159. // table. This wastes one hasbit, but we don't worry about it for now.
  160. int index = ++hasbit_count_;
  161. hasbit_indexes_[field] = index;
  162. if (field->is_required()) {
  163. if (index > 63) {
  164. // This could be fixed in the decoder without too much trouble. But
  165. // we expect this to be so rare that we don't worry about it for now.
  166. std::cerr << "upb does not support messages with more than 63 "
  167. "required fields: "
  168. << field->full_name() << "\n";
  169. exit(1);
  170. }
  171. required_count_++;
  172. }
  173. }
  174. }
  175. // Place hasbits at the beginning.
  176. hasbit_bytes_ = hasbit_count_ ? DivRoundUp(hasbit_count_ + 1, 8) : 0;
  177. Place(SizeAndAlign{{hasbit_bytes_, hasbit_bytes_}, {1, 1}});
  178. // Place non-oneof fields.
  179. for (auto field : field_order) {
  180. field_offsets_[field] = Place(SizeOf(field));
  181. }
  182. }
  183. void MessageLayout::PlaceOneofFields(const protobuf::Descriptor* descriptor) {
  184. std::vector<const protobuf::OneofDescriptor*> oneof_order;
  185. for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
  186. oneof_order.push_back(descriptor->oneof_decl(i));
  187. }
  188. std::sort(oneof_order.begin(), oneof_order.end(),
  189. [](const protobuf::OneofDescriptor* a,
  190. const protobuf::OneofDescriptor* b) {
  191. return a->full_name() < b->full_name();
  192. });
  193. for (auto oneof : oneof_order) {
  194. SizeAndAlign oneof_maxsize{{0, 0}, {0, 0}};
  195. // Calculate max size.
  196. for (int i = 0; i < oneof->field_count(); i++) {
  197. oneof_maxsize.MaxFrom(SizeOf(oneof->field(i)));
  198. }
  199. // Place discriminator enum and data.
  200. Size data = Place(oneof_maxsize);
  201. Size discriminator = Place(SizeAndAlign{{4, 4}, {4, 4}});
  202. oneof_case_offsets_[oneof] = discriminator;
  203. for (int i = 0; i < oneof->field_count(); i++) {
  204. field_offsets_[oneof->field(i)] = data;
  205. }
  206. }
  207. }
  208. } // namespace upbc