Skip to content

Commit e539f61

Browse files
Add MicroString support for DynamicMessage types.
This support is currently experimental and enabled via opt-in flag. PiperOrigin-RevId: 743666524
1 parent f1e3262 commit e539f61

12 files changed

+312
-129
lines changed

src/google/protobuf/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@ cc_library(
712712
],
713713
deps = [
714714
":internal_visibility",
715+
":micro_string",
715716
":port",
716717
":protobuf_lite",
717718
"//src/google/protobuf/io",

src/google/protobuf/dynamic_message.cc

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include "google/protobuf/map.h"
6565
#include "google/protobuf/map_field.h"
6666
#include "google/protobuf/message_lite.h"
67+
#include "google/protobuf/micro_string.h"
6768
#include "google/protobuf/port.h"
6869
#include "google/protobuf/repeated_field.h"
6970
#include "google/protobuf/unknown_field_set.h"
@@ -79,6 +80,7 @@ using internal::ExtensionSet;
7980

8081

8182
using internal::ArenaStringPtr;
83+
using internal::MicroString;
8284

8385
// ===================================================================
8486
// Some helper tables and functions...
@@ -242,6 +244,10 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
242244
case FieldDescriptor::CppStringType::kCord:
243245
return sizeof(absl::Cord);
244246
case FieldDescriptor::CppStringType::kView:
247+
if (internal::EnableExperimentalMicroString()) {
248+
return sizeof(MicroString);
249+
}
250+
[[fallthrough]];
245251
case FieldDescriptor::CppStringType::kString:
246252
return sizeof(ArenaStringPtr);
247253
}
@@ -253,6 +259,17 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
253259
return 0;
254260
}
255261

262+
uint32_t FieldFlags(const FieldDescriptor* field) {
263+
if (internal::EnableExperimentalMicroString() && //
264+
!field->is_repeated() && //
265+
!field->is_extension() && //
266+
field->cpp_type() == field->CPPTYPE_STRING && //
267+
field->cpp_string_type() == FieldDescriptor::CppStringType::kView) {
268+
return internal::kMicroStringMask;
269+
}
270+
return 0;
271+
}
272+
256273
inline int DivideRoundingUp(int i, int j) { return (i + (j - 1)) / j; }
257274

258275
static const int kSafeAlignment = sizeof(uint64_t);
@@ -326,7 +343,11 @@ class DynamicMessage final : public Message {
326343
static void* NewImpl(const void* prototype, void* mem, Arena* arena);
327344
static void DestroyImpl(MessageLite& ptr);
328345

329-
void* MutableRaw(int i);
346+
// If `T` is not `void`, it will mask bits off the offset via alignment.
347+
// Used to remove feature masks that are part of the reflection
348+
// implementation.
349+
template <typename T = void>
350+
T* MutableRaw(int i);
330351
void* MutableExtensionsRaw();
331352
void* MutableWeakFieldMapRaw();
332353
void* MutableOneofCaseRaw(int i);
@@ -416,8 +437,13 @@ DynamicMessage::DynamicMessage(DynamicMessageFactory::TypeInfo* type_info,
416437
SharedCtor(lock_factory);
417438
}
418439

419-
inline void* DynamicMessage::MutableRaw(int i) {
420-
return OffsetToPointer(type_info_->offsets[i]);
440+
template <typename T>
441+
inline T* DynamicMessage::MutableRaw(int i) {
442+
uint32_t mask = ~uint32_t{};
443+
if constexpr (!std::is_void_v<T>) {
444+
mask = ~(uint32_t{alignof(T)} - 1);
445+
}
446+
return reinterpret_cast<T*>(OffsetToPointer(type_info_->offsets[i] & mask));
421447
}
422448
inline void* DynamicMessage::MutableExtensionsRaw() {
423449
return OffsetToPointer(type_info_->extensions_offset);
@@ -513,6 +539,16 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
513539
}
514540
break;
515541
case FieldDescriptor::CppStringType::kView:
542+
if (internal::EnableExperimentalMicroString() &&
543+
!field->is_repeated()) {
544+
auto* str = ::new (MutableRaw<MicroString>(i)) MicroString();
545+
if (field->has_default_value()) {
546+
// TODO: Use an unowned block instead.
547+
str->Set(field->default_value_string(), arena);
548+
}
549+
break;
550+
}
551+
[[fallthrough]];
516552
case FieldDescriptor::CppStringType::kString:
517553
if (!field->is_repeated()) {
518554
ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
@@ -600,6 +636,11 @@ DynamicMessage::~DynamicMessage() {
600636
delete *reinterpret_cast<absl::Cord**>(field_ptr);
601637
break;
602638
case FieldDescriptor::CppStringType::kView:
639+
if (internal::EnableExperimentalMicroString()) {
640+
reinterpret_cast<MicroString*>(field_ptr)->Destroy();
641+
break;
642+
}
643+
[[fallthrough]];
603644
case FieldDescriptor::CppStringType::kString: {
604645
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
605646
break;
@@ -661,6 +702,11 @@ DynamicMessage::~DynamicMessage() {
661702
reinterpret_cast<absl::Cord*>(field_ptr)->~Cord();
662703
break;
663704
case FieldDescriptor::CppStringType::kView:
705+
if (internal::EnableExperimentalMicroString()) {
706+
MutableRaw<MicroString>(i)->Destroy();
707+
break;
708+
}
709+
[[fallthrough]];
664710
case FieldDescriptor::CppStringType::kString: {
665711
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
666712
break;
@@ -868,7 +914,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
868914
if (!InRealOneof(type->field(i))) {
869915
int field_size = FieldSpaceUsed(type->field(i));
870916
size = AlignTo(size, std::min(kSafeAlignment, field_size));
871-
offsets[i] = size;
917+
offsets[i] = size | FieldFlags(type->field(i));
872918
size += field_size;
873919
}
874920
}
@@ -893,11 +939,11 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock(
893939
for (int j = 0; j < type->real_oneof_decl(i)->field_count(); j++) {
894940
const FieldDescriptor* field = type->real_oneof_decl(i)->field(j);
895941
// oneof fields are not accessed through offsets, but we still have the
896-
// entry from a legacy implementation. This should be removed at some
897-
// point.
942+
// entry for each.
898943
// Mark the field to prevent unintentional access through reflection.
899944
// Don't use the top bit because that is for unused fields.
900-
offsets[field->index()] = internal::kInvalidFieldOffsetTag;
945+
offsets[field->index()] =
946+
internal::kInvalidFieldOffsetTag | FieldFlags(field);
901947
}
902948
}
903949

0 commit comments

Comments
 (0)