PROTOBUF_SYNC_PIPER
pull/10325/head
Sandy Zhang 3 years ago
parent b2aca61f4d
commit aebdd0885f
  1. 25
      CHANGES.txt
  2. 2
      Protobuf.podspec
  3. 2
      conformance/failure_list_php.txt
  4. 3
      conformance/failure_list_php_c.txt
  5. 3
      conformance/failure_list_ruby.txt
  6. 2
      csharp/Google.Protobuf.Tools.nuspec
  7. 18
      csharp/protos/unittest_issues.proto
  8. 618
      csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs
  9. 63
      csharp/src/Google.Protobuf.Test/ParsingPrimitivesTest.cs
  10. 61
      csharp/src/Google.Protobuf.Test/WritingPrimitivesTest.cs
  11. BIN
      csharp/src/Google.Protobuf.Test/testprotos.pb
  12. 2
      csharp/src/Google.Protobuf/Google.Protobuf.csproj
  13. 6
      java/README.md
  14. 2
      java/bom/pom.xml
  15. 2
      java/core/pom.xml
  16. 2
      java/kotlin-lite/pom.xml
  17. 2
      java/kotlin/pom.xml
  18. 5
      java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
  19. 2
      java/lite.md
  20. 2
      java/lite/pom.xml
  21. 2
      java/pom.xml
  22. 4
      java/protoc/pom.xml
  23. 2
      java/util/pom.xml
  24. 12
      kokoro/macos/php7.0_mac/build.sh
  25. 12
      kokoro/macos/php7.3_mac/build.sh
  26. 20
      kokoro/macos/php74/build.sh
  27. 2
      kokoro/macos/php74/continuous.cfg
  28. 2
      kokoro/macos/php74/presubmit.cfg
  29. 20
      kokoro/macos/php80/build.sh
  30. 2
      kokoro/macos/php80/continuous.cfg
  31. 2
      kokoro/macos/php80/presubmit.cfg
  32. 36
      kokoro/macos/prepare_build_macos_rc
  33. 3
      kokoro/release/ruby/macos/build_artifacts.sh
  34. 1
      kokoro/release/ruby/macos/ruby/ruby_build.sh
  35. 10
      kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
  36. 8
      objectivec/GPBApi.pbobjc.h
  37. 2
      objectivec/GPBFieldMask.pbobjc.h
  38. 4
      objectivec/GPBStruct.pbobjc.h
  39. 14
      objectivec/GPBType.pbobjc.h
  40. 2
      objectivec/GPBUtilities.m
  41. 1
      objectivec/generate_well_known_types.sh
  42. 2
      php/BUILD.bazel
  43. 5
      php/composer.json
  44. 24
      php/ext/google/protobuf/def.c
  45. 90
      php/ext/google/protobuf/names.c
  46. 3
      php/ext/google/protobuf/names.h
  47. 29
      php/ext/google/protobuf/package.xml
  48. 14
      php/ext/google/protobuf/protobuf.c
  49. 2
      php/ext/google/protobuf/protobuf.h
  50. 16
      php/src/Google/Protobuf/Internal/Descriptor.php
  51. 1
      php/src/Google/Protobuf/Internal/DescriptorPool.php
  52. 3
      php/src/Google/Protobuf/Internal/EnumDescriptor.php
  53. 58
      php/src/Google/Protobuf/Internal/GPBUtil.php
  54. 18
      php/tests/GeneratedClassTest.php
  55. 18
      php/tests/PreviouslyGeneratedClassTest.php
  56. 28
      php/tests/generated_previous/GPBMetadata/ProtoPrevious/TestPreviouslyUnreservedMessage.php
  57. 31
      php/tests/generated_previous/Previous/readonly.php
  58. 1
      php/tests/proto/test_reserved_enum_lower.proto
  59. 1
      php/tests/proto/test_reserved_enum_upper.proto
  60. 1
      php/tests/proto/test_reserved_enum_value_lower.proto
  61. 1
      php/tests/proto/test_reserved_enum_value_upper.proto
  62. 1
      php/tests/proto/test_reserved_message_lower.proto
  63. 1
      php/tests/proto/test_reserved_message_upper.proto
  64. 5
      php/tests/proto_previous/test_previously_unreserved_message.proto
  65. 4
      protobuf_deps.bzl
  66. 6
      protobuf_version.bzl
  67. 4
      protoc-artifacts/pom.xml
  68. 2
      ruby/google-protobuf.gemspec
  69. 4
      ruby/pom.xml
  70. 1
      src/Makefile.am
  71. 1
      src/file_lists.cmake
  72. 2
      src/google/protobuf/arena_unittest.cc
  73. 7
      src/google/protobuf/arenastring.cc
  74. 5
      src/google/protobuf/arenaz_sampler.cc
  75. 4
      src/google/protobuf/arenaz_sampler.h
  76. 25
      src/google/protobuf/arenaz_sampler_test.cc
  77. 4
      src/google/protobuf/compiler/command_line_interface.cc
  78. 1
      src/google/protobuf/compiler/cpp/field.cc
  79. 1
      src/google/protobuf/compiler/cpp/field.h
  80. 8
      src/google/protobuf/compiler/cpp/file.cc
  81. 4
      src/google/protobuf/compiler/cpp/helpers.cc
  82. 82
      src/google/protobuf/compiler/cpp/message.cc
  83. 46
      src/google/protobuf/compiler/cpp/parse_function_generator.cc
  84. 25
      src/google/protobuf/compiler/csharp/csharp_helpers.cc
  85. 12
      src/google/protobuf/compiler/java/enum_field.cc
  86. 12
      src/google/protobuf/compiler/java/enum_field_lite.cc
  87. 5
      src/google/protobuf/compiler/java/generator.h
  88. 36
      src/google/protobuf/compiler/java/message_serialization.h
  89. 124
      src/google/protobuf/compiler/java/message_serialization_unittest.cc
  90. 56
      src/google/protobuf/compiler/java/message_serialization_unittest.proto
  91. 9
      src/google/protobuf/compiler/main.cc
  92. 2
      src/google/protobuf/compiler/objectivec/objectivec_field.cc
  93. 151
      src/google/protobuf/compiler/php/php_generator.cc
  94. 6
      src/google/protobuf/compiler/python/generator.h
  95. 71
      src/google/protobuf/compiler/python/pyi_generator.cc
  96. 25
      src/google/protobuf/compiler/python/pyi_generator.h
  97. 162
      src/google/protobuf/generated_message_tctable_impl.h
  98. 73
      src/google/protobuf/generated_message_tctable_lite.cc
  99. 16
      src/google/protobuf/io/printer.h
  100. 2
      src/google/protobuf/message.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -14,6 +14,31 @@
