google-protobuf 3.22.3 → 3.25.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +23 -70
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +36 -48
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +2 -1
  8. data/ext/google/protobuf_c/glue.c +21 -0
  9. data/ext/google/protobuf_c/map.c +7 -28
  10. data/ext/google/protobuf_c/map.h +3 -28
  11. data/ext/google/protobuf_c/message.c +37 -75
  12. data/ext/google/protobuf_c/message.h +3 -28
  13. data/ext/google/protobuf_c/protobuf.c +39 -176
  14. data/ext/google/protobuf_c/protobuf.h +24 -32
  15. data/ext/google/protobuf_c/repeated_field.c +9 -29
  16. data/ext/google/protobuf_c/repeated_field.h +3 -28
  17. data/ext/google/protobuf_c/ruby-upb.c +2982 -2494
  18. data/ext/google/protobuf_c/ruby-upb.h +5836 -3465
  19. data/ext/google/protobuf_c/shared_convert.c +64 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +65 -0
  22. data/ext/google/protobuf_c/shared_message.h +25 -0
  23. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  24. data/lib/google/protobuf/any_pb.rb +24 -5
  25. data/lib/google/protobuf/api_pb.rb +26 -23
  26. data/lib/google/protobuf/descriptor_pb.rb +40 -252
  27. data/lib/google/protobuf/duration_pb.rb +24 -5
  28. data/lib/google/protobuf/empty_pb.rb +24 -3
  29. data/lib/google/protobuf/ffi/descriptor.rb +154 -0
  30. data/lib/google/protobuf/ffi/descriptor_pool.rb +70 -0
  31. data/lib/google/protobuf/ffi/enum_descriptor.rb +161 -0
  32. data/lib/google/protobuf/ffi/ffi.rb +213 -0
  33. data/lib/google/protobuf/ffi/field_descriptor.rb +309 -0
  34. data/lib/google/protobuf/ffi/file_descriptor.rb +48 -0
  35. data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
  36. data/lib/google/protobuf/ffi/internal/convert.rb +305 -0
  37. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  38. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  39. data/lib/google/protobuf/ffi/map.rb +396 -0
  40. data/lib/google/protobuf/ffi/message.rb +641 -0
  41. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  42. data/lib/google/protobuf/ffi/oneof_descriptor.rb +88 -0
  43. data/lib/google/protobuf/ffi/repeated_field.rb +503 -0
  44. data/lib/google/protobuf/field_mask_pb.rb +24 -4
  45. data/lib/google/protobuf/message_exts.rb +3 -26
  46. data/lib/google/protobuf/object_cache.rb +97 -0
  47. data/lib/google/protobuf/plugin_pb.rb +25 -28
  48. data/lib/google/protobuf/repeated_field.rb +3 -26
  49. data/lib/google/protobuf/source_context_pb.rb +24 -4
  50. data/lib/google/protobuf/struct_pb.rb +24 -20
  51. data/lib/google/protobuf/timestamp_pb.rb +24 -5
  52. data/lib/google/protobuf/type_pb.rb +26 -68
  53. data/lib/google/protobuf/well_known_types.rb +5 -34
  54. data/lib/google/protobuf/wrappers_pb.rb +24 -28
  55. data/lib/google/protobuf.rb +27 -45
  56. data/lib/google/protobuf_ffi.rb +50 -0
  57. data/lib/google/protobuf_native.rb +20 -0
  58. data/lib/google/tasks/ffi.rake +102 -0
  59. metadata +72 -4
@@ -1,32 +1,9 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2014 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #include "message.h"
32
9
 
@@ -35,6 +12,7 @@
35
12
  #include "map.h"
36
13
  #include "protobuf.h"
37
14
  #include "repeated_field.h"
15
+ #include "shared_message.h"
38
16
 
39
17
  static VALUE cParseError = Qnil;
40
18
  static VALUE cAbstractMessage = Qnil;
