google-protobuf 3.21.2 → 4.29.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/Rakefile +3 -0
- data/ext/google/protobuf_c/convert.c +67 -86
- data/ext/google/protobuf_c/convert.h +3 -28
- data/ext/google/protobuf_c/defs.c +538 -77
- data/ext/google/protobuf_c/defs.h +3 -28
- data/ext/google/protobuf_c/extconf.rb +4 -4
- data/ext/google/protobuf_c/glue.c +72 -0
- data/ext/google/protobuf_c/map.c +114 -85
- data/ext/google/protobuf_c/map.h +12 -30
- data/ext/google/protobuf_c/message.c +264 -238
- data/ext/google/protobuf_c/message.h +11 -33
- data/ext/google/protobuf_c/protobuf.c +63 -187
- data/ext/google/protobuf_c/protobuf.h +27 -39
- data/ext/google/protobuf_c/repeated_field.c +72 -38
- data/ext/google/protobuf_c/repeated_field.h +11 -29
- data/ext/google/protobuf_c/ruby-upb.c +13783 -8236
- data/ext/google/protobuf_c/ruby-upb.h +14077 -4495
- data/ext/google/protobuf_c/shared_convert.c +69 -0
- data/ext/google/protobuf_c/shared_convert.h +26 -0
- data/ext/google/protobuf_c/shared_message.c +37 -0
- data/ext/google/protobuf_c/shared_message.h +21 -0
- data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +1 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +20 -7
- data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
- data/lib/google/protobuf/any_pb.rb +6 -8
- data/lib/google/protobuf/api_pb.rb +6 -26
- data/lib/google/protobuf/descriptor_pb.rb +23 -226
- data/lib/google/protobuf/duration_pb.rb +6 -8
- data/lib/google/protobuf/empty_pb.rb +6 -6
- data/lib/google/protobuf/ffi/descriptor.rb +165 -0
- data/lib/google/protobuf/ffi/descriptor_pool.rb +77 -0
- data/lib/google/protobuf/ffi/enum_descriptor.rb +173 -0
- data/lib/google/protobuf/ffi/ffi.rb +215 -0
- data/lib/google/protobuf/ffi/field_descriptor.rb +330 -0
- data/lib/google/protobuf/ffi/file_descriptor.rb +49 -0
- data/lib/google/protobuf/ffi/internal/arena.rb +60 -0
- data/lib/google/protobuf/ffi/internal/convert.rb +296 -0
- data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
- data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
- data/lib/google/protobuf/ffi/map.rb +433 -0
- data/lib/google/protobuf/ffi/message.rb +785 -0
- data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
- data/lib/google/protobuf/ffi/object_cache.rb +30 -0
- data/lib/google/protobuf/ffi/oneof_descriptor.rb +97 -0
- data/lib/google/protobuf/ffi/repeated_field.rb +411 -0
- data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
- data/lib/google/protobuf/field_mask_pb.rb +6 -7
- data/lib/google/protobuf/internal/object_cache.rb +99 -0
- data/lib/google/protobuf/message_exts.rb +8 -26
- data/lib/google/protobuf/plugin_pb.rb +25 -0
- data/lib/google/protobuf/repeated_field.rb +7 -31
- data/lib/google/protobuf/source_context_pb.rb +6 -7
- data/lib/google/protobuf/struct_pb.rb +6 -23
- data/lib/google/protobuf/timestamp_pb.rb +6 -8
- data/lib/google/protobuf/type_pb.rb +6 -71
- data/lib/google/protobuf/well_known_types.rb +5 -34
- data/lib/google/protobuf/wrappers_pb.rb +6 -31
- data/lib/google/protobuf.rb +27 -45
- data/lib/google/protobuf_ffi.rb +51 -0
- data/lib/google/protobuf_native.rb +19 -0
- data/lib/google/tasks/ffi.rake +100 -0
- metadata +92 -16
- data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
- data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
- data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
- data/lib/google/protobuf/descriptor_dsl.rb +0 -465
- data/tests/basic.rb +0 -739
- data/tests/generated_code_test.rb +0 -23
- data/tests/stress.rb +0 -38
@@ -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
|
-
//
|
6
|
-
//
|
7
|
-
//
|
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
|
|
@@ -61,7 +36,7 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
|
|
61
36
|
|
62
37
|
// Gets or constructs a Ruby wrapper object for the given message. The wrapper
|
63
38
|
// object will reference |arena| and ensure that it outlives this object.
|
64
|
-
VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
|
39
|
+
VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
|
65
40
|
VALUE arena);
|
66
41
|
|
67
42
|
// Gets the given field from this message.
|
@@ -79,10 +54,6 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
|
|
79
54
|
upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
|
80
55
|
upb_Arena* arena);
|
81
56
|
|
82
|
-
// Returns true if these two messages are equal.
|
83
|
-
bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
|
84
|
-
const upb_MessageDef* m);
|
85
|
-
|
86
57
|
// Checks that this Ruby object is a message, and raises an exception if not.
|
87
58
|
void Message_CheckClass(VALUE klass);
|
88
59
|
|
@@ -98,6 +69,13 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc);
|
|
98
69
|
// module.
|
99
70
|
VALUE MessageOrEnum_GetDescriptor(VALUE klass);
|
100
71
|
|
72
|
+
// Decodes a Message from a byte sequence.
|
73
|
+
VALUE Message_decode_bytes(int size, const char* bytes, int options,
|
74
|
+
VALUE klass, bool freeze);
|
75
|
+
|
76
|
+
// Recursively freeze message
|
77
|
+
VALUE Message_freeze(VALUE _self);
|
78
|
+
|
101
79
|
// Call at startup to register all types in this module.
|
102
80
|
void Message_register(VALUE protobuf);
|
103
81
|
|
@@ -1,37 +1,12 @@
|
|
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
|
-
//
|
6
|
-
//
|
7
|
-
//
|
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
|
|
33
|
-
#include <ruby/version.h>
|
34
|
-
|
35
10
|
#include "defs.h"
|
36
11
|
#include "map.h"
|
37
12
|
#include "message.h"
|
@@ -171,6 +146,8 @@ void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val,
|
|
171
146
|
|
172
147
|
typedef struct {
|
173
148
|
upb_Arena *arena;
|
149
|
+
// IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
|
150
|
+
// macro to update VALUE references, as to trigger write barriers.
|
174
151
|
VALUE pinned_objs;
|
175
152
|
} Arena;
|
176
153
|
|
@@ -185,15 +162,28 @@ static void Arena_free(void *data) {
|
|
185
162
|
xfree(arena);
|
186
163
|
}
|
187
164
|
|
165
|
+
static size_t Arena_memsize(const void *data) {
|
166
|
+
const Arena *arena = data;
|
167
|
+
size_t fused_count;
|
168
|
+
size_t memsize = upb_Arena_SpaceAllocated(arena->arena, &fused_count);
|
169
|
+
if (fused_count > 1) {
|
170
|
+
// If other arena were fused we attribute an equal
|
171
|
+
// share of memory usage to each one.
|
172
|
+
memsize /= fused_count;
|
173
|
+
}
|
174
|
+
return memsize + sizeof(Arena);
|
175
|
+
}
|
176
|
+
|
188
177
|
static VALUE cArena;
|
189
178
|
|
190
179
|
const rb_data_type_t Arena_type = {
|
191
180
|
"Google::Protobuf::Internal::Arena",
|
192
|
-
{Arena_mark, Arena_free,
|
193
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
181
|
+
{Arena_mark, Arena_free, Arena_memsize},
|
182
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
194
183
|
};
|
195
184
|
|
196
|
-
static void*
|
185
|
+
static void *ruby_upb_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
|
186
|
+
size_t size) {
|
197
187
|
if (size == 0) {
|
198
188
|
xfree(ptr);
|
199
189
|
return NULL;
|
@@ -229,15 +219,6 @@ void Arena_fuse(VALUE _arena, upb_Arena *other) {
|
|
229
219
|
|
230
220
|
VALUE Arena_new() { return Arena_alloc(cArena); }
|
231
221
|
|
232
|
-
void Arena_Pin(VALUE _arena, VALUE obj) {
|
233
|
-
Arena *arena;
|
234
|
-
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
235
|
-
if (arena->pinned_objs == Qnil) {
|
236
|
-
arena->pinned_objs = rb_ary_new();
|
237
|
-
}
|
238
|
-
rb_ary_push(arena->pinned_objs, obj);
|
239
|
-
}
|
240
|
-
|
241
222
|
void Arena_register(VALUE module) {
|
242
223
|
VALUE internal = rb_define_module_under(module, "Internal");
|
243
224
|
VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject);
|
@@ -250,164 +231,49 @@ void Arena_register(VALUE module) {
|
|
250
231
|
// Object Cache
|
251
232
|
// -----------------------------------------------------------------------------
|
252
233
|
|
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
234
|
// Public ObjectCache API.
|
378
235
|
|
379
236
|
VALUE weak_obj_cache = Qnil;
|
380
237
|
ID item_get;
|
381
|
-
ID
|
238
|
+
ID item_try_add;
|
239
|
+
|
240
|
+
static void ObjectCache_Init(VALUE protobuf) {
|
241
|
+
item_get = rb_intern("get");
|
242
|
+
item_try_add = rb_intern("try_add");
|
382
243
|
|
383
|
-
static void ObjectCache_Init() {
|
384
244
|
rb_gc_register_address(&weak_obj_cache);
|
385
|
-
VALUE
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
SecondaryMap_Init();
|
245
|
+
VALUE internal = rb_const_get(protobuf, rb_intern("Internal"));
|
246
|
+
#if SIZEOF_LONG >= SIZEOF_VALUE
|
247
|
+
VALUE cache_class = rb_const_get(internal, rb_intern("ObjectCache"));
|
248
|
+
#else
|
249
|
+
VALUE cache_class = rb_const_get(internal, rb_intern("LegacyObjectCache"));
|
391
250
|
#endif
|
251
|
+
|
252
|
+
weak_obj_cache = rb_class_new_instance(0, NULL, cache_class);
|
253
|
+
rb_const_set(internal, rb_intern("OBJECT_CACHE"), weak_obj_cache);
|
254
|
+
rb_const_set(internal, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG));
|
255
|
+
rb_const_set(internal, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE));
|
392
256
|
}
|
393
257
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
VALUE
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
258
|
+
static VALUE ObjectCache_GetKey(const void *key) {
|
259
|
+
VALUE key_val = (VALUE)key;
|
260
|
+
PBRUBY_ASSERT((key_val & 3) == 0);
|
261
|
+
// Ensure the key can be stored as a Fixnum since 1 bit is needed for
|
262
|
+
// FIXNUM_FLAG and 1 bit is needed for the sign bit.
|
263
|
+
VALUE new_key = LL2NUM(key_val >> 2);
|
264
|
+
PBRUBY_ASSERT(FIXNUM_P(new_key));
|
265
|
+
return new_key;
|
266
|
+
}
|
267
|
+
|
268
|
+
VALUE ObjectCache_TryAdd(const void *key, VALUE val) {
|
269
|
+
VALUE key_val = ObjectCache_GetKey(key);
|
270
|
+
return rb_funcall(weak_obj_cache, item_try_add, 2, key_val, val);
|
405
271
|
}
|
406
272
|
|
407
273
|
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
408
274
|
VALUE ObjectCache_Get(const void *key) {
|
409
|
-
VALUE
|
410
|
-
return rb_funcall(weak_obj_cache, item_get, 1,
|
275
|
+
VALUE key_val = ObjectCache_GetKey(key);
|
276
|
+
return rb_funcall(weak_obj_cache, item_get, 1, key_val);
|
411
277
|
}
|
412
278
|
|
413
279
|
/*
|
@@ -457,11 +323,10 @@ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
|
|
457
323
|
// This must be named "Init_protobuf_c" because the Ruby module is named
|
458
324
|
// "protobuf_c" -- the VM looks for this symbol in our .so.
|
459
325
|
__attribute__((visibility("default"))) void Init_protobuf_c() {
|
460
|
-
ObjectCache_Init();
|
461
|
-
|
462
326
|
VALUE google = rb_define_module("Google");
|
463
327
|
VALUE protobuf = rb_define_module_under(google, "Protobuf");
|
464
328
|
|
329
|
+
ObjectCache_Init(protobuf);
|
465
330
|
Arena_register(protobuf);
|
466
331
|
Defs_register(protobuf);
|
467
332
|
RepeatedField_register(protobuf);
|
@@ -478,3 +343,14 @@ __attribute__((visibility("default"))) void Init_protobuf_c() {
|
|
478
343
|
rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy,
|
479
344
|
1);
|
480
345
|
}
|
346
|
+
|
347
|
+
// -----------------------------------------------------------------------------
|
348
|
+
// Utilities
|
349
|
+
// -----------------------------------------------------------------------------
|
350
|
+
|
351
|
+
// Raises a Ruby error if val is frozen in Ruby or UPB.
|
352
|
+
void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen) {
|
353
|
+
if (RB_UNLIKELY(rb_obj_frozen_p(val)||upb_frozen)) {
|
354
|
+
rb_error_frozen_object(val);
|
355
|
+
}
|
356
|
+
}
|
@@ -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
|
-
//
|
6
|
-
//
|
7
|
-
//
|
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"
|
@@ -59,13 +50,6 @@ upb_Arena* Arena_get(VALUE arena);
|
|
59
50
|
// possible.
|
60
51
|
void Arena_fuse(VALUE arena, upb_Arena* other);
|
61
52
|
|
62
|
-
// Pins this Ruby object to the lifetime of this arena, so that as long as the
|
63
|
-
// arena is alive this object will not be collected.
|
64
|
-
//
|
65
|
-
// We use this to guarantee that the "frozen" bit on the object will be
|
66
|
-
// remembered, even if the user drops their reference to this precise object.
|
67
|
-
void Arena_Pin(VALUE arena, VALUE obj);
|
68
|
-
|
69
53
|
// -----------------------------------------------------------------------------
|
70
54
|
// ObjectCache
|
71
55
|
// -----------------------------------------------------------------------------
|
@@ -76,10 +60,9 @@ void Arena_Pin(VALUE arena, VALUE obj);
|
|
76
60
|
// being collected (though in Ruby <2.7 is it effectively strong, due to
|
77
61
|
// implementation limitations).
|
78
62
|
|
79
|
-
//
|
80
|
-
//
|
81
|
-
|
82
|
-
void ObjectCache_Add(const void* key, VALUE val);
|
63
|
+
// Tries to add a new entry to the cache, returning the newly installed value or
|
64
|
+
// the pre-existing entry.
|
65
|
+
VALUE ObjectCache_TryAdd(const void* key, VALUE val);
|
83
66
|
|
84
67
|
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
85
68
|
VALUE ObjectCache_Get(const void* key);
|
@@ -110,9 +93,14 @@ extern VALUE cTypeError;
|
|
110
93
|
do { \
|
111
94
|
} while (false && (expr))
|
112
95
|
#else
|
113
|
-
#define PBRUBY_ASSERT(expr)
|
96
|
+
#define PBRUBY_ASSERT(expr) \
|
97
|
+
if (!(expr)) \
|
98
|
+
rb_bug("Assertion failed at %s:%d, expr: %s", __FILE__, __LINE__, #expr)
|
114
99
|
#endif
|
115
100
|
|
101
|
+
// Raises a Ruby error if val is frozen in Ruby or upb_frozen is true.
|
102
|
+
void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen);
|
103
|
+
|
116
104
|
#define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))
|
117
105
|
|
118
106
|
#define UPB_UNUSED(var) (void)var
|
@@ -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
|
-
//
|
6
|
-
//
|
7
|
-
//
|
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 "repeated_field.h"
|
32
9
|
|
@@ -67,8 +44,9 @@ static RepeatedField* ruby_to_RepeatedField(VALUE _self) {
|
|
67
44
|
}
|
68
45
|
|
69
46
|
static upb_Array* RepeatedField_GetMutable(VALUE _self) {
|
70
|
-
|
71
|
-
|
47
|
+
const upb_Array* array = ruby_to_RepeatedField(_self)->array;
|
48
|
+
Protobuf_CheckNotFrozen(_self, upb_Array_IsFrozen(array));
|
49
|
+
return (upb_Array*)array;
|
72
50
|
}
|
73
51
|
|
74
52
|
VALUE RepeatedField_alloc(VALUE klass) {
|
@@ -79,15 +57,37 @@ VALUE RepeatedField_alloc(VALUE klass) {
|
|
79
57
|
return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
|
80
58
|
}
|
81
59
|
|
82
|
-
VALUE
|
60
|
+
VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f) {
|
61
|
+
PBRUBY_ASSERT(upb_FieldDef_IsRepeated(f));
|
62
|
+
VALUE val = ObjectCache_Get(f);
|
63
|
+
|
64
|
+
if (val == Qnil) {
|
65
|
+
val = RepeatedField_alloc(cRepeatedField);
|
66
|
+
RepeatedField* self;
|
67
|
+
TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
|
68
|
+
self->arena = Arena_new();
|
69
|
+
TypeInfo type_info = TypeInfo_get(f);
|
70
|
+
self->array = upb_Array_New(Arena_get(self->arena), type_info.type);
|
71
|
+
self->type_info = type_info;
|
72
|
+
if (self->type_info.type == kUpb_CType_Message) {
|
73
|
+
self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
|
74
|
+
}
|
75
|
+
val = ObjectCache_TryAdd(f, RepeatedField_freeze(val));
|
76
|
+
}
|
77
|
+
PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
|
78
|
+
PBRUBY_ASSERT(upb_Array_IsFrozen(ruby_to_RepeatedField(val)->array));
|
79
|
+
return val;
|
80
|
+
}
|
81
|
+
|
82
|
+
VALUE RepeatedField_GetRubyWrapper(const upb_Array* array, TypeInfo type_info,
|
83
83
|
VALUE arena) {
|
84
84
|
PBRUBY_ASSERT(array);
|
85
|
+
PBRUBY_ASSERT(arena != Qnil);
|
85
86
|
VALUE val = ObjectCache_Get(array);
|
86
87
|
|
87
88
|
if (val == Qnil) {
|
88
89
|
val = RepeatedField_alloc(cRepeatedField);
|
89
90
|
RepeatedField* self;
|
90
|
-
ObjectCache_Add(array, val);
|
91
91
|
TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
|
92
92
|
self->array = array;
|
93
93
|
self->arena = arena;
|
@@ -95,11 +95,13 @@ VALUE RepeatedField_GetRubyWrapper(upb_Array* array, TypeInfo type_info,
|
|
95
95
|
if (self->type_info.type == kUpb_CType_Message) {
|
96
96
|
self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
|
97
97
|
}
|
98
|
+
val = ObjectCache_TryAdd(array, val);
|
98
99
|
}
|
99
100
|
|
100
101
|
PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.type == type_info.type);
|
101
102
|
PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.def.msgdef ==
|
102
103
|
type_info.def.msgdef);
|
104
|
+
PBRUBY_ASSERT(ruby_to_RepeatedField(val)->array == array);
|
103
105
|
return val;
|
104
106
|
}
|
105
107
|
|
@@ -284,7 +286,7 @@ static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
|
|
284
286
|
memset(&fill, 0, sizeof(fill));
|
285
287
|
for (int i = size; i < index; i++) {
|
286
288
|
// Fill default values.
|
287
|
-
// TODO
|
289
|
+
// TODO: should this happen at the upb level?
|
288
290
|
upb_Array_Set(array, i, fill);
|
289
291
|
}
|
290
292
|
}
|
@@ -492,19 +494,49 @@ VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
|
|
492
494
|
return Qtrue;
|
493
495
|
}
|
494
496
|
|
497
|
+
/*
|
498
|
+
* call-seq:
|
499
|
+
* RepeatedField.frozen? => bool
|
500
|
+
*
|
501
|
+
* Returns true if the repeated field is frozen in either Ruby or the underlying
|
502
|
+
* representation. Freezes the Ruby repeated field object if it is not already
|
503
|
+
* frozen in Ruby but it is frozen in the underlying representation.
|
504
|
+
*/
|
505
|
+
VALUE RepeatedField_frozen(VALUE _self) {
|
506
|
+
RepeatedField* self = ruby_to_RepeatedField(_self);
|
507
|
+
if (!upb_Array_IsFrozen(self->array)) {
|
508
|
+
PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
|
509
|
+
return Qfalse;
|
510
|
+
}
|
511
|
+
|
512
|
+
// Lazily freeze the Ruby wrapper.
|
513
|
+
if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
|
514
|
+
return Qtrue;
|
515
|
+
}
|
516
|
+
|
495
517
|
/*
|
496
518
|
* call-seq:
|
497
519
|
* RepeatedField.freeze => self
|
498
520
|
*
|
499
|
-
* Freezes the repeated field. We have to intercept this so we can
|
500
|
-
*
|
521
|
+
* Freezes the repeated field object. We have to intercept this so we can freeze
|
522
|
+
* the underlying representation, not just the Ruby wrapper.
|
501
523
|
*/
|
502
|
-
|
524
|
+
VALUE RepeatedField_freeze(VALUE _self) {
|
503
525
|
RepeatedField* self = ruby_to_RepeatedField(_self);
|
504
|
-
if (
|
505
|
-
|
506
|
-
|
526
|
+
if (RB_OBJ_FROZEN(_self)) {
|
527
|
+
PBRUBY_ASSERT(upb_Array_IsFrozen(self->array));
|
528
|
+
return _self;
|
529
|
+
}
|
530
|
+
|
531
|
+
if (!upb_Array_IsFrozen(self->array)) {
|
532
|
+
if (self->type_info.type == kUpb_CType_Message) {
|
533
|
+
upb_Array_Freeze(RepeatedField_GetMutable(_self),
|
534
|
+
upb_MessageDef_MiniTable(self->type_info.def.msgdef));
|
535
|
+
} else {
|
536
|
+
upb_Array_Freeze(RepeatedField_GetMutable(_self), NULL);
|
537
|
+
}
|
507
538
|
}
|
539
|
+
RB_OBJ_FREEZE(_self);
|
508
540
|
return _self;
|
509
541
|
}
|
510
542
|
|
@@ -613,7 +645,8 @@ VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) {
|
|
613
645
|
|
614
646
|
self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary);
|
615
647
|
self->array = upb_Array_New(arena, self->type_info.type);
|
616
|
-
|
648
|
+
VALUE stored_val = ObjectCache_TryAdd(self->array, _self);
|
649
|
+
PBRUBY_ASSERT(stored_val == _self);
|
617
650
|
|
618
651
|
if (ary != Qnil) {
|
619
652
|
if (!RB_TYPE_P(ary, T_ARRAY)) {
|
@@ -650,6 +683,7 @@ void RepeatedField_register(VALUE module) {
|
|
650
683
|
rb_define_method(klass, "==", RepeatedField_eq, 1);
|
651
684
|
rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0);
|
652
685
|
rb_define_method(klass, "freeze", RepeatedField_freeze, 0);
|
686
|
+
rb_define_method(klass, "frozen?", RepeatedField_frozen, 0);
|
653
687
|
rb_define_method(klass, "hash", RepeatedField_hash, 0);
|
654
688
|
rb_define_method(klass, "+", RepeatedField_plus, 1);
|
655
689
|
rb_define_method(klass, "concat", RepeatedField_concat, 1);
|