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.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/Rakefile +3 -0
- data/ext/google/protobuf_c/convert.c +23 -70
- data/ext/google/protobuf_c/convert.h +3 -28
- data/ext/google/protobuf_c/defs.c +36 -48
- data/ext/google/protobuf_c/defs.h +3 -28
- data/ext/google/protobuf_c/extconf.rb +2 -1
- data/ext/google/protobuf_c/glue.c +21 -0
- data/ext/google/protobuf_c/map.c +7 -28
- data/ext/google/protobuf_c/map.h +3 -28
- data/ext/google/protobuf_c/message.c +37 -75
- data/ext/google/protobuf_c/message.h +3 -28
- data/ext/google/protobuf_c/protobuf.c +39 -176
- data/ext/google/protobuf_c/protobuf.h +24 -32
- data/ext/google/protobuf_c/repeated_field.c +9 -29
- data/ext/google/protobuf_c/repeated_field.h +3 -28
- data/ext/google/protobuf_c/ruby-upb.c +2982 -2494
- data/ext/google/protobuf_c/ruby-upb.h +5836 -3465
- data/ext/google/protobuf_c/shared_convert.c +64 -0
- data/ext/google/protobuf_c/shared_convert.h +26 -0
- data/ext/google/protobuf_c/shared_message.c +65 -0
- data/ext/google/protobuf_c/shared_message.h +25 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
- data/lib/google/protobuf/any_pb.rb +24 -5
- data/lib/google/protobuf/api_pb.rb +26 -23
- data/lib/google/protobuf/descriptor_pb.rb +40 -252
- data/lib/google/protobuf/duration_pb.rb +24 -5
- data/lib/google/protobuf/empty_pb.rb +24 -3
- data/lib/google/protobuf/ffi/descriptor.rb +154 -0
- data/lib/google/protobuf/ffi/descriptor_pool.rb +70 -0
- data/lib/google/protobuf/ffi/enum_descriptor.rb +161 -0
- data/lib/google/protobuf/ffi/ffi.rb +213 -0
- data/lib/google/protobuf/ffi/field_descriptor.rb +309 -0
- data/lib/google/protobuf/ffi/file_descriptor.rb +48 -0
- data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
- data/lib/google/protobuf/ffi/internal/convert.rb +305 -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 +396 -0
- data/lib/google/protobuf/ffi/message.rb +641 -0
- data/lib/google/protobuf/ffi/object_cache.rb +30 -0
- data/lib/google/protobuf/ffi/oneof_descriptor.rb +88 -0
- data/lib/google/protobuf/ffi/repeated_field.rb +503 -0
- data/lib/google/protobuf/field_mask_pb.rb +24 -4
- data/lib/google/protobuf/message_exts.rb +3 -26
- data/lib/google/protobuf/object_cache.rb +97 -0
- data/lib/google/protobuf/plugin_pb.rb +25 -28
- data/lib/google/protobuf/repeated_field.rb +3 -26
- data/lib/google/protobuf/source_context_pb.rb +24 -4
- data/lib/google/protobuf/struct_pb.rb +24 -20
- data/lib/google/protobuf/timestamp_pb.rb +24 -5
- data/lib/google/protobuf/type_pb.rb +26 -68
- data/lib/google/protobuf/well_known_types.rb +5 -34
- data/lib/google/protobuf/wrappers_pb.rb +24 -28
- data/lib/google/protobuf.rb +27 -45
- data/lib/google/protobuf_ffi.rb +50 -0
- data/lib/google/protobuf_native.rb +20 -0
- data/lib/google/tasks/ffi.rake +102 -0
- 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
|
-
//
|
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 "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
|
109
|
-
|
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
|
684
|
-
// TODO
|
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
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
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
|
-
|
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
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
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
|
-
|
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 |=
|
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
|
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
|
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 |=
|
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
|
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
|
-
//
|
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
|
|
@@ -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 "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*
|
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
|
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
|
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
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
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
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
VALUE
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
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
|
410
|
-
return rb_funcall(weak_obj_cache, item_get, 1,
|
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
|
-
//
|
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"
|
@@ -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
|
-
//
|
80
|
-
//
|
81
|
-
|
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)
|
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))
|