* Performance improvement for repeated use of FieldMaskUtil#merge by caching
constructed FieldMaskTrees.
2022-07-19 version 21.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
C++
* Add header search paths to Protobuf-C++.podspec (#10024)
* Fixed Visual Studio constinit errors (#10232)
* Fix #9947: make the ABI compatible between debug and non-debug builds (#10271)
UPB
* Allow empty package names (fixes behavior regression in 4.21.0)
* Fix a SEGV bug when comparing a non-materialized sub-message (#10208)
* Fix several bugs in descriptor mapping containers (eg. descriptor.services_by_name)
* for x in mapping now yields keys rather than values, to match Python conventions and the behavior of the old library.
* Lookup operations now correctly reject unhashable types as map keys.
* We implement repr() to use the same format as dict.
* Fix maps to use the ScalarMapContainer class when appropriate
* Fix bug when parsing an unknown value in a proto2 enum extension (protocolbuffers/upb#717)
PHP
* Add "readonly" as a keyword for PHP and add previous classnames to descriptor pool (#10041)
Python
* Make //:protobuf_python and //:well_known_types_py_pb2 public (#10118)
Bazel
* Add back a filegroup for :well_known_protos (#10061)
2022-06-27 version 21.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
C++
* ArenaString improvements (fix alignment issue)

@ -5,7 +5,7 @@
# dependent projects use the :git notation to refer to the library.
Pod::Spec.new do |s|
s.name = 'Protobuf'
s.version = '3.21.2'
s.version = '3.21.3'
s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.'
s.homepage = 'https://github.com/protocolbuffers/protobuf'
s.license = 'BSD-3-Clause'

@ -8,6 +8,8 @@ Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
Recommended.Proto3.ProtobufInput.ValidDataOneofBinary.MESSAGE.Merge.ProtobufOutput
Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator
Required.Proto3.JsonInput.DoubleFieldTooSmall
Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput
Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput
Required.Proto3.JsonInput.FloatFieldTooLarge
Required.Proto3.JsonInput.FloatFieldTooSmall
Required.Proto3.JsonInput.Int32FieldNotInteger

@ -1,2 +1,5 @@
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator
Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput
Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput
Required.Proto3.JsonInput.DurationNegativeSeconds.JsonOutput

@ -56,3 +56,6 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.UnpackedOu
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.UnpackedOutput.ProtobufOutput
Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput
Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput
Required.Proto3.JsonInput.DurationNegativeSeconds.JsonOutput

@ -5,7 +5,7 @@
<title>Google Protocol Buffers tools</title>
<summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
<description>See project site for more info.</description>
<version>3.21.2</version>
<version>3.21.3</version>
<authors>Google Inc.</authors>
<owners>protobuf-packages</owners>
<licenseUrl>https://github.com/protocolbuffers/protobuf/blob/main/LICENSE</licenseUrl>

@ -169,4 +169,20 @@ message OneofWithNoneName {
string x = 1;
string y = 2;
}
}
}
// Issue 8810
message DisambiguateCommonMembers {
int32 disambiguate_common_members = 1;
int32 types = 2;
int32 descriptor = 3;
int32 equals = 4;
int32 to_string = 5;
int32 get_hash_code = 6;
int32 write_to = 7;
int32 clone = 8;
int32 calculate_size = 9;
int32 merge_from = 10;
int32 on_construction = 11;
int32 parser = 12;
}

@ -56,11 +56,17 @@ namespace UnitTest.Issues.TestProtos {
"dWxhcl9maWVsZBgBIAEoCRIbCg5vcHRpb25hbF9maWVsZBgCIAEoCUgAiAEB",
"QhEKD19vcHRpb25hbF9maWVsZCI5ChJPbmVvZldpdGhOb25lRmllbGQSCwoB",
"eBgBIAEoCUgAEg4KBG5vbmUYAiABKAlIAEIGCgR0ZXN0IjUKEU9uZW9mV2l0",
"aE5vbmVOYW1lEgsKAXgYASABKAlIABILCgF5GAIgASgJSABCBgoEbm9uZSpV",
"CgxOZWdhdGl2ZUVudW0SFgoSTkVHQVRJVkVfRU5VTV9aRVJPEAASFgoJRml2",
"ZUJlbG93EPv//////////wESFQoITWludXNPbmUQ////////////ASouCg5E",
"ZXByZWNhdGVkRW51bRITCg9ERVBSRUNBVEVEX1pFUk8QABIHCgNvbmUQAUId",
"qgIaVW5pdFRlc3QuSXNzdWVzLlRlc3RQcm90b3NiBnByb3RvMw=="));
"aE5vbmVOYW1lEgsKAXgYASABKAlIABILCgF5GAIgASgJSABCBgoEbm9uZSKT",
"AgoZRGlzYW1iaWd1YXRlQ29tbW9uTWVtYmVycxIjChtkaXNhbWJpZ3VhdGVf",
"Y29tbW9uX21lbWJlcnMYASABKAUSDQoFdHlwZXMYAiABKAUSEgoKZGVzY3Jp",
"cHRvchgDIAEoBRIOCgZlcXVhbHMYBCABKAUSEQoJdG9fc3RyaW5nGAUgASgF",
"EhUKDWdldF9oYXNoX2NvZGUYBiABKAUSEAoId3JpdGVfdG8YByABKAUSDQoF",
"Y2xvbmUYCCABKAUSFgoOY2FsY3VsYXRlX3NpemUYCSABKAUSEgoKbWVyZ2Vf",
"ZnJvbRgKIAEoBRIXCg9vbl9jb25zdHJ1Y3Rpb24YCyABKAUSDgoGcGFyc2Vy",
"GAwgASgFKlUKDE5lZ2F0aXZlRW51bRIWChJORUdBVElWRV9FTlVNX1pFUk8Q",
"ABIWCglGaXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD/////////",
"//8BKi4KDkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcK",
"A29uZRABQh2qAhpVbml0VGVzdC5Jc3N1ZXMuVGVzdFByb3Rvc2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
@ -77,7 +83,8 @@ namespace UnitTest.Issues.TestProtos {
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NullValueNotInOneof), global::UnitTest.Issues.TestProtos.NullValueNotInOneof.Parser, new[]{ "NullValue" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.MixedRegularAndOptional), global::UnitTest.Issues.TestProtos.MixedRegularAndOptional.Parser, new[]{ "RegularField", "OptionalField" }, new[]{ "OptionalField" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneField), global::UnitTest.Issues.TestProtos.OneofWithNoneField.Parser, new[]{ "X", "None" }, new[]{ "Test" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null)
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DisambiguateCommonMembers), global::UnitTest.Issues.TestProtos.DisambiguateCommonMembers.Parser, new[]{ "DisambiguateCommonMembers_", "Types_", "Descriptor_", "Equals_", "ToString_", "GetHashCode_", "WriteTo_", "Clone_", "CalculateSize_", "MergeFrom_", "OnConstruction_", "Parser_" }, null, null, null, null)
}));
}
#endregion
@ -4347,6 +4354,605 @@ namespace UnitTest.Issues.TestProtos {
}
/// <summary>
/// Issue 8810
/// </summary>
public sealed partial class DisambiguateCommonMembers : pb::IMessage<DisambiguateCommonMembers>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<DisambiguateCommonMembers> _parser = new pb::MessageParser<DisambiguateCommonMembers>(() => new DisambiguateCommonMembers());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<DisambiguateCommonMembers> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[14]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public DisambiguateCommonMembers() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public DisambiguateCommonMembers(DisambiguateCommonMembers other) : this() {
disambiguateCommonMembers_ = other.disambiguateCommonMembers_;
types_ = other.types_;
descriptor_ = other.descriptor_;
equals_ = other.equals_;
toString_ = other.toString_;
getHashCode_ = other.getHashCode_;
writeTo_ = other.writeTo_;
clone_ = other.clone_;
calculateSize_ = other.calculateSize_;
mergeFrom_ = other.mergeFrom_;
onConstruction_ = other.onConstruction_;
parser_ = other.parser_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public DisambiguateCommonMembers Clone() {
return new DisambiguateCommonMembers(this);
}
/// <summary>Field number for the "disambiguate_common_members" field.</summary>
public const int DisambiguateCommonMembers_FieldNumber = 1;
private int disambiguateCommonMembers_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int DisambiguateCommonMembers_ {
get { return disambiguateCommonMembers_; }
set {
disambiguateCommonMembers_ = value;
}
}
/// <summary>Field number for the "types" field.</summary>
public const int Types_FieldNumber = 2;
private int types_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Types_ {
get { return types_; }
set {
types_ = value;
}
}
/// <summary>Field number for the "descriptor" field.</summary>
public const int Descriptor_FieldNumber = 3;
private int descriptor_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Descriptor_ {
get { return descriptor_; }
set {
descriptor_ = value;
}
}
/// <summary>Field number for the "equals" field.</summary>
public const int Equals_FieldNumber = 4;
private int equals_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Equals_ {
get { return equals_; }
set {
equals_ = value;
}
}
/// <summary>Field number for the "to_string" field.</summary>
public const int ToString_FieldNumber = 5;
private int toString_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int ToString_ {
get { return toString_; }
set {
toString_ = value;
}
}
/// <summary>Field number for the "get_hash_code" field.</summary>
public const int GetHashCode_FieldNumber = 6;
private int getHashCode_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int GetHashCode_ {
get { return getHashCode_; }
set {
getHashCode_ = value;
}
}
/// <summary>Field number for the "write_to" field.</summary>
public const int WriteTo_FieldNumber = 7;
private int writeTo_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int WriteTo_ {
get { return writeTo_; }
set {
writeTo_ = value;
}
}
/// <summary>Field number for the "clone" field.</summary>
public const int Clone_FieldNumber = 8;
private int clone_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Clone_ {
get { return clone_; }
set {
clone_ = value;
}
}
/// <summary>Field number for the "calculate_size" field.</summary>
public const int CalculateSize_FieldNumber = 9;
private int calculateSize_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize_ {
get { return calculateSize_; }
set {
calculateSize_ = value;
}
}
/// <summary>Field number for the "merge_from" field.</summary>
public const int MergeFrom_FieldNumber = 10;
private int mergeFrom_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int MergeFrom_ {
get { return mergeFrom_; }
set {
mergeFrom_ = value;
}
}
/// <summary>Field number for the "on_construction" field.</summary>
public const int OnConstruction_FieldNumber = 11;
private int onConstruction_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int OnConstruction_ {
get { return onConstruction_; }
set {
onConstruction_ = value;
}
}
/// <summary>Field number for the "parser" field.</summary>
public const int Parser_FieldNumber = 12;
private int parser_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Parser_ {
get { return parser_; }
set {
parser_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as DisambiguateCommonMembers);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(DisambiguateCommonMembers other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (DisambiguateCommonMembers_ != other.DisambiguateCommonMembers_) return false;
if (Types_ != other.Types_) return false;
if (Descriptor_ != other.Descriptor_) return false;
if (Equals_ != other.Equals_) return false;
if (ToString_ != other.ToString_) return false;
if (GetHashCode_ != other.GetHashCode_) return false;
if (WriteTo_ != other.WriteTo_) return false;
if (Clone_ != other.Clone_) return false;
if (CalculateSize_ != other.CalculateSize_) return false;
if (MergeFrom_ != other.MergeFrom_) return false;
if (OnConstruction_ != other.OnConstruction_) return false;
if (Parser_ != other.Parser_) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (DisambiguateCommonMembers_ != 0) hash ^= DisambiguateCommonMembers_.GetHashCode();
if (Types_ != 0) hash ^= Types_.GetHashCode();
if (Descriptor_ != 0) hash ^= Descriptor_.GetHashCode();
if (Equals_ != 0) hash ^= Equals_.GetHashCode();
if (ToString_ != 0) hash ^= ToString_.GetHashCode();
if (GetHashCode_ != 0) hash ^= GetHashCode_.GetHashCode();
if (WriteTo_ != 0) hash ^= WriteTo_.GetHashCode();
if (Clone_ != 0) hash ^= Clone_.GetHashCode();
if (CalculateSize_ != 0) hash ^= CalculateSize_.GetHashCode();
if (MergeFrom_ != 0) hash ^= MergeFrom_.GetHashCode();
if (OnConstruction_ != 0) hash ^= OnConstruction_.GetHashCode();
if (Parser_ != 0) hash ^= Parser_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (DisambiguateCommonMembers_ != 0) {
output.WriteRawTag(8);
output.WriteInt32(DisambiguateCommonMembers_);
}
if (Types_ != 0) {
output.WriteRawTag(16);
output.WriteInt32(Types_);
}
if (Descriptor_ != 0) {
output.WriteRawTag(24);
output.WriteInt32(Descriptor_);
}
if (Equals_ != 0) {
output.WriteRawTag(32);
output.WriteInt32(Equals_);
}
if (ToString_ != 0) {
output.WriteRawTag(40);
output.WriteInt32(ToString_);
}
if (GetHashCode_ != 0) {
output.WriteRawTag(48);
output.WriteInt32(GetHashCode_);
}
if (WriteTo_ != 0) {
output.WriteRawTag(56);
output.WriteInt32(WriteTo_);
}
if (Clone_ != 0) {
output.WriteRawTag(64);
output.WriteInt32(Clone_);
}
if (CalculateSize_ != 0) {
output.WriteRawTag(72);
output.WriteInt32(CalculateSize_);
}
if (MergeFrom_ != 0) {
output.WriteRawTag(80);
output.WriteInt32(MergeFrom_);
}
if (OnConstruction_ != 0) {
output.WriteRawTag(88);
output.WriteInt32(OnConstruction_);
}
if (Parser_ != 0) {
output.WriteRawTag(96);
output.WriteInt32(Parser_);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (DisambiguateCommonMembers_ != 0) {
output.WriteRawTag(8);
output.WriteInt32(DisambiguateCommonMembers_);
}
if (Types_ != 0) {
output.WriteRawTag(16);
output.WriteInt32(Types_);
}
if (Descriptor_ != 0) {
output.WriteRawTag(24);
output.WriteInt32(Descriptor_);
}
if (Equals_ != 0) {
output.WriteRawTag(32);
output.WriteInt32(Equals_);
}
if (ToString_ != 0) {
output.WriteRawTag(40);
output.WriteInt32(ToString_);
}
if (GetHashCode_ != 0) {
output.WriteRawTag(48);
output.WriteInt32(GetHashCode_);
}
if (WriteTo_ != 0) {
output.WriteRawTag(56);
output.WriteInt32(WriteTo_);
}
if (Clone_ != 0) {
output.WriteRawTag(64);
output.WriteInt32(Clone_);
}
if (CalculateSize_ != 0) {
output.WriteRawTag(72);
output.WriteInt32(CalculateSize_);
}
if (MergeFrom_ != 0) {
output.WriteRawTag(80);
output.WriteInt32(MergeFrom_);
}
if (OnConstruction_ != 0) {
output.WriteRawTag(88);
output.WriteInt32(OnConstruction_);
}
if (Parser_ != 0) {
output.WriteRawTag(96);
output.WriteInt32(Parser_);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (DisambiguateCommonMembers_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(DisambiguateCommonMembers_);
}
if (Types_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Types_);
}
if (Descriptor_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Descriptor_);
}
if (Equals_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Equals_);
}
if (ToString_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ToString_);
}
if (GetHashCode_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(GetHashCode_);
}
if (WriteTo_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(WriteTo_);
}
if (Clone_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Clone_);
}
if (CalculateSize_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(CalculateSize_);
}
if (MergeFrom_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(MergeFrom_);
}
if (OnConstruction_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(OnConstruction_);
}
if (Parser_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Parser_);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(DisambiguateCommonMembers other) {
if (other == null) {
return;
}
if (other.DisambiguateCommonMembers_ != 0) {
DisambiguateCommonMembers_ = other.DisambiguateCommonMembers_;
}
if (other.Types_ != 0) {
Types_ = other.Types_;
}
if (other.Descriptor_ != 0) {
Descriptor_ = other.Descriptor_;
}
if (other.Equals_ != 0) {
Equals_ = other.Equals_;
}
if (other.ToString_ != 0) {
ToString_ = other.ToString_;
}
if (other.GetHashCode_ != 0) {
GetHashCode_ = other.GetHashCode_;
}
if (other.WriteTo_ != 0) {
WriteTo_ = other.WriteTo_;
}
if (other.Clone_ != 0) {
Clone_ = other.Clone_;
}
if (other.CalculateSize_ != 0) {
CalculateSize_ = other.CalculateSize_;
}
if (other.MergeFrom_ != 0) {
MergeFrom_ = other.MergeFrom_;
}
if (other.OnConstruction_ != 0) {
OnConstruction_ = other.OnConstruction_;
}
if (other.Parser_ != 0) {
Parser_ = other.Parser_;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
DisambiguateCommonMembers_ = input.ReadInt32();
break;
}
case 16: {
Types_ = input.ReadInt32();
break;
}
case 24: {
Descriptor_ = input.ReadInt32();
break;
}
case 32: {
Equals_ = input.ReadInt32();
break;
}
case 40: {
ToString_ = input.ReadInt32();
break;
}
case 48: {
GetHashCode_ = input.ReadInt32();
break;
}
case 56: {
WriteTo_ = input.ReadInt32();
break;
}
case 64: {
Clone_ = input.ReadInt32();
break;
}
case 72: {
CalculateSize_ = input.ReadInt32();
break;
}
case 80: {
MergeFrom_ = input.ReadInt32();
break;
}
case 88: {
OnConstruction_ = input.ReadInt32();
break;
}
case 96: {
Parser_ = input.ReadInt32();
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 8: {
DisambiguateCommonMembers_ = input.ReadInt32();
break;
}
case 16: {
Types_ = input.ReadInt32();
break;
}
case 24: {
Descriptor_ = input.ReadInt32();
break;
}
case 32: {
Equals_ = input.ReadInt32();
break;
}
case 40: {
ToString_ = input.ReadInt32();
break;
}
case 48: {
GetHashCode_ = input.ReadInt32();
break;
}
case 56: {
WriteTo_ = input.ReadInt32();
break;
}
case 64: {
Clone_ = input.ReadInt32();
break;
}
case 72: {
CalculateSize_ = input.ReadInt32();
break;
}
case 80: {
MergeFrom_ = input.ReadInt32();
break;
}
case 88: {
OnConstruction_ = input.ReadInt32();
break;
}
case 96: {
Parser_ = input.ReadInt32();
break;
}
}
}
}
#endif
}
#endregion
}

@ -0,0 +1,63 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2022 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
using System;
using System.Linq;
namespace Google.Protobuf.Test;
internal class ParsingPrimitivesTest
{
// Note: test cases use integers rather than bytes as they're easier
// to specify in attributes.
[Test]
[TestCase("\ufffd", 255)]
[TestCase("A\ufffd", 65, 255)]
[TestCase("A\ufffd\ufffdB", 65, 255, 255, 66)]
// Overlong form of "space"
[TestCase("\ufffd\ufffd", 0xc0, 0xa0)]
public void ReadRawString_NonUtf8(string expectedText, params int[] bytes)
{
var context = CreateContext(bytes);
string text = ParsingPrimitives.ReadRawString(ref context.buffer, ref context.state, bytes.Length);
Assert.AreEqual(expectedText, text);
}
private static ParseContext CreateContext(int[] bytes)
{
byte[] actualBytes = bytes.Select(b => (byte) b).ToArray();
ParseContext.Initialize(actualBytes.AsSpan(), out var context);
return context;
}
}

@ -0,0 +1,61 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2022 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Google.Protobuf.Test;
internal class WritingPrimitivesTest
{
[Test]
public void WriteRawString_IllFormedUnicodeString()
{
// See https://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/
char c1 = '\u0058';
char c2 = '\ud800';
char c3 = '\u0059';
string text = new string(new[] { c1, c2, c3 });
Span<byte> buffer = new byte[10];
WriteContext.Initialize(ref buffer, out var context);
WritingPrimitives.WriteString(ref context.buffer, ref context.state, text);
// The high surrogate is written out in a "raw" form, surrounded by the ASCII
// characters.
byte[] expectedBytes = { 0x5, 0x58, 0xef, 0xbf, 0xbd, 0x59 };
Assert.AreEqual(expectedBytes, buffer.Slice(0, context.state.position).ToArray());
}
}

@ -4,7 +4,7 @@
<Description>C# runtime library for Protocol Buffers - Google's data interchange format.</Description>
<Copyright>Copyright 2015, Google Inc.</Copyright>
<AssemblyTitle>Google Protocol Buffers</AssemblyTitle>
<VersionPrefix>3.21.2</VersionPrefix>
<VersionPrefix>3.21.3</VersionPrefix>
<LangVersion>10.0</LangVersion>
<Authors>Google Inc.</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0;net45;net50</TargetFrameworks>

@ -23,7 +23,7 @@ If you are using Maven, use the following:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</dependency>
```
@ -37,7 +37,7 @@ protobuf-java-util package:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</dependency>
```
@ -45,7 +45,7 @@ protobuf-java-util package:
If you are using Gradle, add the following to your `build.gradle` file's dependencies:
```
implementation 'com.google.protobuf:protobuf-java:3.21.2'
implementation 'com.google.protobuf:protobuf-java:3.21.3'
```
Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using.

@ -4,7 +4,7 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-bom</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
<packaging>pom</packaging>
<name>Protocol Buffers [BOM]</name>

@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</parent>
<artifactId>protobuf-java</artifactId>

@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</parent>
<artifactId>protobuf-kotlin-lite</artifactId>

@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</parent>
<artifactId>protobuf-kotlin</artifactId>

@ -66,6 +66,11 @@ class Proto3Test {
assertThat(optionalNestedMessage).isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
optionalNestedEnum = NestedEnum.BAZ
assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
assertThat(optionalNestedEnumValue).isEqualTo(3)
optionalNestedEnumValue = 1
assertThat(optionalNestedEnumValue).isEqualTo(1)
assertThat(optionalNestedEnum).isEqualTo(NestedEnum.FOO)
oneofUint32 = 601
assertThat(oneofUint32).isEqualTo(601)
}