@@ -53,6 +31,8 @@ VALUE MessageOrEnum_GetDescriptor(VALUE klass) {
53
31
  // -----------------------------------------------------------------------------
54
32
 
55
33
  typedef struct {
34
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
35
+ // macro to update VALUE references, as to trigger write barriers.
56
36
  VALUE arena;
57
37
  const upb_Message* msg; // Can get as mutable when non-frozen.
58
38
  const upb_MessageDef*
@@ -65,9 +45,9 @@ static void Message_mark(void* _self) {
65
45
  }
66
46
 
67
47
  static rb_data_type_t Message_type = {
68
- "Message",
48
+ "Google::Protobuf::Message",
69
49
  {Message_mark, RUBY_DEFAULT_FREE, NULL},
70
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
50
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
71
51
  };
72
52
 
73
53
  static Message* ruby_to_Message(VALUE msg_rb) {
@@ -105,8 +85,10 @@ upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
105
85
  void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
106
86
  Message* self = ruby_to_Message(self_);
107
87
  self->msg = msg;
108
- self->arena = arena;
109
- ObjectCache_Add(msg, self_);
88
+ RB_OBJ_WRITE(self_, &self->arena, arena);
89
+ VALUE stored = ObjectCache_TryAdd(msg, self_);
90
+ (void)stored;
91
+ PBRUBY_ASSERT(stored == self_);
110
92
  }
111
93
 
112
94
  VALUE Message_GetArena(VALUE msg_rb) {
@@ -680,8 +662,8 @@ static VALUE Message_dup(VALUE _self) {
680
662
  Message* new_msg_self = ruby_to_Message(new_msg);
681
663
  size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
682
664
 
683
- // TODO(copy unknown fields?)
684
- // TODO(use official upb msg copy function)
665
+ // TODO
666
+ // TODO
685
667
  memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
686
668
  Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
687
669
  return new_msg;
@@ -690,29 +672,13 @@ static VALUE Message_dup(VALUE _self) {
690
672
  // Support function for Message_eq, and also used by other #eq functions.
691
673
  bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
692
674
  const upb_MessageDef* m) {
693
- if (m1 == m2) return true;
694
-
695
- size_t size1, size2;
696
- int encode_opts =
697
- kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic;
698
- upb_Arena* arena_tmp = upb_Arena_New();
699
- const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
700
-
701
- // Compare deterministically serialized payloads with no unknown fields.
702
- char* data1;
703
- char* data2;
704
- upb_EncodeStatus status1 =
705
- upb_Encode(m1, layout, encode_opts, arena_tmp, &data1, &size1);
706
- upb_EncodeStatus status2 =
707
- upb_Encode(m2, layout, encode_opts, arena_tmp, &data2, &size2);
708
-
709
- if (status1 == kUpb_EncodeStatus_Ok && status2 == kUpb_EncodeStatus_Ok) {
710
- bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0);
711
- upb_Arena_Free(arena_tmp);
712
- return ret;
675
+ upb_Status status;
676
+ upb_Status_Clear(&status);
677
+ bool return_value = shared_Message_Equal(m1, m2, m, &status);
678
+ if (upb_Status_IsOk(&status)) {
679
+ return return_value;
713
680
  } else {
714
- upb_Arena_Free(arena_tmp);
715
- rb_raise(cParseError, "Error comparing messages");
681
+ rb_raise(cParseError, upb_Status_ErrorMessage(&status));
716
682
  }
717
683
  }
718
684
 
@@ -737,23 +703,13 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
737
703
 
738
704
  uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
739
705
  uint64_t seed) {
740
- upb_Arena* arena = upb_Arena_New();
741
- char* data;
742
- size_t size;
743
-
744
- // Hash a deterministically serialized payloads with no unknown fields.
745
- upb_EncodeStatus status = upb_Encode(
746
- msg, upb_MessageDef_MiniTable(m),
747
- kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic, arena,
748
- &data, &size);
749
-
750
- if (status == kUpb_EncodeStatus_Ok) {
751
- uint64_t ret = _upb_Hash(data, size, seed);
752
- upb_Arena_Free(arena);
753
- return ret;
706
+ upb_Status status;
707
+ upb_Status_Clear(&status);
708
+ uint64_t return_value = shared_Message_Hash(msg, m, seed, &status);
709
+ if (upb_Status_IsOk(&status)) {
710
+ return return_value;
754
711
  } else {
755
- upb_Arena_Free(arena);
756
- rb_raise(cParseError, "Error calculating hash");
712
+ rb_raise(cParseError, upb_Status_ErrorMessage(&status));
757
713
  }
758
714
  }
759
715
 
@@ -978,7 +934,7 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
978
934
  rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
979
935
 
980
936
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
981
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
937
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
982
938
  }
983
939
  }
984
940
 
@@ -1018,7 +974,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1018
974
  int options = 0;
1019
975
  upb_Status status;
1020
976
 
1021
- // TODO(haberman): use this message's pool instead.
977
+ // TODO: use this message's pool instead.
1022
978
  const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1023
979
 
1024
980
  if (argc < 1 || argc > 2) {
@@ -1041,7 +997,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1041
997
  rb_raise(rb_eArgError, "Expected string for JSON data.");
1042
998
  }
1043
999
 
1044
- // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
1000
+ // TODO: Check and respect string encoding. If not UTF-8, we need to
1045
1001
  // convert, because string handlers pass data directly to message string
1046
1002
  // fields.
1047
1003
 
@@ -1096,7 +1052,7 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1096
1052
  rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1097
1053
 
1098
1054
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
1099
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
1055
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
1100
1056
  }
1101
1057
  }