@ -29,7 +29,7 @@ protobuf Java Lite runtime. If you are using Maven, include the following:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-javalite</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</dependency>
```

@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</parent>
<artifactId>protobuf-javalite</artifactId>

@ -4,7 +4,7 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
<packaging>pom</packaging>
<name>Protocol Buffers [Parent]</name>

@ -4,11 +4,11 @@
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
<version>1</version>
<version>5</version>
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
<packaging>pom</packaging>
<name>Protobuf Compiler</name>
<description>

@ -4,7 +4,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</parent>
<artifactId>protobuf-java-util</artifactId>

@ -1,12 +0,0 @@
#!/bin/bash
#
# Build file to set up and run tests
# Change to repo root
cd $(dirname $0)/../../..
# Prepare worker environment to run tests
source kokoro/macos/prepare_build_macos_rc
# TODO(mkruskal) Re-enable this once we can get a working PHP 7.0 installed.
#./tests.sh php7.0_mac

@ -1,12 +0,0 @@
#!/bin/bash
#
# Build file to set up and run tests
# Change to repo root
cd $(dirname $0)/../../..
# Prepare worker environment to run tests
source kokoro/macos/prepare_build_macos_rc
# TODO(mkruskal) Re-enable this once we can get a working PHP 7.0 installed.
#./tests.sh php7.3_mac

@ -0,0 +1,20 @@
#!/bin/bash
#
# Build file to set up and run tests
# Change to repo root
cd $(dirname $0)/../../..
# Prepare worker environment to run tests
source kokoro/macos/prepare_build_macos_rc
# Install Dependencies
brew install coreutils php@7.4
# Configure path
PHP_FOLDER=$(find $HOMEBREW_PREFIX -type d -regex ".*php.*/7.4.[0-9]*")
test ! -z "$PHP_FOLDER"
export PATH="$PHP_FOLDER/bin:$PATH"
# Test
./tests.sh php_mac

@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
build_file: "protobuf/kokoro/macos/php74/build.sh"
timeout_mins: 1440

@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
build_file: "protobuf/kokoro/macos/php7.0_mac/build.sh"
build_file: "protobuf/kokoro/macos/php74/build.sh"
timeout_mins: 1440

@ -0,0 +1,20 @@
#!/bin/bash
#
# Build file to set up and run tests
# Change to repo root
cd $(dirname $0)/../../..
# Prepare worker environment to run tests
source kokoro/macos/prepare_build_macos_rc
# Install Dependencies
brew install coreutils php@8.0
# Configure path
PHP_FOLDER=$(find $HOMEBREW_PREFIX -type d -regex ".*php.*/8.0.[0-9]*")
test ! -z "$PHP_FOLDER"
export PATH="$PHP_FOLDER/bin:$PATH"
# Test
./tests.sh php_mac

@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
build_file: "protobuf/kokoro/macos/php7.0_mac/build.sh"
build_file: "protobuf/kokoro/macos/php80/build.sh"
timeout_mins: 1440

@ -1,5 +1,5 @@
# Config file for running tests in Kokoro
# Location of the build script in repository
build_file: "protobuf/kokoro/macos/php7.3_mac/build.sh"
build_file: "protobuf/kokoro/macos/php80/build.sh"
timeout_mins: 1440

@ -4,20 +4,16 @@
set -eux
export HOMEBREW_PREFIX=$(brew --prefix)
##
# Select Xcode version
# Remember to update the Xcode version when Xcode_11.3.app is not available.
# If xcode is not available, it will probably encounter the failure for
# "autom4te: need GNU m4 1.4 or later: /usr/bin/m4"
# go/kokoro/userdocs/macos/selecting_xcode.md for more information.
export DEVELOPER_DIR=/Applications/Xcode_11.3.app/Contents/Developer
export DEVELOPER_DIR=/Applications/Xcode_13.3.1.app/Contents/Developer
sudo xcode-select -s "${DEVELOPER_DIR}"
##
# Select C/C++ compilers
export CC=gcc
export CXX=g++
# Use Python 2 by default (for googletest)
pyenv global 2.7.18
##
# Install Tox
@ -27,14 +23,18 @@ if [[ "${KOKORO_INSTALL_TOX:-}" == "yes" ]] ; then
fi
##
# Install RVM
# Setup RVM
if [[ "${KOKORO_INSTALL_RVM:-}" == "yes" ]] ; then
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -
git config --global --add safe.directory $HOMEBREW_PREFIX/Library/Taps/homebrew/homebrew-cask
git config --global --add safe.directory $HOMEBREW_PREFIX/Library/Taps/homebrew/homebrew-core
git config --global --add safe.directory $HOMEBREW_PREFIX/Library/Taps/homebrew/homebrew-services
sudo chown -R $(whoami) $HOME/.rvm/
fi
# Old OpenSSL versions cannot handle the SSL certificate used by
# https://get.rvm.io, so as a workaround we download RVM directly from
# GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133
curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master --ruby
# "Install" valgrind if it doesn't exist
##
if [ ! -x "$(command -v valgrind)" ]; then
echo "#! /bin/bash" > valgrind
chmod ug+x valgrind
sudo mv valgrind /usr/local/bin/valgrind
fi

@ -12,8 +12,5 @@ export ARTIFACT_DIR=$(pwd)/artifacts
# ruby environment
bash kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
gem install rubygems-update
update_rubygems
# build artifacts
bash kokoro/release/ruby/macos/ruby/ruby_build.sh

@ -3,7 +3,6 @@
set -ex
# Build protoc
use_bazel.sh 5.1.1
bazel build //:protoc
export PROTOC=$PWD/bazel-bin/protoc

@ -4,13 +4,9 @@ set -ex
set +ex # rvm script is very verbose and exits with errorcode
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -
# Old OpenSSL versions cannot handle the SSL certificate used by
# https://get.rvm.io, so as a workaround we download RVM directly from
# GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133
curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master --ruby
# Fix permissions
sudo chown -R $(whoami) $HOME/.rvm/
sudo chown -R $(whoami) /Library/Ruby/
source $HOME/.rvm/scripts/rvm
set -e # rvm commands are very verbose

@ -74,12 +74,12 @@ GPB_FINAL @interface GPBApi : GPBMessage
/** The methods of this interface, in unspecified order. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMethod*> *methodsArray;
/** The number of items in @c methodsArray without causing the array to be created. */
/** The number of items in @c methodsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger methodsArray_Count;
/** Any metadata attached to the interface. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
/** The number of items in @c optionsArray without causing the array to be created. */
/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/**
@ -115,7 +115,7 @@ GPB_FINAL @interface GPBApi : GPBMessage
/** Included interfaces. See [Mixin][]. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMixin*> *mixinsArray;
/** The number of items in @c mixinsArray without causing the array to be created. */
/** The number of items in @c mixinsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger mixinsArray_Count;
/** The source syntax of the service. */
@ -169,7 +169,7 @@ GPB_FINAL @interface GPBMethod : GPBMessage
/** Any metadata attached to the method. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
/** The number of items in @c optionsArray without causing the array to be created. */
/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The source syntax of this method. */

@ -247,7 +247,7 @@ GPB_FINAL @interface GPBFieldMask : GPBMessage
/** The set of field mask paths. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *pathsArray;
/** The number of items in @c pathsArray without causing the array to be created. */
/** The number of items in @c pathsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger pathsArray_Count;
@end

@ -87,7 +87,7 @@ GPB_FINAL @interface GPBStruct : GPBMessage
/** Unordered map of dynamically typed values. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, GPBValue*> *fields;
/** The number of items in @c fields without causing the array to be created. */
/** The number of items in @c fields without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger fields_Count;
@end
@ -178,7 +178,7 @@ GPB_FINAL @interface GPBListValue : GPBMessage
/** Repeated field of dynamically typed values. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBValue*> *valuesArray;
/** The number of items in @c valuesArray without causing the array to be created. */
/** The number of items in @c valuesArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger valuesArray_Count;
@end

@ -195,17 +195,17 @@ GPB_FINAL @interface GPBType : GPBMessage
/** The list of fields. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBField*> *fieldsArray;
/** The number of items in @c fieldsArray without causing the array to be created. */
/** The number of items in @c fieldsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger fieldsArray_Count;
/** The list of types appearing in `oneof` definitions in this type. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *oneofsArray;
/** The number of items in @c oneofsArray without causing the array to be created. */
/** The number of items in @c oneofsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger oneofsArray_Count;
/** The protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
/** The number of items in @c optionsArray without causing the array to be created. */
/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The source context. */
@ -279,7 +279,7 @@ GPB_FINAL @interface GPBField : GPBMessage
/** The protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
/** The number of items in @c optionsArray without causing the array to be created. */
/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The field JSON name. */
@ -334,12 +334,12 @@ GPB_FINAL @interface GPBEnum : GPBMessage
/** Enum value definitions. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumValue*> *enumvalueArray;
/** The number of items in @c enumvalueArray without causing the array to be created. */
/** The number of items in @c enumvalueArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger enumvalueArray_Count;
/** Protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
/** The number of items in @c optionsArray without causing the array to be created. */
/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
/** The source context. */
@ -385,7 +385,7 @@ GPB_FINAL @interface GPBEnumValue : GPBMessage
/** Protocol buffer options. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
/** The number of items in @c optionsArray without causing the array to be created. */
/** The number of items in @c optionsArray without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger optionsArray_Count;
@end

@ -2248,7 +2248,7 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
NSCAssert([[self descriptor] oneofWithName:oneof.name] == oneof,
@"OneofDescriptor %@ doesn't appear to be for %@ messages.",
oneof.name, [self class]);
GPBFieldDescriptor *firstField = oneof->fields_[0];
GPBFieldDescriptor *firstField __unused = oneof->fields_[0];
NSCAssert(firstField->description_->hasIndex == oneofHasIndex,
@"Internal error, oneofHasIndex (%d) doesn't match (%d).",
firstField->description_->hasIndex, oneofHasIndex);

@ -73,6 +73,7 @@ for PROTO_FILE in "${RUNTIME_PROTO_FILES[@]}"; do
if ! diff "${ObjCDir}/GPB${OBJC_NAME}${EXT}" "${TMP_DIR}/${DIR}/${OBJC_NAME}${EXT}" > /dev/null 2>&1 ; then
if [[ "${CHECK_ONLY}" == 1 ]] ; then
echo "ERROR: The WKTs need to be regenerated! Run $0"
diff -u "${ObjCDir}/GPB${OBJC_NAME}${EXT}" "${TMP_DIR}/${DIR}/${OBJC_NAME}${EXT}"
exit 1
fi

@ -12,7 +12,9 @@ pkg_files(
"src/Google/Protobuf/**/*.php",
"tests/*.php",
"tests/*.sh",
"tests/generated_previous/**/*.php",
"tests/proto/**/*.proto",
"tests/proto_previous/*.proto",
]) + [
"BUILD.bazel",
"README.md",

@ -20,7 +20,10 @@
"autoload-dev": {
"psr-4": {
"": "tmp"
}
},
"classmap": [
"tests/generated_previous"
]
},
"scripts": {
"test_c": "./generate_test_protos.sh && ./tests/compile_extension.sh && php -dextension=ext/google/protobuf/modules/protobuf.so vendor/bin/phpunit --bootstrap tests/force_c_ext.php tests",

@ -162,7 +162,7 @@ static void EnumDescriptor_FromEnumDef(zval *val, const upb_EnumDef *m) {
ZVAL_NULL(val);
} else {
char *classname =
GetPhpClassname(upb_EnumDef_File(m), upb_EnumDef_FullName(m));
GetPhpClassname(upb_EnumDef_File(m), upb_EnumDef_FullName(m), false);
zend_string *str = zend_string_init(classname, strlen(classname), 0);
zend_class_entry *ce = zend_lookup_class(str); // May autoload the class.
@ -499,19 +499,23 @@ static void Descriptor_destructor(zend_object* obj) {
}
static zend_class_entry *Descriptor_GetGeneratedClass(const upb_MessageDef *m) {
char *classname =
GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m));
zend_string *str = zend_string_init(classname, strlen(classname), 0);
zend_class_entry *ce = zend_lookup_class(str); // May autoload the class.
for (int i = 0; i < 2; ++i) {
char *classname =
GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), (bool)i);
zend_string *str = zend_string_init(classname, strlen(classname), 0);
zend_class_entry *ce = zend_lookup_class(str); // May autoload the class.
zend_string_release (str);
zend_string_release (str);
free(classname);
if (!ce) {
zend_error(E_ERROR, "Couldn't load generated class %s", classname);
if (ce) {
return ce;
}
}
free(classname);
return ce;
char *classname =
GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), false);
zend_error(E_ERROR, "Couldn't load generated class %s", classname);
}
void Descriptor_FromMessageDef(zval *val, const upb_MessageDef *m) {

@ -82,12 +82,15 @@ const char *const kReservedNames[] = {
"global", "goto", "insteadof", "interface", "isset",
"list", "match", "namespace", "new", "object",
"or", "parent", "print", "private", "protected",
"public", "require", "require_once", "return", "self",
"static", "switch", "throw", "trait", "try",
"unset", "use", "var", "while", "xor",
"yield", "int", "float", "bool", "string",
"true", "false", "null", "void", "iterable",
NULL};
"public", "readonly", "require", "require_once", "return",
"self", "static", "switch", "throw", "trait",
"try", "unset", "use", "var", "while",
"xor", "yield", "int", "float", "bool",
"string", "true", "false", "null", "void",
"iterable", NULL};
const char *const kPreviouslyUnreservedNames[] = {
"readonly", NULL};
bool is_reserved_name(const char* name) {
int i;
@ -99,6 +102,15 @@ bool is_reserved_name(const char* name) {
return false;
}
bool is_previously_unreserved_name(const char* name) {
for (int i = 0; kPreviouslyUnreservedNames[i]; i++) {
if (strcmp(kPreviouslyUnreservedNames[i], name) == 0) {
return true;
}
}
return false;
}
static char nolocale_tolower(char ch) {
if (ch >= 'A' && ch <= 'Z') {
return ch - ('A' - 'a');
@ -115,17 +127,22 @@ static char nolocale_toupper(char ch) {
}
}
static bool is_reserved(const char *segment, int length) {
static char *strdup_nolocale_lower(char *str, int length) {
char* lower = malloc(length + 1);
lower[length] = '\0';
for(int i = 0; i < length; ++i) {
lower[i] = nolocale_tolower(str[i]);
}
return lower;
}
static bool is_reserved(const char *segment, int length, bool previous) {
bool result;
char* lower = calloc(1, length + 1);
memcpy(lower, segment, length);
int i = 0;
while(lower[i]) {
lower[i] = nolocale_tolower(lower[i]);
i++;
}
lower[length] = 0;
char* lower = strdup_nolocale_lower(segment, length);
result = is_reserved_name(lower);
if (result && previous && is_previously_unreserved_name(lower)) {
result = false;
}
free(lower);
return result;
}
@ -133,11 +150,12 @@ static bool is_reserved(const char *segment, int length) {
static void fill_prefix(const char *segment, int length,
const char *prefix_given,
const char *package_name,
stringsink *classname) {
stringsink *classname,
bool previous) {
if (prefix_given != NULL && strcmp(prefix_given, "") != 0) {
stringsink_string(classname, prefix_given, strlen(prefix_given));
} else {
if (is_reserved(segment, length)) {
if (is_reserved(segment, length, previous)) {
if (package_name != NULL &&
strcmp("google.protobuf", package_name) == 0) {
stringsink_string(classname, "GPB", 3);
@ -160,7 +178,7 @@ static void fill_segment(const char *segment, int length,
}
static void fill_namespace(const char *package, const char *php_namespace,
stringsink *classname) {
stringsink *classname, bool previous) {
if (php_namespace != NULL) {
if (strlen(php_namespace) != 0) {
stringsink_string(classname, php_namespace, strlen(php_namespace));
@ -174,7 +192,7 @@ static void fill_namespace(const char *package, const char *php_namespace,
while (j < package_len && package[j] != '.') {
j++;
}
fill_prefix(package + i, j - i, "", package, classname);
fill_prefix(package + i, j - i, "", package, classname, previous);
fill_segment(package + i, j - i, classname, true);
stringsink_string(classname, "\\", 1);
i = j + 1;
@ -185,7 +203,8 @@ static void fill_namespace(const char *package, const char *php_namespace,
static void fill_classname(const char *fullname,
const char *package,
const char *prefix,
stringsink *classname) {
stringsink *classname,
bool previous) {
int classname_start = 0;
if (package != NULL) {
size_t package_len = strlen(package);
@ -199,7 +218,7 @@ static void fill_classname(const char *fullname,
while (j < fullname_len && fullname[j] != '.') {
j++;
}
fill_prefix(fullname + i, j - i, prefix, package, classname);
fill_prefix(fullname + i, j - i, prefix, package, classname, previous);
fill_segment(fullname + i, j - i, classname, false);
if (j != fullname_len) {
stringsink_string(classname, "\\", 1);
@ -215,7 +234,7 @@ char *str_view_dup(upb_StringView str) {
return ret;
}
char *GetPhpClassname(const upb_FileDef *file, const char *fullname) {
char *GetPhpClassname(const upb_FileDef *file, const char *fullname, bool previous) {
// Prepend '.' to package name to make it absolute. In the 5 additional
// bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if
// given message is google.protobuf.Empty.
@ -234,8 +253,8 @@ char *GetPhpClassname(const upb_FileDef *file, const char *fullname) {
stringsink namesink;
stringsink_init(&namesink);
fill_namespace(package, php_namespace, &namesink);
fill_classname(fullname, package, prefix, &namesink);
fill_namespace(package, php_namespace, &namesink, previous);
fill_classname(fullname, package, prefix, &namesink, previous);
stringsink_string(&namesink, "\0", 1);
ret = strdup(namesink.ptr);
stringsink_uninit(&namesink);
@ -243,3 +262,26 @@ char *GetPhpClassname(const upb_FileDef *file, const char *fullname) {
free(prefix);
return ret;
}
bool IsPreviouslyUnreservedClassName(const char* fullname) {
const char *classname = strrchr(fullname, '\\');
if (classname) {
classname += 1;
} else {
classname = fullname;
}
if (strncmp(classname, "PB", 2) != 0) {
return false;
}
classname += 2;
int length = strlen(classname);
char* lower = strdup_nolocale_lower(classname, length);
for (int j = 0; kPreviouslyUnreservedNames[j]; j++) {
if (strcmp(kPreviouslyUnreservedNames[j], lower) == 0) {
free(lower);
return true;
}
}
free(lower);
return false;
}

@ -35,6 +35,7 @@
// Translates a protobuf symbol name (eg. foo.bar.Baz) into a PHP class name
// (eg. \Foo\Bar\Baz).
char *GetPhpClassname(const upb_FileDef *file, const char *fullname);
char *GetPhpClassname(const upb_FileDef *file, const char *fullname, bool previous);
bool IsPreviouslyUnreservedClassName(const char* fullname);
#endif // PHP_PROTOBUF_NAMES_H_

@ -5,16 +5,16 @@
<summary>Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.</summary>
<description>https://developers.google.com/protocol-buffers/</description>
<lead>
<name>Bo Yang</name>
<user>stanleycheung</user>
<email>protobuf-opensource@google.com</email>
<name>Protobuf Team</name>
<user>protobufpackages</user>
<email>protobuf-packages@google.com</email>
<active>yes</active>
</lead>
<date>2022-06-23</date>
<time>12:12:44</time>
<date>2022-07-21</date>
<time>10:19:47</time>
<version>
<release>3.21.2</release>
<api>3.21.2</api>
<release>3.21.3</release>
<api>3.21.3</api>
</version>
<stability>
<release>stable</release>
@ -1358,5 +1358,20 @@ G A release.
<notes>
</notes>
</release>
<release>
<version>
<release>3.21.3</release>
<api>3.21.3</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2022-07-21</date>
<time>10:19:47</time>
<license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
<notes>
</notes>
</release>
</changelog>
</package>

@ -242,13 +242,19 @@ bool ObjCache_Get(const void *upb_obj, zval *val) {
// -----------------------------------------------------------------------------
void NameMap_AddMessage(const upb_MessageDef *m) {
char *k = GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m));
zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m);
free(k);
for (int i = 0; i < 2; ++i) {
char *k = GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), (bool)i);
zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m);
if (!IsPreviouslyUnreservedClassName(k)) {
free(k);
return;
}
free(k);
}
}
void NameMap_AddEnum(const upb_EnumDef *e) {
char *k = GetPhpClassname(upb_EnumDef_File(e), upb_EnumDef_FullName(e));
char *k = GetPhpClassname(upb_EnumDef_File(e), upb_EnumDef_FullName(e), false);
zend_hash_str_add_ptr(&PROTOBUF_G(name_enum_cache), k, strlen(k), (void*)e);
free(k);
}

@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define PHP_PROTOBUF_VERSION "3.21.2"
#define PHP_PROTOBUF_VERSION "3.21.3"
// ptr -> PHP object cache. This is a weak map that caches lazily-created
// wrapper objects around upb types:

@ -45,6 +45,7 @@ class Descriptor
private $enum_type = [];
private $klass;
private $legacy_klass;
private $previous_klass;
private $options;
private $oneof_decl = [];
@ -162,6 +163,16 @@ class Descriptor
return $this->legacy_klass;
}
public function setPreviouslyUnreservedClass($klass)
{
$this->previous_klass = $klass;
}
public function getPreviouslyUnreservedClass()
{
return $this->previous_klass;
}
public function setOptions($options)
{
$this->options = $options;
@ -179,6 +190,7 @@ class Descriptor
$message_name_without_package = "";
$classname = "";
$legacy_classname = "";
$previous_classname = "";
$fullname = "";
GPBUtil::getFullClassName(
$proto,
@ -187,10 +199,12 @@ class Descriptor
$message_name_without_package,
$classname,
$legacy_classname,
$fullname);
$fullname,
$previous_classname);
$desc->setFullName($fullname);
$desc->setClass($classname);
$desc->setLegacyClass($legacy_classname);
$desc->setPreviouslyUnreservedClass($previous_classname);
$desc->setOptions($proto->getOptions());
foreach ($proto->getField() as $field_proto) {

@ -96,6 +96,7 @@ class DescriptorPool
$descriptor->getClass();
$this->class_to_desc[$descriptor->getClass()] = $descriptor;
$this->class_to_desc[$descriptor->getLegacyClass()] = $descriptor;
$this->class_to_desc[$descriptor->getPreviouslyUnreservedClass()] = $descriptor;
foreach ($descriptor->getNestedType() as $nested_type) {
$this->addDescriptor($nested_type);
}

@ -101,7 +101,8 @@ class EnumDescriptor
$enum_name_without_package,
$classname,
$legacy_classname,
$fullname);
$fullname,
$unused_previous_classname);
$desc->setFullName($fullname);
$desc->setClass($classname);
$desc->setLegacyClass($legacy_classname);

@ -285,11 +285,12 @@ class GPBUtil
"include"=>0, "include_once"=>0, "instanceof"=>0, "insteadof"=>0,
"interface"=>0, "isset"=>0, "list"=>0, "match"=>0, "namespace"=>0,
"new"=>0, "or"=>0, "parent"=>0, "print"=>0, "private"=>0,
"protected"=>0,"public"=>0, "require"=>0, "require_once"=>0,
"return"=>0, "self"=>0, "static"=>0, "switch"=>0, "throw"=>0,
"trait"=>0, "try"=>0,"unset"=>0, "use"=>0, "var"=>0, "while"=>0,
"xor"=>0, "yield"=>0, "int"=>0, "float"=>0, "bool"=>0, "string"=>0,
"true"=>0, "false"=>0, "null"=>0, "void"=>0, "iterable"=>0
"protected"=>0,"public"=>0, "readonly" => 0,"require"=>0,
"require_once"=>0,"return"=>0, "self"=>0, "static"=>0, "switch"=>0,
"throw"=>0,"trait"=>0, "try"=>0,"unset"=>0, "use"=>0, "var"=>0,
"while"=>0,"xor"=>0, "yield"=>0, "int"=>0, "float"=>0, "bool"=>0,
"string"=>0,"true"=>0, "false"=>0, "null"=>0, "void"=>0,
"iterable"=>0
);
if (array_key_exists(strtolower($classname), $reserved_words)) {
@ -303,6 +304,27 @@ class GPBUtil
return "";
}
private static function getPreviouslyUnreservedClassNamePrefix(
$classname,
$file_proto)
{
$previously_unreserved_words = array(
"readonly"=>0
);
if (array_key_exists(strtolower($classname), $previously_unreserved_words)) {
$option = $file_proto->getOptions();
$prefix = is_null($option) ? "" : $option->getPhpClassPrefix();
if ($prefix !== "") {
return $prefix;
}
return "";
}
return self::getClassNamePrefix($classname, $file_proto);
}
public static function getLegacyClassNameWithoutPackage(
$name,
$file_proto)
@ -322,6 +344,17 @@ class GPBUtil
return implode('\\', $parts);
}
private static function getPreviouslyUnreservedClassNameWithoutPackage(
$name,
$file_proto)
{
$parts = explode('.', $name);
foreach ($parts as $i => $part) {
$parts[$i] = static::getPreviouslyUnreservedClassNamePrefix($parts[$i], $file_proto) . $parts[$i];
}
return implode('\\', $parts);
}
public static function getFullClassName(
$proto,
$containing,
@ -329,7 +362,8 @@ class GPBUtil
&$message_name_without_package,
&$classname,
&$legacy_classname,
&$fullname)
&$fullname,
&$previous_classname)
{
// Full name needs to start with '.'.
$message_name_without_package = $proto->getName();
@ -350,6 +384,9 @@ class GPBUtil
$legacy_class_name_without_package =
static::getLegacyClassNameWithoutPackage(
$message_name_without_package, $file_proto);
$previous_class_name_without_package =
static::getPreviouslyUnreservedClassNameWithoutPackage(
$message_name_without_package, $file_proto);
$option = $file_proto->getOptions();
if (!is_null($option) && $option->hasPhpNamespace()) {
@ -358,10 +395,13 @@ class GPBUtil
$classname = $namespace . "\\" . $class_name_without_package;
$legacy_classname =
$namespace . "\\" . $legacy_class_name_without_package;
$previous_classname =
$namespace . "\\" . $previous_class_name_without_package;
return;
} else {
$classname = $class_name_without_package;
$legacy_classname = $legacy_class_name_without_package;
$previous_classname = $previous_class_name_without_package;
return;
}
}
@ -369,6 +409,7 @@ class GPBUtil
if ($package === "") {
$classname = $class_name_without_package;
$legacy_classname = $legacy_class_name_without_package;
$previous_classname = $previous_class_name_without_package;
} else {
$parts = array_map('ucwords', explode('.', $package));
foreach ($parts as $i => $part) {
@ -381,6 +422,11 @@ class GPBUtil
$legacy_classname =
implode('\\', array_map('ucwords', explode('.', $package))).
"\\".$legacy_class_name_without_package;
$previous_classname =
implode('\\', array_map('ucwords', explode('.', $package))).
"\\".self::getPreviouslyUnreservedClassNamePrefix(
$previous_class_name_without_package, $file_proto).
$previous_class_name_without_package;
}
}

@ -334,6 +334,18 @@ class GeneratedClassTest extends TestBase
$this->legacyEnum(new TestLegacyMessage\NestedEnum);
}
public function testLegacyReadOnlyMessage()
{
$this->assertTrue(class_exists('\Upper\READONLY'));
$this->assertTrue(class_exists('\Lower\readonly'));
}
public function testLegacyReadOnlyEnum()
{
$this->assertTrue(class_exists('\Upper_enum\READONLY'));
$this->assertTrue(class_exists('\Lower_enum\readonly'));
}
private function legacyEnum(TestLegacyMessage_NestedEnum $enum)
{
// If we made it here without a PHP Fatal error, the typehint worked
@ -943,6 +955,7 @@ class GeneratedClassTest extends TestBase
$m = new \Lower\PBprivate();
$m = new \Lower\PBprotected();
$m = new \Lower\PBpublic();
$m = new \Lower\PBreadonly();
$m = new \Lower\PBrequire();
$m = new \Lower\PBrequire_once();
$m = new \Lower\PBreturn();
@ -1023,6 +1036,7 @@ class GeneratedClassTest extends TestBase
$m = new \Upper\PBPRIVATE();
$m = new \Upper\PBPROTECTED();
$m = new \Upper\PBPUBLIC();
$m = new \Upper\PBREADONLY();
$m = new \Upper\PBREQUIRE();
$m = new \Upper\PBREQUIRE_ONCE();
$m = new \Upper\PBRETURN();
@ -1104,6 +1118,7 @@ class GeneratedClassTest extends TestBase
$m = new \Lower_enum\PBprotected();
$m = new \Lower_enum\PBpublic();
$m = new \Lower_enum\PBrequire();
$m = new \Lower_enum\PBreadonly();
$m = new \Lower_enum\PBrequire_once();
$m = new \Lower_enum\PBreturn();
$m = new \Lower_enum\PBself();
@ -1183,6 +1198,7 @@ class GeneratedClassTest extends TestBase
$m = new \Upper_enum\PBPRIVATE();
$m = new \Upper_enum\PBPROTECTED();
$m = new \Upper_enum\PBPUBLIC();
$m = new \Upper_enum\PBREADONLY();
$m = new \Upper_enum\PBREQUIRE();
$m = new \Upper_enum\PBREQUIRE_ONCE();
$m = new \Upper_enum\PBRETURN();
@ -1287,6 +1303,7 @@ class GeneratedClassTest extends TestBase
$m = \Lower_enum_value\NotAllowed::iterable;
$m = \Lower_enum_value\NotAllowed::parent;
$m = \Lower_enum_value\NotAllowed::self;
$m = \Lower_enum_value\NotAllowed::readonly;
$m = \Upper_enum_value\NotAllowed::PBABSTRACT;
$m = \Upper_enum_value\NotAllowed::PBAND;
@ -1367,6 +1384,7 @@ class GeneratedClassTest extends TestBase
$m = \Upper_enum_value\NotAllowed::ITERABLE;
$m = \Upper_enum_value\NotAllowed::PARENT;
$m = \Upper_enum_value\NotAllowed::SELF;
$m = \Upper_enum_value\NotAllowed::READONLY;
$this->assertTrue(true);
}

@ -0,0 +1,18 @@
<?php
require_once('test_base.php');
require_once('test_util.php');
class PreviouslyGeneratedClassTest extends TestBase
{
#########################################################
# Test compatibility for previously unreserved words.
#########################################################
public function testPrefixForReservedWords()
{
$m = new \Previous\readonly();
$this->assertTrue(true);
}
}

@ -0,0 +1,28 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: proto_previous/test_previously_unreserved_message.proto
namespace GPBMetadata\ProtoPrevious;
class TestPreviouslyUnreservedMessage
{
public static $is_initialized = false;
public static function initOnce() {
$pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
if (static::$is_initialized == true) {
return;
}
$pool->internalAddGeneratedFile(
'
W
7proto_previous/test_previously_unreserved_message.protoprevious"
readonlybproto3'
, true);
static::$is_initialized = true;
}
}

@ -0,0 +1,31 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: proto_previous/test_previously_unreserved_message.proto
namespace Previous;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>previous.readonly</code>
*/
class readonly extends \Google\Protobuf\Internal\Message
{
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\ProtoPrevious\TestPreviouslyUnreservedMessage::initOnce();
parent::__construct($data);
}
}

@ -57,6 +57,7 @@ enum print { ZERO51 = 0; }
enum private { ZERO52 = 0; }
enum protected { ZERO53 = 0; }
enum public { ZERO54 = 0; }
enum readonly { ZERO80 = 0; }
enum require { ZERO55 = 0; }
enum require_once { ZERO56 = 0; }
enum return { ZERO57 = 0; }

@ -57,6 +57,7 @@ enum PRINT { ZERO51 = 0; }
enum PRIVATE { ZERO52 = 0; }
enum PROTECTED { ZERO53 = 0; }
enum PUBLIC { ZERO54 = 0; }
enum READONLY { ZERO80 = 0; }
enum REQUIRE { ZERO55 = 0; }
enum REQUIRE_ONCE { ZERO56 = 0; }
enum RETURN { ZERO57 = 0; }

@ -58,6 +58,7 @@ enum NotAllowed {
private = 51;
protected = 52;
public = 53;
readonly = 79;
require = 54;
require_once = 55;
return = 56;

@ -58,6 +58,7 @@ enum NotAllowed {
PRIVATE = 51;
PROTECTED = 52;
PUBLIC = 53;
READONLY = 79;
REQUIRE = 54;
REQUIRE_ONCE = 55;
RETURN = 56;

@ -57,6 +57,7 @@ message print {}
message private {}
message protected {}
message public {}
message readonly {}
message require {}
message require_once {}
message return {}

@ -57,6 +57,7 @@ message PRINT {}
message PRIVATE {}
message PROTECTED {}
message PUBLIC {}
message READONLY {}
message REQUIRE {}
message REQUIRE_ONCE {}
message RETURN {}

@ -0,0 +1,5 @@
syntax = "proto3";
package previous;
message readonly {}

@ -114,6 +114,6 @@ def protobuf_deps():
_github_archive(
name = "upb",
repo = "https://github.com/protocolbuffers/upb",
commit = "04cb5af6b67c80db61f0aee76dcb6d233e51795c",
sha256 = "62d3519a7b65d6695e011f2733bfc5d7c6ab77f2bd83cdd2dca449da2e739c7f",
commit = "17b6451684ffcf6e77d10a5def9bf19af57eccd3",
sha256 = "655c30a01c8ab56680c154baded548c5df8f726305d3338d0885cbb1f700ec10",
)

@ -1,3 +1,3 @@
PROTOC_VERSION = '21.2'
PROTOBUF_JAVA_VERSION = '3.21.2'
PROTOBUF_PYTHON_VERSION = '4.21.2'
PROTOC_VERSION = '21.3'
PROTOBUF_JAVA_VERSION = '3.21.3'
PROTOBUF_PYTHON_VERSION = '4.21.3'

@ -4,11 +4,11 @@
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
<version>1</version>
<version>5</version>
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
<packaging>pom</packaging>
<name>Protobuf Compiler</name>
<description>

@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "google-protobuf"
s.version = "3.21.2"
s.version = "3.21.3"
git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag
s.licenses = ["BSD-3-Clause"]
s.summary = "Protocol Buffers"

@ -9,7 +9,7 @@
<groupId>com.google.protobuf.jruby</groupId>
<artifactId>protobuf-jruby</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
<name>Protocol Buffer JRuby native extension</name>
<description>
Protocol Buffers are a way of encoding structured data in an efficient yet
@ -76,7 +76,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.21.2</version>
<version>3.21.3</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>

@ -774,6 +774,7 @@ protobuf_test_SOURCES = \
google/protobuf/compiler/csharp/csharp_generator_unittest.cc \
google/protobuf/compiler/importer_unittest.cc \
google/protobuf/compiler/java/doc_comment_unittest.cc \
google/protobuf/compiler/java/message_serialization_unittest.cc \
google/protobuf/compiler/java/plugin_unittest.cc \
google/protobuf/compiler/mock_code_generator.cc \
google/protobuf/compiler/mock_code_generator.h \

@ -771,6 +771,7 @@ set(compiler_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/plugin_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser_unittest.cc

@ -1419,7 +1419,7 @@ TEST(ArenaTest, BlockSizeDoubling) {
ASSERT_GT(arena.SpaceAllocated(), first_block_size);
auto second_block_size = (arena.SpaceAllocated() - first_block_size);
EXPECT_EQ(second_block_size, 2*first_block_size);
EXPECT_GE(second_block_size, 2*first_block_size);
}
TEST(ArenaTest, Alignment) {

@ -50,7 +50,8 @@ namespace internal {
namespace {
// Enforce that allocated data aligns to at least 8 bytes, and that
// TaggedStringPtr::Flags uses the lower 2 bits as tags.
// Enforce that allocated data aligns to at least 4 bytes, and that
// the alignment of the global const string value does as well.
// The alignment guaranteed by `new std::string` depends on both:
// - new align = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / max_align_t
@ -64,8 +65,8 @@ constexpr size_t kNewAlign = alignof(std::max_align_t);
#endif
constexpr size_t kStringAlign = alignof(std::string);
static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 8, "");
static_assert(alignof(ExplicitlyConstructedArenaString) >= 8, "");
static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 4, "");
static_assert(alignof(ExplicitlyConstructedArenaString) >= 4, "");
} // namespace

@ -72,7 +72,7 @@ void ThreadSafeArenaStats::PrepareForSampling(int64_t stride) {
bytes_used.store(0, std::memory_order_relaxed);
bytes_allocated.store(0, std::memory_order_relaxed);
bytes_wasted.store(0, std::memory_order_relaxed);
max_bytes_allocated.store(0, std::memory_order_relaxed);
max_block_size.store(0, std::memory_order_relaxed);
thread_ids.store(0, std::memory_order_relaxed);
weight = stride;
// The inliner makes hardcoded skip_count difficult (especially when combined
@ -87,6 +87,9 @@ void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used,
info->bytes_used.fetch_add(used, std::memory_order_relaxed);
info->bytes_allocated.fetch_add(allocated, std::memory_order_relaxed);
info->bytes_wasted.fetch_add(wasted, std::memory_order_relaxed);
if (info->max_block_size.load(std::memory_order_relaxed) < allocated) {
info->max_block_size.store(allocated, std::memory_order_relaxed);
}
const uint64_t tid = 1ULL << (GetCachedTID() % 63);
info->thread_ids.fetch_or(tid, std::memory_order_relaxed);
}

@ -69,8 +69,8 @@ struct ThreadSafeArenaStats
std::atomic<size_t> bytes_used;
std::atomic<size_t> bytes_allocated;
std::atomic<size_t> bytes_wasted;
// Records the largest size an arena ever had.
std::atomic<size_t> max_bytes_allocated;
// Records the largest block allocated for the arena.
std::atomic<size_t> max_block_size;
// Bit `i` is set to 1 indicates that a thread with `tid % 63 = i` accessed
// the underlying arena. We use `% 63` as a rudimentary hash to ensure some
// bit mixing for thread-ids; `% 64` would only grab the low bits and might

@ -89,21 +89,21 @@ TEST(ThreadSafeArenaStatsTest, PrepareForSampling) {
EXPECT_EQ(info.bytes_used.load(), 0);
EXPECT_EQ(info.bytes_allocated.load(), 0);
EXPECT_EQ(info.bytes_wasted.load(), 0);
EXPECT_EQ(info.max_bytes_allocated.load(), 0);
EXPECT_EQ(info.max_block_size.load(), 0);
EXPECT_EQ(info.weight, kTestStride);
info.num_allocations.store(1, std::memory_order_relaxed);
info.bytes_used.store(1, std::memory_order_relaxed);
info.bytes_allocated.store(1, std::memory_order_relaxed);
info.bytes_wasted.store(1, std::memory_order_relaxed);
info.max_bytes_allocated.store(1, std::memory_order_relaxed);
info.max_block_size.store(1, std::memory_order_relaxed);
info.PrepareForSampling(2 * kTestStride);
EXPECT_EQ(info.num_allocations.load(), 0);
EXPECT_EQ(info.bytes_used.load(), 0);
EXPECT_EQ(info.bytes_allocated.load(), 0);
EXPECT_EQ(info.bytes_wasted.load(), 0);
EXPECT_EQ(info.max_bytes_allocated.load(), 0);
EXPECT_EQ(info.max_block_size.load(), 0);
EXPECT_EQ(info.weight, 2 * kTestStride);
}
@ -117,14 +117,29 @@ TEST(ThreadSafeArenaStatsTest, RecordAllocateSlow) {
EXPECT_EQ(info.bytes_used.load(), 100);
EXPECT_EQ(info.bytes_allocated.load(), 128);
EXPECT_EQ(info.bytes_wasted.load(), 0);
EXPECT_EQ(info.max_bytes_allocated.load(), 0);
EXPECT_EQ(info.max_block_size.load(), 128);
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
/*wasted=*/28);
EXPECT_EQ(info.num_allocations.load(), 2);
EXPECT_EQ(info.bytes_used.load(), 200);
EXPECT_EQ(info.bytes_allocated.load(), 384);
EXPECT_EQ(info.bytes_wasted.load(), 28);
EXPECT_EQ(info.max_bytes_allocated.load(), 0);
EXPECT_EQ(info.max_block_size.load(), 256);
}
TEST(ThreadSafeArenaStatsTest, RecordAllocateSlowMaxBlockSizeTest) {
ThreadSafeArenaStats info;
constexpr int64_t kTestStride = 458;
MutexLock l(&info.init_mu);
info.PrepareForSampling(kTestStride);
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
EXPECT_EQ(info.max_block_size.load(), 128);
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
/*wasted=*/28);
EXPECT_EQ(info.max_block_size.load(), 256);
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128,
/*wasted=*/28);
EXPECT_EQ(info.max_block_size.load(), 256);
}
TEST(ThreadSafeArenazSamplerTest, SamplingCorrectness) {

@ -398,7 +398,6 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
// Get name of all output files.
void GetOutputFilenames(std::vector<std::string>* output_filenames);
// implements GeneratorContext --------------------------------------
io::ZeroCopyOutputStream* Open(const std::string& filename) override;
io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename) override;
@ -963,6 +962,7 @@ PopulateSingleSimpleDescriptorDatabase(const std::string& descriptor_set_name);
int CommandLineInterface::Run(int argc, const char* const argv[]) {
Clear();
switch (ParseArguments(argc, argv)) {
case PARSE_ARGUMENT_DONE_AND_EXIT:
return 0;
@ -1076,7 +1076,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
// Write all output to disk.
for (const auto& pair : output_directories) {
const std::string& location = pair.first;
GeneratorContextImpl* directory = pair.second.get();
@ -1151,7 +1150,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// Do not add a default case.
}
}
return 0;
}

@ -330,7 +330,6 @@ void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
}
}
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {

@ -208,7 +208,6 @@ class FieldGenerator {
virtual bool IsInlined() const { return false; }
virtual ArenaDtorNeeds NeedsArenaDestructor() const {
return ArenaDtorNeeds::kNone;
}

@ -495,12 +495,10 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
generator->GenerateInitDefaultSplitInstance(printer);
format(
"} {}\n"
" ~$1$() {}\n"
" union {\n"
" $2$ _instance;\n"
" $1$ _instance;\n"
" };\n"
"};\n",
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
StrCat(generator->classname_, "::Impl_::Split"));
// NO_DESTROY is not necessary for correctness. The empty destructor is
// enough. However, the empty destructor fails to be elided in some
@ -508,7 +506,7 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
// there just to improve performance and binary size in these builds.
format(
"PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const $1$ $2$;\n",
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
DefaultInstanceName(generator->descriptor_, options_, /*split=*/true));
}
@ -999,7 +997,7 @@ class FileGenerator::ForwardDeclarations {
const Descriptor* class_desc = p.second;
format(
"struct $1$;\n"
"$dllexport_decl $extern $1$ $2$;\n",
"$dllexport_decl $extern const $1$ $2$;\n",
DefaultInstanceType(class_desc, options, /*split=*/true),
DefaultInstanceName(class_desc, options, /*split=*/true));
}

@ -176,7 +176,6 @@ static const char* const kKeywordList[] = {
#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES
};
static std::unordered_set<std::string>* MakeKeywordsMap() {
auto* result = new std::unordered_set<std::string>();
for (const auto keyword : kKeywordList) {
@ -525,7 +524,6 @@ std::string FieldName(const FieldDescriptor* field) {
return result;
}
std::string FieldMemberName(const FieldDescriptor* field, bool split) {
StringPiece prefix =
IsMapEntryMessage(field->containing_type()) ? "" : "_impl_.";
@ -876,8 +874,6 @@ std::string SafeFunctionName(const Descriptor* descriptor,
bool IsProfileDriven(const Options& options) {
return options.access_info_map != nullptr;
}
bool IsStringInlined(const FieldDescriptor* descriptor,
const Options& options) {
(void)descriptor;

@ -828,7 +828,6 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) {
// Generate type-specific accessor declarations.
field_generators_.get(field).GenerateAccessorDeclarations(printer);
format("\n");
}
@ -1238,41 +1237,41 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) {
Formatter::SaveState saver(&format);
format.AddMap(vars);
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
if (IsFieldStripped(field, options_)) {
format(
"inline int $classname$::$name$_size() const { "
"__builtin_trap(); }\n");
} else {
format(
"inline int $classname$::_internal_$name$_size() const {\n"
" return $field$$1$.size();\n"
"}\n"
"inline int $classname$::$name$_size() const {\n"
"$annotate_size$"
" return _internal_$name$_size();\n"
"}\n",
IsImplicitWeakField(field, options_, scc_analyzer_) &&
field->message_type()
? ".weak"
: "");
}
} else if (field->real_containing_oneof()) {
format.Set("field_name", UnderscoresToCamelCase(field->name(), true));
format.Set("oneof_name", field->containing_oneof()->name());
format.Set("oneof_index",
StrCat(field->containing_oneof()->index()));
GenerateOneofMemberHasBits(field, format);
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
if (IsFieldStripped(field, options_)) {
format(
"inline int $classname$::$name$_size() const { "
"__builtin_trap(); }\n");
} else {
// Singular field.
GenerateSingularFieldHasBits(field, format);
format(
"inline int $classname$::_internal_$name$_size() const {\n"
" return $field$$1$.size();\n"
"}\n"
"inline int $classname$::$name$_size() const {\n"
"$annotate_size$"
" return _internal_$name$_size();\n"
"}\n",
IsImplicitWeakField(field, options_, scc_analyzer_) &&
field->message_type()
? ".weak"
: "");
}
} else if (field->real_containing_oneof()) {
format.Set("field_name", UnderscoresToCamelCase(field->name(), true));
format.Set("oneof_name", field->containing_oneof()->name());
format.Set("oneof_index",
StrCat(field->containing_oneof()->index()));
GenerateOneofMemberHasBits(field, format);
} else {
// Singular field.
GenerateSingularFieldHasBits(field, format);
}
if (!IsCrossFileMaybeMap(field)) {
GenerateFieldClear(field, true, format);
}
// Generate type-specific accessors.
if (!IsFieldStripped(field, options_)) {
field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
@ -1760,7 +1759,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
format(
"private:\n"
"inline bool IsSplitMessageDefault() const {\n"
" return $split$ == reinterpret_cast<Impl_::Split*>(&$1$);\n"
" return $split$ == reinterpret_cast<const Impl_::Split*>(&$1$);\n"
"}\n"
"PROTOBUF_NOINLINE void PrepareSplitMessageForWrite();\n"
"public:\n",
@ -1928,6 +1927,8 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
" typedef void InternalArenaConstructable_;\n"
" typedef void DestructorSkippable_;\n"
"};\n"
"static_assert(std::is_trivially_copy_constructible<Split>::value);\n"
"static_assert(std::is_trivially_destructible<Split>::value);\n"
"Split* _split_;\n");
}
@ -2421,8 +2422,15 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
}
if (ShouldSplit(descriptor_, options_)) {
put_sep();
format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
DefaultInstanceName(descriptor_, options_, /*split=*/true));
// We can't assign the default split to this->split without the const_cast
// because the former is a const. The const_cast is safe because we don't
// intend to modify the default split through this pointer, and we also
// expect the default split to be in the rodata section which is protected
// from mutation.
format(
"decltype($split$){const_cast<Impl_::Split*>"
"(reinterpret_cast<const Impl_::Split*>(&$1$))}",
DefaultInstanceName(descriptor_, options_, /*split=*/true));
}
for (auto oneof : OneOfRange(descriptor_)) {
put_sep();
@ -2681,7 +2689,7 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) {
}
if (ShouldSplit(descriptor_, options_)) {
put_sep();
format("/*decltype($split$)*/&$1$._instance",
format("/*decltype($split$)*/const_cast<Impl_::Split*>(&$1$._instance)",
DefaultInstanceName(descriptor_, options_, /*split=*/true));
}
@ -2866,8 +2874,10 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
}
if (ShouldSplit(descriptor_, options_)) {
put_sep();
format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
DefaultInstanceName(descriptor_, options_, /*split=*/true));
format(
"decltype($split$){const_cast<Impl_::Split*>"
"(reinterpret_cast<const Impl_::Split*>(&$1$))}",
DefaultInstanceName(descriptor_, options_, /*split=*/true));
}
for (auto oneof : OneOfRange(descriptor_)) {
put_sep();

@ -83,7 +83,8 @@ int TagSize(uint32_t field_number) {
return 2;
}
void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry,
void PopulateFastFieldEntry(const Descriptor* descriptor,
const TailCallTableInfo::FieldEntryInfo& entry,
const Options& options,
TailCallTableInfo::FastFieldInfo& info);
@ -158,6 +159,7 @@ bool IsFieldEligibleForFastParsing(
}
std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize(
const Descriptor* descriptor,
const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries,
int table_size_log2, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
@ -200,7 +202,7 @@ std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize(
GOOGLE_CHECK(info.func_name.empty()) << info.func_name;
info.field = field;
info.coded_tag = tag;
PopulateFastFieldEntry(entry, options, info);
PopulateFastFieldEntry(descriptor, entry, options, info);
// If this field does not have presence, then it can set an out-of-bounds
// bit (tailcall parsing uses a uint64_t for hasbits, but only stores 32).
info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63;
@ -412,8 +414,8 @@ TailCallTableInfo::TailCallTableInfo(
int num_fast_fields = -1;
for (int try_size_log2 : {0, 1, 2, 3, 4, 5}) {
size_t try_size = 1 << try_size_log2;
auto split_fields = SplitFastFieldsForSize(field_entries, try_size_log2,
options, scc_analyzer);
auto split_fields = SplitFastFieldsForSize(
descriptor, field_entries, try_size_log2, options, scc_analyzer);
GOOGLE_CHECK_EQ(split_fields.size(), try_size);
int try_num_fast_fields = 0;
for (const auto& info : split_fields) {
@ -1667,11 +1669,12 @@ void ParseFunctionGenerator::GenerateFieldSwitch(
namespace {
void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry,
void PopulateFastFieldEntry(const Descriptor* descriptor,
const TailCallTableInfo::FieldEntryInfo& entry,
const Options& options,
TailCallTableInfo::FastFieldInfo& info) {
const FieldDescriptor* field = entry.field;
std::string name = "::_pbi::TcParser::Fast";
std::string name;
uint8_t aux_idx = static_cast<uint8_t>(entry.aux_idx);
switch (field->type()) {
@ -1784,7 +1787,36 @@ void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry,
// Append the tag length. Fast parsing only handles 1- or 2-byte tags.
name.append(TagSize(field->number()) == 1 ? "1" : "2");
info.func_name = std::move(name);
if (name == "V8S1") {
info.func_name = StrCat(
"::_pbi::TcParser::SingularVarintNoZag1<bool, offsetof(", //
ClassName(descriptor), //
", ", //
FieldMemberName(field, /*split=*/false), //
"), ", //
HasHasbit(field) ? entry.hasbit_idx : 63, //
">()");
} else if (name == "V32S1") {
info.func_name = StrCat(
"::_pbi::TcParser::SingularVarintNoZag1<uint32_t, offsetof(", //
ClassName(descriptor), //
", ", //
FieldMemberName(field, /*split=*/false), //
"), ", //
HasHasbit(field) ? entry.hasbit_idx : 63, //
">()");
} else if (name == "V64S1") {
info.func_name = StrCat(
"::_pbi::TcParser::SingularVarintNoZag1<uint64_t, offsetof(", //
ClassName(descriptor), //
", ", //
FieldMemberName(field, /*split=*/false), //
"), ", //
HasHasbit(field) ? entry.hasbit_idx : 63, //
">()");
} else {
info.func_name = StrCat("::_pbi::TcParser::Fast", name);
}
info.aux_idx = aux_idx;
}

@ -379,15 +379,30 @@ std::string GetFieldConstantName(const FieldDescriptor* field) {
}
std::string GetPropertyName(const FieldDescriptor* descriptor) {
// Names of members declared or overridden in the message.
static const auto& reserved_member_names = *new std::unordered_set<std::string>({
"Types",
"Descriptor",
"Equals",
"ToString",
"GetHashCode",
"WriteTo",
"Clone",
"CalculateSize",
"MergeFrom",
"OnConstruction",
"Parser"
});
// TODO(jtattermusch): consider introducing csharp_property_name field option
std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor));
// Avoid either our own type name or reserved names. Note that not all names
// are reserved - a field called to_string, write_to etc would still cause a problem.
// Avoid either our own type name or reserved names.
// There are various ways of ending up with naming collisions, but we try to avoid obvious
// ones.
// ones. In particular, we avoid the names of all the members we generate.
// Note that we *don't* add an underscore for MemberwiseClone or GetType. Those generate
// warnings, but not errors; changing the name now could be a breaking change.
if (property_name == descriptor->containing_type()->name()
|| property_name == "Types"
|| property_name == "Descriptor") {
|| reserved_member_names.find(property_name) != reserved_member_names.end()) {
property_name += "_";
}
return property_name;

@ -281,6 +281,18 @@ void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
" $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
" }\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
printer->Print(
variables_,
"$kt_deprecation$ var $kt_name$Value: kotlin.Int\n"
" @JvmName(\"${$get$kt_capitalized_name$Value$}$\")\n"
" get() = $kt_dsl_builder$.${$get$capitalized_name$Value$}$()\n"
" @JvmName(\"${$set$kt_capitalized_name$Value$}$\")\n"
" set(value) {\n"
" $kt_dsl_builder$.${$set$capitalized_name$Value$}$(value)\n"
" }\n");
}
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
/* builder */ false, /* kdoc */ true);
printer->Print(variables_,

@ -296,6 +296,18 @@ void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
" $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
" }\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
printer->Print(
variables_,
"$kt_deprecation$ var $kt_name$Value: kotlin.Int\n"
" @JvmName(\"${$get$kt_capitalized_name$Value$}$\")\n"
" get() = $kt_dsl_builder$.${$get$capitalized_name$Value$}$()\n"
" @JvmName(\"${$set$kt_capitalized_name$Value$}$\")\n"
" set(value) {\n"
" $kt_dsl_builder$.${$set$capitalized_name$Value$}$(value)\n"
" }\n");
}
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
/* builder */ false, /* kdoc */ true);
printer->Print(variables_,

@ -63,7 +63,12 @@ class PROTOC_EXPORT JavaGenerator : public CodeGenerator {
uint64_t GetSupportedFeatures() const override;
void set_opensource_runtime(bool opensource) {
opensource_runtime_ = opensource;
}
private:
bool opensource_runtime_ = true;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator);
};

@ -32,6 +32,7 @@
#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_SERIALIZATION_H__
#include <algorithm>
#include <cstddef>
#include <vector>
#include <google/protobuf/io/printer.h>
@ -66,20 +67,31 @@ void GenerateSerializeFieldsAndExtensions(
std::sort(sorted_extensions.begin(), sorted_extensions.end(),
ExtensionRangeOrdering());
std::size_t range_idx = 0;
// Merge the fields and the extension ranges, both sorted by field number.
for (int i = 0, j = 0;
i < descriptor->field_count() || j < sorted_extensions.size();) {
if (i == descriptor->field_count()) {
GenerateSerializeExtensionRange(printer, sorted_extensions[j++]);
} else if (j == sorted_extensions.size()) {
field_generators.get(sorted_fields[i++])
.GenerateSerializationCode(printer);
} else if (sorted_fields[i]->number() < sorted_extensions[j]->start) {
field_generators.get(sorted_fields[i++])
.GenerateSerializationCode(printer);
} else {
GenerateSerializeExtensionRange(printer, sorted_extensions[j++]);
for (int i = 0; i < descriptor->field_count(); ++i) {
const FieldDescriptor* field = sorted_fields[i];
// Collapse all extension ranges up until the next field. This leads to
// shorter and more efficient codegen for messages containing a large
// number of extension ranges without fields in between them.
const Descriptor::ExtensionRange* range = nullptr;
while (range_idx < sorted_extensions.size() &&
sorted_extensions[range_idx]->end <= field->number()) {
range = sorted_extensions[range_idx++];
}
if (range != nullptr) {
GenerateSerializeExtensionRange(printer, range);
}
field_generators.get(field).GenerateSerializationCode(printer);
}
// After serializing all fields, serialize any remaining extensions via a
// single writeUntil call.
if (range_idx < sorted_extensions.size()) {
GenerateSerializeExtensionRange(printer, sorted_extensions.back());
}
}

@ -0,0 +1,124 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
#include <gmock/gmock.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/compiler/java/generator.h>
#include <google/protobuf/test_util2.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace java {
namespace {
using ::testing::ElementsAre;
// Generates Java code for the specified Java proto, returning the compiler's
// exit status.
int CompileJavaProto(std::string proto_file_name) {
JavaGenerator java_generator;
CommandLineInterface cli;
cli.RegisterGenerator("--java_out", &java_generator, /*help_text=*/"");
std::string proto_path = StrCat(
"--proto_path=",
TestUtil::GetTestDataPath("third_party/protobuf/compiler/java"));
std::string java_out = StrCat("--java_out=", TestTempDir());
const char* argv[] = {
"protoc",
proto_path.c_str(),
java_out.c_str(),
proto_file_name.c_str(),
};
// Open-source codebase does not support ABSL_ARRAYSIZE.
return cli.Run(sizeof(argv) / sizeof(*argv), argv);
}
TEST(MessageSerializationTest, CollapseAdjacentExtensionRanges) {
GOOGLE_CHECK_EQ(CompileJavaProto("message_serialization_unittest.proto"), 0);
std::string java_source;
GOOGLE_CHECK_OK(File::GetContents(
// Open-source codebase does not support file::JoinPath, so we manually
// concatenate instead.
StrCat(TestTempDir(),
"/TestMessageWithManyExtensionRanges.java"),
&java_source, true));
// Open-source codebase does not support constexpr StringPiece.
static constexpr const char kWriteUntilCall[] = "extensionWriter.writeUntil(";
std::vector<std::string> range_ends;
// Open-source codebase does not have Split overload taking a single
// char delimiter.
//
// NOLINTNEXTLINE(abseil-faster-strsplit-delimiter)
for (const auto& line : Split(java_source, "\n")) {
// Extract end position from writeUntil call. (Open-source codebase does not
// support RE2.)
std::size_t write_until_pos = line.find(kWriteUntilCall);
if (write_until_pos == std::string::npos) {
continue;
}
write_until_pos += (sizeof(kWriteUntilCall) - 1);
std::size_t comma_pos = line.find(',', write_until_pos);
if (comma_pos == std::string::npos) {
continue;
}
range_ends.push_back(
std::string(line.substr(write_until_pos, comma_pos - write_until_pos)));
}
EXPECT_THAT(range_ends, ElementsAre("3", "13", "43"));
}
} // namespace
} // namespace java
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -0,0 +1,56 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
package protobuf_unittest;
option java_multiple_files = true;
option java_package = "";
// Each batch of extension ranges not separated by a non-extension field should
// be serialized using a single ExtensionWriter#writeUntil call.
message TestMessageWithManyExtensionRanges {
// First extension range: ends at field number 3 (exclusive)
extensions 1 to 2;
optional int32 foo = 3;
optional int32 bar = 5;
// Second extension range: ends at field number 13 (exclusive)
extensions 6;
extensions 8;
extensions 10 to 12;
optional int32 baz = 23;
// Third extension range: ends at field number 43 (exclusive)
extensions 42;
}

@ -66,6 +66,10 @@ int ProtobufMain(int argc, char* argv[]) {
cli.RegisterGenerator("--java_out", "--java_opt", &java_generator,
"Generate Java source file.");
#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
java_generator.set_opensource_runtime(true);
#endif
// Proto2 Kotlin
java::KotlinGenerator kt_generator;
cli.RegisterGenerator("--kotlin_out", "--kotlin_opt", &kt_generator,
@ -76,6 +80,11 @@ int ProtobufMain(int argc, char* argv[]) {
python::Generator py_generator;
cli.RegisterGenerator("--python_out", "--python_opt", &py_generator,
"Generate Python source file.");
#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
py_generator.set_opensource_runtime(true);
#endif
// Python pyi
python::PyiGenerator pyi_generator;
cli.RegisterGenerator("--pyi_out", &pyi_generator,

@ -388,7 +388,7 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration(
"$comments$"
"$array_comment$"
"@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
"/** The number of items in @c $name$ without causing the array to be created. */\n"
"/** The number of items in @c $name$ without causing the container to be created. */\n"
"@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
if (IsInitName(variables_.find("name")->second)) {
// If property name starts with init we need to annotate it to get past ARC.

@ -48,29 +48,29 @@ const std::string kDescriptorMetadataFile =
const std::string kDescriptorDirName = "Google/Protobuf/Internal";
const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
const char* const kReservedNames[] = {
"abstract", "and", "array", "as", "break",
"callable", "case", "catch", "class", "clone",
"const", "continue", "declare", "default", "die",
"do", "echo", "else", "elseif", "empty",
"enddeclare", "endfor", "endforeach", "endif", "endswitch",
"endwhile", "eval", "exit", "extends", "final",
"finally", "fn", "for", "foreach", "function",
"global", "goto", "if", "implements", "include",
"include_once", "instanceof", "insteadof", "interface", "isset",
"list", "match", "namespace", "new", "or",
"parent", "print", "private", "protected", "public",
"require", "require_once", "return", "self", "static",
"switch", "throw", "trait", "try", "unset",
"use", "var", "while", "xor", "yield",
"int", "float", "bool", "string", "true",
"false", "null", "void", "iterable"};
"abstract", "and", "array", "as", "break",
"callable", "case", "catch", "class", "clone",
"const", "continue", "declare", "default", "die",
"do", "echo", "else", "elseif", "empty",
"enddeclare", "endfor", "endforeach", "endif", "endswitch",
"endwhile", "eval", "exit", "extends", "final",
"finally", "fn", "for", "foreach", "function",
"global", "goto", "if", "implements", "include",
"include_once", "instanceof", "insteadof", "interface", "isset",
"list", "match", "namespace", "new", "or",
"parent", "print", "private", "protected", "public",
"readonly", "require", "require_once", "return", "self",
"static", "switch", "throw", "trait", "try",
"unset", "use", "var", "while", "xor",
"yield", "int", "float", "bool", "string",
"true", "false", "null", "void", "iterable"};
const char* const kValidConstantNames[] = {
"int", "float", "bool", "string", "true",
"false", "null", "void", "iterable", "parent",
"self"
"self", "readonly"
};
const int kReservedNamesSize = 79;
const int kValidConstantNamesSize = 11;
const int kReservedNamesSize = 80;
const int kValidConstantNamesSize = 12;
const int kFieldSetter = 1;
const int kFieldGetter = 2;
const int kFieldProperty = 3;
@ -407,6 +407,29 @@ std::string GeneratedClassFileName(const DescriptorType* desc,
return result + ".php";
}
template <typename DescriptorType>
std::string LegacyGeneratedClassFileName(const DescriptorType* desc,
const Options& options) {
std::string result = LegacyFullClassName(desc, options);
for (int i = 0; i < result.size(); i++) {
if (result[i] == '\\') {
result[i] = '/';
}
}
return result + ".php";
}
template <typename DescriptorType>
std::string LegacyReadOnlyGeneratedClassFileName(const DescriptorType* desc,
const Options& options) {
std::string php_namespace = RootPhpNamespace(desc, options);
if (!php_namespace.empty()) {
return php_namespace + "/" + desc->name() + ".php";
}
return desc->name() + ".php";
}
std::string GeneratedServiceFileName(const ServiceDescriptor* service,
const Options& options) {
std::string result = FullClassName(service, options) + "Interface";
@ -1252,6 +1275,70 @@ void GenerateMetadataFile(const FileDescriptor* file, const Options& options,
printer.Print("}\n\n");
}
template <typename DescriptorType>
void LegacyGenerateClassFile(const FileDescriptor* file,
const DescriptorType* desc, const Options& options,
GeneratorContext* generator_context) {
std::string filename = LegacyGeneratedClassFileName(desc, options);
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(filename));
io::Printer printer(output.get(), '^');
GenerateHead(file, &printer);
std::string php_namespace = RootPhpNamespace(desc, options);
if (!php_namespace.empty()) {
printer.Print(
"namespace ^name^;\n\n",
"name", php_namespace);
}
std::string newname = FullClassName(desc, options);
printer.Print("if (false) {\n");
Indent(&printer);
printer.Print("/**\n");
printer.Print(" * This class is deprecated. Use ^new^ instead.\n",
"new", newname);
printer.Print(" * @deprecated\n");
printer.Print(" */\n");
printer.Print("class ^old^ {}\n",
"old", LegacyGeneratedClassName(desc));
Outdent(&printer);
printer.Print("}\n");
printer.Print("class_exists(^new^::class);\n",
"new", GeneratedClassNameImpl(desc));
printer.Print("@trigger_error('^old^ is deprecated and will be removed in "
"the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
"old", LegacyFullClassName(desc, options),
"fullname", newname);
}
template <typename DescriptorType>
void LegacyReadOnlyGenerateClassFile(const FileDescriptor* file,
const DescriptorType* desc, const Options& options,
GeneratorContext* generator_context) {
std::string filename = LegacyReadOnlyGeneratedClassFileName(desc, options);
std::unique_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(filename));
io::Printer printer(output.get(), '^');
GenerateHead(file, &printer);
std::string php_namespace = RootPhpNamespace(desc, options);
if (!php_namespace.empty()) {
printer.Print(
"namespace ^name^;\n\n",
"name", php_namespace);
}
std::string newname = FullClassName(desc, options);
printer.Print("class_exists(^new^::class); // autoload the new class, which "
"will also create an alias to the deprecated class\n",
"new", GeneratedClassNameImpl(desc));
printer.Print("@trigger_error(__NAMESPACE__ . '\\^old^ is deprecated and will be removed in "
"the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
"old", desc->name(),
"fullname", newname);
}
void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
const Options& options,
GeneratorContext* generator_context) {
@ -1372,6 +1459,19 @@ void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
"new", fullname,
"old", LegacyFullClassName(en, options));
}
// Write legacy file for backwards compatibility with "readonly" keywword
std::string lower = en->name();
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
if (lower == "readonly") {
printer.Print(
"// Adding a class alias for backwards compatibility with the \"readonly\" keyword.\n");
printer.Print(
"class_alias(^new^::class, __NAMESPACE__ . '\\^old^');\n\n",
"new", fullname,
"old", en->name());
LegacyReadOnlyGenerateClassFile(file, en, options, generator_context);
}
}
void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
@ -1487,6 +1587,19 @@ void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
"old", LegacyFullClassName(message, options));
}
// Write legacy file for backwards compatibility with "readonly" keywword
std::string lower = message->name();
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
if (lower == "readonly") {
printer.Print(
"// Adding a class alias for backwards compatibility with the \"readonly\" keyword.\n");
printer.Print(
"class_alias(^new^::class, __NAMESPACE__ . '\\^old^');\n\n",
"new", fullname,
"old", message->name());
LegacyReadOnlyGenerateClassFile(file, message, options, generator_context);
}
// Nested messages and enums.
for (int i = 0; i < message->nested_type_count(); i++) {
GenerateMessageFile(file, message->nested_type(i), options,

@ -76,6 +76,10 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
uint64_t GetSupportedFeatures() const override;
void set_opensource_runtime(bool opensource) {
opensource_runtime_ = opensource;
}
private:
void PrintImports() const;
void PrintFileDescriptor() const;
@ -172,6 +176,8 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
mutable io::Printer* printer_; // Set in Generate(). Under mutex_.
mutable bool pure_python_workable_;
bool opensource_runtime_ = true;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator);
};

@ -64,19 +64,17 @@ void PyiGenerator::PrintItemMap(
}
template <typename DescriptorT>
std::string PyiGenerator::ModuleLevelName(
const DescriptorT& descriptor,
const std::map<std::string, std::string>& import_map) const {
std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
if (descriptor.file() != file_) {
std::string module_alias;
std::string filename = descriptor.file()->name();
if (import_map.find(filename) == import_map.end()) {
if (import_map_.find(filename) == import_map_.end()) {
std::string module_name = ModuleName(descriptor.file()->name());
std::vector<std::string> tokens = Split(module_name, ".");
module_alias = "_" + tokens.back();
} else {
module_alias = import_map.at(filename);
module_alias = import_map_.at(filename);
}
name = module_alias + "." + name;
}
@ -156,7 +154,6 @@ void CheckImportModules(const Descriptor* descriptor,
void PyiGenerator::PrintImportForDescriptor(
const FileDescriptor& desc,
std::map<std::string, std::string>* import_map,
std::set<std::string>* seen_aliases) const {
const std::string& filename = desc.name();
std::string module_name = StrippedModuleName(filename);
@ -176,21 +173,20 @@ void PyiGenerator::PrintImportForDescriptor(
}
printer_->Print("$statement$ as $alias$\n", "statement",
import_statement, "alias", alias);
(*import_map)[filename] = alias;
import_map_[filename] = alias;
seen_aliases->insert(alias);
}
void PyiGenerator::PrintImports(
std::map<std::string, std::string>* item_map,
std::map<std::string, std::string>* import_map) const {
std::map<std::string, std::string>* item_map) const {
// Prints imported dependent _pb2 files.
std::set<std::string> seen_aliases;
for (int i = 0; i < file_->dependency_count(); ++i) {
const FileDescriptor* dep = file_->dependency(i);
PrintImportForDescriptor(*dep, import_map, &seen_aliases);
PrintImportForDescriptor(*dep, &seen_aliases);
for (int j = 0; j < dep->public_dependency_count(); ++j) {
PrintImportForDescriptor(
*dep->public_dependency(j), import_map, &seen_aliases);
*dep->public_dependency(j), &seen_aliases);
}
}
@ -277,7 +273,7 @@ void PyiGenerator::PrintImports(
const EnumDescriptor* enum_descriptor = public_dep->enum_type(i);
for (int j = 0; j < enum_descriptor->value_count(); ++j) {
(*item_map)[enum_descriptor->value(j)->name()] =
ModuleLevelName(*enum_descriptor, *import_map);
ModuleLevelName(*enum_descriptor);
}
}
// Top level extensions for public imports
@ -296,10 +292,9 @@ void PyiGenerator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
// Adds enum value to item map which will be ordered and printed later.
void PyiGenerator::AddEnumValue(
const EnumDescriptor& enum_descriptor,
std::map<std::string, std::string>* item_map,
const std::map<std::string, std::string>& import_map) const {
std::map<std::string, std::string>* item_map) const {
// enum values
std::string module_enum_name = ModuleLevelName(enum_descriptor, import_map);
std::string module_enum_name = ModuleLevelName(enum_descriptor);
for (int j = 0; j < enum_descriptor.value_count(); ++j) {
const EnumValueDescriptor* value_descriptor = enum_descriptor.value(j);
(*item_map)[value_descriptor->name()] = module_enum_name;
@ -331,8 +326,7 @@ void PyiGenerator::AddExtensions(
// Returns the string format of a field's cpp_type
std::string PyiGenerator::GetFieldType(
const FieldDescriptor& field_des, const Descriptor& containing_des,
const std::map<std::string, std::string>& import_map) const {
const FieldDescriptor& field_des, const Descriptor& containing_des) const {
switch (field_des.cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
case FieldDescriptor::CPPTYPE_UINT32:
@ -345,7 +339,7 @@ std::string PyiGenerator::GetFieldType(
case FieldDescriptor::CPPTYPE_BOOL:
return "bool";
case FieldDescriptor::CPPTYPE_ENUM:
return ModuleLevelName(*field_des.enum_type(), import_map);
return ModuleLevelName(*field_des.enum_type());
case FieldDescriptor::CPPTYPE_STRING:
if (field_des.type() == FieldDescriptor::TYPE_STRING) {
return "str";
@ -356,7 +350,7 @@ std::string PyiGenerator::GetFieldType(
// If the field is inside a nested message and the nested message has the
// same name as a top-level message, then we need to prefix the field type
// with the module name for disambiguation.
std::string name = ModuleLevelName(*field_des.message_type(), import_map);
std::string name = ModuleLevelName(*field_des.message_type());
if ((containing_des.containing_type() != nullptr &&
name == containing_des.name())) {
std::string module = ModuleName(field_des.file()->name());
@ -371,8 +365,7 @@ std::string PyiGenerator::GetFieldType(
}
void PyiGenerator::PrintMessage(
const Descriptor& message_descriptor, bool is_nested,
const std::map<std::string, std::string>& import_map) const {
const Descriptor& message_descriptor, bool is_nested) const {
if (!is_nested) {
printer_->Print("\n");
}
@ -431,7 +424,7 @@ void PyiGenerator::PrintMessage(
for (const auto& entry : nested_enums) {
PrintEnum(*entry);
// Adds enum value to item_map which will be ordered and printed later
AddEnumValue(*entry, &item_map, import_map);
AddEnumValue(*entry, &item_map);
}
// Prints nested messages
@ -444,7 +437,7 @@ void PyiGenerator::PrintMessage(
SortByName<Descriptor>());
for (const auto& entry : nested_messages) {
PrintMessage(*entry, true, import_map);
PrintMessage(*entry, true);
}
// Adds extensions to item_map which will be ordered and printed later
@ -465,16 +458,16 @@ void PyiGenerator::PrintMessage(
field_type = (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
? "_containers.MessageMap["
: "_containers.ScalarMap[");
field_type += GetFieldType(*key_des, message_descriptor, import_map);
field_type += GetFieldType(*key_des, message_descriptor);
field_type += ", ";
field_type += GetFieldType(*value_des, message_descriptor, import_map);
field_type += GetFieldType(*value_des, message_descriptor);
} else {
if (field_des.is_repeated()) {
field_type = (field_des.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
? "_containers.RepeatedCompositeFieldContainer["
: "_containers.RepeatedScalarFieldContainer[");
}
field_type += GetFieldType(field_des, message_descriptor, import_map);
field_type += GetFieldType(field_des, message_descriptor);
}
if (field_des.is_repeated()) {
@ -513,9 +506,9 @@ void PyiGenerator::PrintMessage(
const Descriptor* map_entry = field_des->message_type();
printer_->Print(
"_Mapping[$key_type$, $value_type$]", "key_type",
GetFieldType(*map_entry->field(0), message_descriptor, import_map),
GetFieldType(*map_entry->field(0), message_descriptor),
"value_type",
GetFieldType(*map_entry->field(1), message_descriptor, import_map));
GetFieldType(*map_entry->field(1), message_descriptor));
} else {
if (field_des->is_repeated()) {
printer_->Print("_Iterable[");
@ -523,15 +516,15 @@ void PyiGenerator::PrintMessage(
if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer_->Print(
"_Union[$type_name$, _Mapping]", "type_name",
GetFieldType(*field_des, message_descriptor, import_map));
GetFieldType(*field_des, message_descriptor));
} else {
if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
printer_->Print("_Union[$type_name$, str]", "type_name",
ModuleLevelName(*field_des->enum_type(), import_map));
ModuleLevelName(*field_des->enum_type()));
} else {
printer_->Print(
"$type_name$", "type_name",
GetFieldType(*field_des, message_descriptor, import_map));
GetFieldType(*field_des, message_descriptor));
}
}
if (field_des->is_repeated()) {
@ -553,8 +546,7 @@ void PyiGenerator::PrintMessage(
printer_->Outdent();
}
void PyiGenerator::PrintMessages(
const std::map<std::string, std::string>& import_map) const {
void PyiGenerator::PrintMessages() const {
// Deterministically order the descriptors.
std::vector<const Descriptor*> messages;
messages.reserve(file_->message_type_count());
@ -564,7 +556,7 @@ void PyiGenerator::PrintMessages(
std::sort(messages.begin(), messages.end(), SortByName<Descriptor>());
for (const auto& entry : messages) {
PrintMessage(*entry, false, import_map);
PrintMessage(*entry, false);
}
}
@ -591,6 +583,7 @@ bool PyiGenerator::Generate(const FileDescriptor* file,
GeneratorContext* context,
std::string* error) const {
MutexLock lock(&mutex_);
import_map_.clear();
// Calculate file name.
file_ = file;
std::string filename =
@ -608,21 +601,17 @@ bool PyiGenerator::Generate(const FileDescriptor* file,
// Adds "DESCRIPTOR" into item_map.
item_map["DESCRIPTOR"] = "_descriptor.FileDescriptor";
// import_map will be a mapping from filename to module alias, e.g.
// "google3/foo/bar.py" -> "_bar"
std::map<std::string, std::string> import_map;
PrintImports(&item_map, &import_map);
PrintImports(&item_map);
// Adds top level enum values to item_map.
for (int i = 0; i < file_->enum_type_count(); ++i) {
AddEnumValue(*file_->enum_type(i), &item_map, import_map);
AddEnumValue(*file_->enum_type(i), &item_map);
}
// Adds top level extensions to item_map.
AddExtensions(*file_, &item_map);
// Prints item map
PrintItemMap(item_map);
PrintMessages(import_map);
PrintMessages();
PrintTopLevelEnums();
if (HasGenericServices(file)) {
PrintServices();

@ -76,37 +76,32 @@ class PROTOC_EXPORT PyiGenerator : public google::protobuf::compiler::CodeGenera
private:
void PrintImportForDescriptor(const FileDescriptor& desc,
std::map<std::string, std::string>* import_map,
std::set<std::string>* seen_aliases) const;
void PrintImports(std::map<std::string, std::string>* item_map,
std::map<std::string, std::string>* import_map) const;
void PrintImports(std::map<std::string, std::string>* item_map) const;
void PrintEnum(const EnumDescriptor& enum_descriptor) const;
void AddEnumValue(const EnumDescriptor& enum_descriptor,
std::map<std::string, std::string>* item_map,
const std::map<std::string, std::string>& import_map) const;
std::map<std::string, std::string>* item_map) const;
void PrintTopLevelEnums() const;
template <typename DescriptorT>
void AddExtensions(const DescriptorT& descriptor,
std::map<std::string, std::string>* item_map) const;
void PrintMessages(
const std::map<std::string, std::string>& import_map) const;
void PrintMessage(const Descriptor& message_descriptor, bool is_nested,
const std::map<std::string, std::string>& import_map) const;
void PrintMessages() const;
void PrintMessage(const Descriptor& message_descriptor, bool is_nested) const;
void PrintServices() const;
void PrintItemMap(const std::map<std::string, std::string>& item_map) const;
std::string GetFieldType(
const FieldDescriptor& field_des, const Descriptor& containing_des,
const std::map<std::string, std::string>& import_map) const;
const FieldDescriptor& field_des, const Descriptor& containing_des) const;
template <typename DescriptorT>
std::string ModuleLevelName(
const DescriptorT& descriptor,
const std::map<std::string, std::string>& import_map) const;
std::string ModuleLevelName(const DescriptorT& descriptor) const;
// Very coarse-grained lock to ensure that Generate() is reentrant.
// Guards file_ and printer_.
// Guards file_, printer_, and import_map_.
mutable Mutex mutex_;
mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_.
mutable io::Printer* printer_; // Set in Generate(). Under mutex_.
// import_map will be a mapping from filename to module alias, e.g.
// "google3/foo/bar.py" -> "_bar"
mutable std::map<std::string, std::string> import_map_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PyiGenerator);
};

@ -38,7 +38,6 @@
#include <google/protobuf/port.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_tctable_decl.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/wire_format_lite.h>
@ -257,16 +256,6 @@ enum FieldType : uint16_t {
// clang-format on
} // namespace field_layout
// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
// defined in port_def.inc.
//
// Note that this is performance sensitive: changing the parameters will change
// the registers used by the ABI calling convention, which subsequently affects
// register selection logic inside the function.
// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
#ifndef NDEBUG
template <size_t align>
void AlignFail(uintptr_t address) {
@ -349,6 +338,28 @@ class PROTOBUF_EXPORT TcParser final {
static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
// Manually unrolled and specialized Varint parsing.
template <typename FieldType, int data_offset, int hasbit_idx>
static const char* SpecializedUnrolledVImpl1(PROTOBUF_TC_PARAM_DECL);
template <typename FieldType, int data_offset, int hasbit_idx>
static constexpr TailCallParseFunc SingularVarintNoZag1() {
if (data_offset < 100) {
return &SpecializedUnrolledVImpl1<FieldType, data_offset, hasbit_idx>;
} else if (sizeof(FieldType) == 1) {
return &FastV8S1;
} else if (sizeof(FieldType) == 4) {
return &FastV32S1;
} else if (sizeof(FieldType) == 8) {
return &FastV64S1;
} else {
static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
sizeof(FieldType) == 8,
"");
return nullptr;
}
}
// Functions referenced by generated fast tables (closed enum):
// E: closed enum (N.B.: open enums use V32, above)
// r: enum range v: enum validator (_IsValid function)
@ -600,6 +611,135 @@ class PROTOBUF_EXPORT TcParser final {
static const char* MpMap(PROTOBUF_TC_PARAM_DECL);
};
template <typename FieldType, int data_offset, int hasbit_idx>
const char* TcParser::SpecializedUnrolledVImpl1(PROTOBUF_TC_PARAM_DECL) {
using TagType = uint8_t;
// super-early success test...
if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
ptr += sizeof(TagType); // Consume tag
if (hasbit_idx < 32) {
hasbits |= (uint64_t{1} << hasbit_idx);
}
uint8_t value = data.data >> 8;
RefAt<FieldType>(msg, data_offset) = value;
ptr += 1;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
}
ptr += sizeof(TagType); // Consume tag
if (hasbit_idx < 32) {
hasbits |= (uint64_t{1} << hasbit_idx);
}
// Few registers
auto* out = &RefAt<FieldType>(msg, data_offset);
uint64_t res = 0xFF & (data.data >> 8);
/* if (PROTOBUF_PREDICT_FALSE(res & 0x80)) */ {
res = RotRight7AndReplaceLowByte(res, ptr[1]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[2]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[3]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[4]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[5]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[6]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[7]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
res = RotRight7AndReplaceLowByte(res, ptr[8]);
if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
if (ptr[9] & 0xFE) return nullptr;
res = RotateLeft(res, -7) & ~1;
res += ptr[9] & 1;
*out = RotateLeft(res, 63);
ptr += 10;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 56);
ptr += 9;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 49);
ptr += 8;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 42);
ptr += 7;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 35);
ptr += 6;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 28);
ptr += 5;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 21);
ptr += 4;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 14);
ptr += 3;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = RotateLeft(res, 7);
ptr += 2;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
*out = res;
ptr += 1;
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
PROTOBUF_TC_PARAM_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
const size_t idx = coded_tag & table->fast_idx_mask;
PROTOBUF_ASSUME((idx & 7) == 0);
auto* fast_entry = table->fast_entry(idx >> 3);
data = fast_entry->bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
}
// We can only safely call from field to next field if the call is optimized
// to a proper tail call. Otherwise we blow through stack. Clang and gcc
// reliably do this optimization in opt mode, but do not perform this in debug
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
PROTOBUF_TC_PARAM_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
SyncHasbits(msg, hasbits, table);
return ptr;
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
(void)ptr;
SyncHasbits(msg, hasbits, table);
return nullptr;
}
} // namespace internal
} // namespace protobuf
} // namespace google

@ -30,6 +30,7 @@
#include <cstdint>
#include <numeric>
#include <type_traits>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_tctable_decl.h>
@ -84,56 +85,13 @@ PROTOBUF_NOINLINE const char* TcParser::ParseLoop(
// TODO(b/64614992): remove this asm
asm("" : "+r"(table));
#endif
ptr = TagDispatch(msg, ptr, ctx, table - 1, 0, {});
ptr = TagDispatch(msg, ptr, ctx, {}, table - 1, 0);
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
return ptr;
}
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
PROTOBUF_TC_PARAM_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
const size_t idx = coded_tag & table->fast_idx_mask;
PROTOBUF_ASSUME((idx & 7) == 0);
auto* fast_entry = table->fast_entry(idx >> 3);
data = fast_entry->bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
}
// We can only safely call from field to next field if the call is optimized
// to a proper tail call. Otherwise we blow through stack. Clang and gcc
// reliably do this optimization in opt mode, but do not perform this in debug
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
PROTOBUF_TC_PARAM_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
SyncHasbits(msg, hasbits, table);
return ptr;
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
(void)ptr;
SyncHasbits(msg, hasbits, table);
return nullptr;
}
// On the fast path, a (matching) 1-byte tag already has the decoded value.
static uint32_t FastDecodeTag(uint8_t coded_tag) {
return coded_tag;
@ -875,8 +833,31 @@ PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint(
}
const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<bool, uint8_t>(
PROTOBUF_TC_PARAM_PASS);
// Special case for a varint bool field with a tag of 1 byte:
// The coded_tag() field will actually contain the value too and we can check
// both at the same time.
auto coded_tag = data.coded_tag<uint16_t>();
if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
auto& field = RefAt<bool>(msg, data.offset());
// Note: we use `data.data` because Clang generates suboptimal code when
// using coded_tag.
// In x86_64 this uses the CH register to read the second byte out of
// `data`.
uint8_t value = data.data >> 8;
// The assume allows using a mov instead of test+setne.
PROTOBUF_ASSUME(value <= 1);
field = static_cast<bool>(value);
ptr += 2; // Consume the tag and the value.
hasbits |= (uint64_t{1} << data.hasbit_idx());
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
// If it didn't match above either the tag is wrong, or the value is encoded
// non-canonically.
// Jump to MiniParse as wrong tag is the most probable reason.
PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
}
const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(

@ -251,7 +251,8 @@ class PROTOBUF_EXPORT Printer {
template <typename... Args>
void Print(const char* text, const Args&... args) {
std::map<std::string, std::string> vars;
PrintInternal(&vars, text, args...);
FillMap(&vars, args...);
Print(vars, text);
}
// Indent text by two spaces. After calling Indent(), two spaces will be
@ -299,18 +300,13 @@ class PROTOBUF_EXPORT Printer {
void Annotate(const char* begin_varname, const char* end_varname,
const std::string& file_path, const std::vector<int>& path);
// Base case
void PrintInternal(std::map<std::string, std::string>* vars,
const char* text) {
Print(*vars, text);
}
void FillMap(std::map<std::string, std::string>* vars) {}
template <typename... Args>
void PrintInternal(std::map<std::string, std::string>* vars, const char* text,
const char* key, const std::string& value,
const Args&... args) {
void FillMap(std::map<std::string, std::string>* vars, const std::string& key,
const std::string& value, const Args&... args) {
(*vars)[key] = value;
PrintInternal(vars, text, args...);
FillMap(vars, args...);
}
// Copy size worth of bytes from data to buffer_.

@ -214,7 +214,7 @@ uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
}
namespace internal {
void* CreateSplitMessageGeneric(Arena* arena, void* default_split,
void* CreateSplitMessageGeneric(Arena* arena, const void* default_split,
size_t size) {
void* split =
(arena == nullptr) ? ::operator new(size) : arena->AllocateAligned(size);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save