1102
1058
 
@@ -1134,7 +1090,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1134
1090
  size_t size;
1135
1091
  upb_Status status;
1136
1092
 
1137
- // TODO(haberman): use this message's pool instead.
1093
+ // TODO: use this message's pool instead.
1138
1094
  const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1139
1095
 
1140
1096
  if (argc < 1 || argc > 2) {
@@ -1162,6 +1118,12 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1162
1118
  Qfalse))) {
1163
1119
  options |= upb_JsonEncode_EmitDefaults;
1164
1120
  }
1121
+
1122
+ if (RTEST(rb_hash_lookup2(hash_args,
1123
+ ID2SYM(rb_intern("format_enums_as_integers")),
1124
+ Qfalse))) {
1125
+ options |= upb_JsonEncode_FormatEnumsAsIntegers;
1126
+ }
1165
1127
  }
1166
1128
 
1167
1129
  upb_Status_Clear(&status);
@@ -1,38 +1,13 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2008 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #ifndef RUBY_PROTOBUF_MESSAGE_H_
32
9
  #define RUBY_PROTOBUF_MESSAGE_H_
33
10
 
34
- #include <ruby/ruby.h>
35
-
36
11
  #include "protobuf.h"
37
12
  #include "ruby-upb.h"
38
13
 
@@ -1,32 +1,9 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2014 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #include "protobuf.h"
32
9
 
@@ -171,6 +148,8 @@ void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val,
171
148
 
172
149
  typedef struct {
173
150
  upb_Arena *arena;
151
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
152
+ // macro to update VALUE references, as to trigger write barriers.
174
153
  VALUE pinned_objs;
175
154
  } Arena;
176
155
 
@@ -190,10 +169,11 @@ static VALUE cArena;
190
169
  const rb_data_type_t Arena_type = {
191
170
  "Google::Protobuf::Internal::Arena",
192
171
  {Arena_mark, Arena_free, NULL},
193
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
172
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
194
173
  };
195
174
 
196
- static void* ruby_upb_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, size_t size) {
175
+ static void *ruby_upb_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
176
+ size_t size) {
197
177
  if (size == 0) {
198
178
  xfree(ptr);
199
179
  return NULL;
@@ -233,7 +213,7 @@ void Arena_Pin(VALUE _arena, VALUE obj) {
233
213
  Arena *arena;
234
214
  TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
235
215
  if (arena->pinned_objs == Qnil) {
236
- arena->pinned_objs = rb_ary_new();
216
+ RB_OBJ_WRITE(_arena, &arena->pinned_objs, rb_ary_new());
237
217
  }
238
218
  rb_ary_push(arena->pinned_objs, obj);
239
219
  }
@@ -250,164 +230,48 @@ void Arena_register(VALUE module) {
250
230
  // Object Cache
251
231
  // -----------------------------------------------------------------------------
252
232
 
253
- // A pointer -> Ruby Object cache that keeps references to Ruby wrapper
254
- // objects. This allows us to look up any Ruby wrapper object by the address
255
- // of the object it is wrapping. That way we can avoid ever creating two
256
- // different wrapper objects for the same C object, which saves memory and
257
- // preserves object identity.
258
- //
259
- // We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
260
- // to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
261
- // keys.
262
- //
263
- // We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
264
- // means it may not be possible to fit a pointer into a Fixnum. Keys are
265
- // pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
266
- // they overflow and require allocating a Bignum, they could get collected
267
- // prematurely, thus removing the cache entry. This happens on 64-bit Windows,
268
- // on which pointers are 64 bits but longs are 32 bits. In this case, we enable
269
- // the secondary Hash to hold the keys and prevent them from being collected.
270
-
271
- #if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
272
- #define USE_SECONDARY_MAP 0
273
- #else
274
- #define USE_SECONDARY_MAP 1
275
- #endif
276
-
277
- #if USE_SECONDARY_MAP
278
-
279
- // Maps Numeric -> Object. The object is then used as a key into the WeakMap.
280
- // This is needed for Ruby <2.7 where a number cannot be a key to WeakMap.
281
- // The object is used only for its identity; it does not contain any data.
282
- VALUE secondary_map = Qnil;
283
-
284
- // Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
285
- // iterates over the map which cannot happen in parallel with insertions, or
286
- // Ruby will throw:
287
- // can't add a new key into hash during iteration (RuntimeError)
288
- VALUE secondary_map_mutex = Qnil;
289
-
290
- // Lambda that will GC entries from the secondary map that are no longer present
291
- // in the primary map.
292
- VALUE gc_secondary_map_lambda = Qnil;
293
- ID length;
294
-
295
- extern VALUE weak_obj_cache;
296
-
297
- static void SecondaryMap_Init() {
298
- rb_gc_register_address(&secondary_map);
299
- rb_gc_register_address(&gc_secondary_map_lambda);
300
- rb_gc_register_address(&secondary_map_mutex);
301
- secondary_map = rb_hash_new();
302
- gc_secondary_map_lambda = rb_eval_string(
303
- "->(secondary, weak) {\n"
304
- " secondary.delete_if { |k, v| !weak.key?(v) }\n"
305
- "}\n");
306
- secondary_map_mutex = rb_mutex_new();
307
- length = rb_intern("length");
308
- }
309
-
310
- // The secondary map is a regular Hash, and will never shrink on its own.
311
- // The main object cache is a WeakMap that will automatically remove entries
312
- // when the target object is no longer reachable, but unless we manually
313
- // remove the corresponding entries from the secondary map, it will grow
314
- // without bound.
315
- //
316
- // To avoid this unbounded growth we periodically remove entries from the
317
- // secondary map that are no longer present in the WeakMap. The logic of
318
- // how often to perform this GC is an artbirary tuning parameter that
319
- // represents a straightforward CPU/memory tradeoff.
320
- //
321
- // Requires: secondary_map_mutex is held.
322
- static void SecondaryMap_MaybeGC() {
323
- PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
324
- size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
325
- size_t secondary_len = RHASH_SIZE(secondary_map);
326
- if (secondary_len < weak_len) {
327
- // Logically this case should not be possible: a valid entry cannot exist in
328
- // the weak table unless there is a corresponding entry in the secondary
329
- // table. It should *always* be the case that secondary_len >= weak_len.
330
- //
331
- // However ObjectSpace::WeakMap#length (and therefore weak_len) is
332
- // unreliable: it overreports its true length by including non-live objects.
333
- // However these non-live objects are not yielded in iteration, so we may
334
- // have previously deleted them from the secondary map in a previous
335
- // invocation of SecondaryMap_MaybeGC().
336
- //
337
- // In this case, we can't measure any waste, so we just return.
338
- return;
339
- }
340
- size_t waste = secondary_len - weak_len;
341
- // GC if we could remove at least 2000 entries or 20% of the table size
342
- // (whichever is greater). Since the cost of the GC pass is O(N), we
343
- // want to make sure that we condition this on overall table size, to
344
- // avoid O(N^2) CPU costs.
345
- size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
346
- if (waste > threshold) {
347
- rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2, secondary_map,
348
- weak_obj_cache);
349
- }
350
- }
351
-
352
- // Requires: secondary_map_mutex is held by this thread iff create == true.
353
- static VALUE SecondaryMap_Get(VALUE key, bool create) {
354
- PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
355
- VALUE ret = rb_hash_lookup(secondary_map, key);
356
- if (ret == Qnil && create) {
357
- SecondaryMap_MaybeGC();
358
- ret = rb_class_new_instance(0, NULL, rb_cObject);
359
- rb_hash_aset(secondary_map, key, ret);
360
- }
361
- return ret;
362
- }
363
-
364
- #endif
365
-
366
- // Requires: secondary_map_mutex is held by this thread iff create == true.
367
- static VALUE ObjectCache_GetKey(const void *key, bool create) {
368
- VALUE key_val = (VALUE)key;
369
- PBRUBY_ASSERT((key_val & 3) == 0);
370
- VALUE ret = LL2NUM(key_val >> 2);
371
- #if USE_SECONDARY_MAP
372
- ret = SecondaryMap_Get(ret, create);
373
- #endif
374
- return ret;
375
- }
376
-
377
233
  // Public ObjectCache API.
378
234
 
379
235
  VALUE weak_obj_cache = Qnil;
380
236
  ID item_get;
381
- ID item_set;
237
+ ID item_try_add;
238
+
239
+ static void ObjectCache_Init(VALUE protobuf) {
240
+ item_get = rb_intern("get");
241
+ item_try_add = rb_intern("try_add");
382
242
 
383
- static void ObjectCache_Init() {
384
243
  rb_gc_register_address(&weak_obj_cache);
385
- VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
386
- weak_obj_cache = rb_class_new_instance(0, NULL, klass);
387
- item_get = rb_intern("[]");
388
- item_set = rb_intern("[]=");
389
- #if USE_SECONDARY_MAP
390
- SecondaryMap_Init();
244
+ #if SIZEOF_LONG >= SIZEOF_VALUE
245
+ VALUE cache_class = rb_const_get(protobuf, rb_intern("ObjectCache"));
246
+ #else
247
+ VALUE cache_class = rb_const_get(protobuf, rb_intern("LegacyObjectCache"));
391
248
  #endif
249
+
250
+ weak_obj_cache = rb_class_new_instance(0, NULL, cache_class);
251
+ rb_const_set(protobuf, rb_intern("OBJECT_CACHE"), weak_obj_cache);
252
+ rb_const_set(protobuf, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG));
253
+ rb_const_set(protobuf, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE));
392
254
  }
393
255
 
394
- void ObjectCache_Add(const void *key, VALUE val) {
395
- PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
396
- #if USE_SECONDARY_MAP
397
- rb_mutex_lock(secondary_map_mutex);
398
- #endif
399
- VALUE key_rb = ObjectCache_GetKey(key, true);
400
- rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
401
- #if USE_SECONDARY_MAP
402
- rb_mutex_unlock(secondary_map_mutex);
403
- #endif
404
- PBRUBY_ASSERT(ObjectCache_Get(key) == val);
256
+ static VALUE ObjectCache_GetKey(const void *key) {
257
+ VALUE key_val = (VALUE)key;
258
+ PBRUBY_ASSERT((key_val & 3) == 0);
259
+ // Ensure the key can be stored as a Fixnum since 1 bit is needed for
260
+ // FIXNUM_FLAG and 1 bit is needed for the sign bit.
261
+ VALUE new_key = LL2NUM(key_val >> 2);
262
+ PBRUBY_ASSERT(FIXNUM_P(new_key));
263
+ return new_key;
264
+ }
265
+
266
+ VALUE ObjectCache_TryAdd(const void *key, VALUE val) {
267
+ VALUE key_val = ObjectCache_GetKey(key);
268
+ return rb_funcall(weak_obj_cache, item_try_add, 2, key_val, val);
405
269
  }
406
270
 
407
271
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
408
272
  VALUE ObjectCache_Get(const void *key) {
409
- VALUE key_rb = ObjectCache_GetKey(key, false);
410
- return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
273
+ VALUE key_val = ObjectCache_GetKey(key);
274
+ return rb_funcall(weak_obj_cache, item_get, 1, key_val);
411
275
  }
412
276
 
413
277
  /*
@@ -457,11 +321,10 @@ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
457
321
  // This must be named "Init_protobuf_c" because the Ruby module is named
458
322
  // "protobuf_c" -- the VM looks for this symbol in our .so.
459
323
  __attribute__((visibility("default"))) void Init_protobuf_c() {
460
- ObjectCache_Init();
461
-
462
324
  VALUE google = rb_define_module("Google");
463
325
  VALUE protobuf = rb_define_module_under(google, "Protobuf");
464
326
 
327
+ ObjectCache_Init(protobuf);
465
328
  Arena_register(protobuf);
466
329
  Defs_register(protobuf);
467
330
  RepeatedField_register(protobuf);
@@ -1,38 +1,29 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2014 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
32
9
  #define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
33
10
 
11
+ // Ruby 3+ defines NDEBUG itself, see: https://bugs.ruby-lang.org/issues/18777
12
+ #ifdef NDEBUG
13
+ #include <ruby.h>
14
+ #else
15
+ #include <ruby.h>
16
+ #undef NDEBUG
17
+ #endif
18
+
19
+ #include <ruby/version.h>
20
+
21
+ #if RUBY_API_VERSION_CODE < 20700
22
+ #error Protobuf requires Ruby >= 2.7
23
+ #endif
24
+
25
+ #include <assert.h> // Must be included after the NDEBUG logic above.
34
26
  #include <ruby/encoding.h>
35
- #include <ruby/ruby.h>
36
27
  #include <ruby/vm.h>
37
28
 
38
29
  #include "defs.h"
@@ -76,10 +67,9 @@ void Arena_Pin(VALUE arena, VALUE obj);
76
67
  // being collected (though in Ruby <2.7 is it effectively strong, due to
77
68
  // implementation limitations).
78
69
 
79
- // Adds an entry to the cache. The "arena" parameter must give the arena that
80
- // "key" was allocated from. In Ruby <2.7.0, it will be used to remove the key
81
- // from the cache when the arena is destroyed.
82
- void ObjectCache_Add(const void* key, VALUE val);
70
+ // Tries to add a new entry to the cache, returning the newly installed value or
71
+ // the pre-existing entry.
72
+ VALUE ObjectCache_TryAdd(const void* key, VALUE val);
83
73
 
84
74
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
85
75
  VALUE ObjectCache_Get(const void* key);
@@ -110,7 +100,9 @@ extern VALUE cTypeError;
110
100
  do { \
111
101
  } while (false && (expr))
112
102
  #else
113
- #define PBRUBY_ASSERT(expr) assert(expr)
103
+ #define PBRUBY_ASSERT(expr) \
104
+ if (!(expr)) \
105
+ rb_bug("Assertion failed at %s:%d, expr: %s", __FILE__, __LINE__, #expr)
114
106
  #endif
115
107
 
116
108
  #define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))