google-protobuf 3.19.1 → 3.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +121 -155
- data/ext/google/protobuf_c/convert.h +15 -37
- data/ext/google/protobuf_c/defs.c +362 -243
- data/ext/google/protobuf_c/defs.h +22 -47
- data/ext/google/protobuf_c/extconf.rb +13 -5
- data/ext/google/protobuf_c/glue.c +56 -0
- data/ext/google/protobuf_c/map.c +129 -137
- data/ext/google/protobuf_c/map.h +13 -36
- data/ext/google/protobuf_c/message.c +486 -389
- data/ext/google/protobuf_c/message.h +32 -47
- data/ext/google/protobuf_c/protobuf.c +101 -228
- data/ext/google/protobuf_c/protobuf.h +37 -42
- data/ext/google/protobuf_c/repeated_field.c +110 -113
- data/ext/google/protobuf_c/repeated_field.h +12 -34
- data/ext/google/protobuf_c/ruby-upb.c +12236 -6993
- data/ext/google/protobuf_c/ruby-upb.h +12127 -3787
- 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/third_party/utf8_range/LICENSE +22 -0
- data/ext/google/protobuf_c/third_party/utf8_range/naive.c +92 -0
- data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +157 -0
- data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +170 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +21 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +7 -29
- data/lib/google/protobuf/any_pb.rb +24 -5
- data/lib/google/protobuf/api_pb.rb +26 -23
- data/lib/google/protobuf/descriptor_dsl.rb +8 -1
- data/lib/google/protobuf/descriptor_pb.rb +43 -225
- 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 +165 -0
- data/lib/google/protobuf/ffi/descriptor_pool.rb +75 -0
- data/lib/google/protobuf/ffi/enum_descriptor.rb +171 -0
- data/lib/google/protobuf/ffi/ffi.rb +213 -0
- data/lib/google/protobuf/ffi/field_descriptor.rb +319 -0
- data/lib/google/protobuf/ffi/file_descriptor.rb +59 -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 +407 -0
- data/lib/google/protobuf/ffi/message.rb +662 -0
- data/lib/google/protobuf/ffi/object_cache.rb +30 -0
- data/lib/google/protobuf/ffi/oneof_descriptor.rb +95 -0
- data/lib/google/protobuf/ffi/repeated_field.rb +383 -0
- data/lib/google/protobuf/field_mask_pb.rb +24 -4
- data/lib/google/protobuf/message_exts.rb +10 -28
- data/lib/google/protobuf/object_cache.rb +97 -0
- data/lib/google/protobuf/plugin_pb.rb +47 -0
- data/lib/google/protobuf/repeated_field.rb +18 -28
- 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 +16 -40
- data/lib/google/protobuf/wrappers_pb.rb +24 -28
- data/lib/google/protobuf.rb +32 -50
- 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 +82 -20
- data/tests/basic.rb +0 -640
- data/tests/generated_code_test.rb +0 -23
- data/tests/stress.rb +0 -38
@@ -1,90 +1,68 @@
|
|
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
|
|
39
|
-
// Gets the underlying
|
40
|
-
// wrapper. Requires that |value| is indeed a message object.
|
41
|
-
const
|
14
|
+
// Gets the underlying upb_Message* and upb_MessageDef for the given Ruby
|
15
|
+
// message wrapper. Requires that |value| is indeed a message object.
|
16
|
+
const upb_Message* Message_Get(VALUE value, const upb_MessageDef** m);
|
42
17
|
|
43
18
|
// Like Message_Get(), but checks that the object is not frozen and returns a
|
44
19
|
// mutable pointer.
|
45
|
-
|
20
|
+
upb_Message* Message_GetMutable(VALUE value, const upb_MessageDef** m);
|
46
21
|
|
47
22
|
// Returns the Arena object for this message.
|
48
23
|
VALUE Message_GetArena(VALUE value);
|
49
24
|
|
50
|
-
// Converts |value| into a
|
51
|
-
// raising an error if this is not possible. Used when assigning |value|
|
52
|
-
// field of another message, which means the message must be of a
|
53
|
-
// type.
|
25
|
+
// Converts |value| into a upb_Message value of the expected upb_MessageDef
|
26
|
+
// type, raising an error if this is not possible. Used when assigning |value|
|
27
|
+
// to a field of another message, which means the message must be of a
|
28
|
+
// particular type.
|
54
29
|
//
|
55
30
|
// This will perform automatic conversions in some cases (for example, Time ->
|
56
31
|
// Google::Protobuf::Timestamp). If any new message is created, it will be
|
57
32
|
// created on |arena|, and any existing message will have its arena fused with
|
58
33
|
// |arena|.
|
59
|
-
const
|
60
|
-
|
34
|
+
const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
|
35
|
+
const char* name, upb_Arena* arena);
|
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(
|
39
|
+
VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
|
40
|
+
VALUE arena);
|
65
41
|
|
66
42
|
// Gets the given field from this message.
|
67
|
-
VALUE Message_getfield(VALUE _self, const
|
43
|
+
VALUE Message_getfield(VALUE _self, const upb_FieldDef* f);
|
68
44
|
|
69
45
|
// Implements #inspect for this message, printing the text to |b|.
|
70
|
-
void Message_PrintMessage(StringBuilder* b, const
|
71
|
-
const
|
46
|
+
void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
|
47
|
+
const upb_MessageDef* m);
|
72
48
|
|
73
49
|
// Returns a hash value for the given message.
|
74
|
-
uint64_t Message_Hash(const
|
50
|
+
uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
|
51
|
+
uint64_t seed);
|
75
52
|
|
76
53
|
// Returns a deep copy of the given message.
|
77
|
-
|
78
|
-
|
54
|
+
upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
|
55
|
+
upb_Arena* arena);
|
79
56
|
|
80
57
|
// Returns true if these two messages are equal.
|
81
|
-
bool Message_Equal(const
|
58
|
+
bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
|
59
|
+
const upb_MessageDef* m);
|
82
60
|
|
83
61
|
// Checks that this Ruby object is a message, and raises an exception if not.
|
84
62
|
void Message_CheckClass(VALUE klass);
|
85
63
|
|
86
64
|
// Returns a new Hash object containing the contents of this message.
|
87
|
-
VALUE Scalar_CreateHash(
|
65
|
+
VALUE Scalar_CreateHash(upb_MessageValue val, TypeInfo type_info);
|
88
66
|
|
89
67
|
// Creates a message class or enum module for this descriptor, respectively.
|
90
68
|
VALUE build_class_from_descriptor(VALUE descriptor);
|
@@ -95,6 +73,13 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc);
|
|
95
73
|
// module.
|
96
74
|
VALUE MessageOrEnum_GetDescriptor(VALUE klass);
|
97
75
|
|
76
|
+
// Decodes a Message from a byte sequence.
|
77
|
+
VALUE Message_decode_bytes(int size, const char* bytes, int options,
|
78
|
+
VALUE klass, bool freeze);
|
79
|
+
|
80
|
+
// Recursively freeze message
|
81
|
+
VALUE Message_internal_deep_freeze(VALUE _self);
|
82
|
+
|
98
83
|
// Call at startup to register all types in this module.
|
99
84
|
void Message_register(VALUE protobuf);
|
100
85
|
|
@@ -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
|
|
@@ -40,14 +17,14 @@
|
|
40
17
|
VALUE cParseError;
|
41
18
|
VALUE cTypeError;
|
42
19
|
|
43
|
-
const
|
44
|
-
const
|
45
|
-
return
|
20
|
+
const upb_FieldDef *map_field_key(const upb_FieldDef *field) {
|
21
|
+
const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field);
|
22
|
+
return upb_MessageDef_FindFieldByNumber(entry, 1);
|
46
23
|
}
|
47
24
|
|
48
|
-
const
|
49
|
-
const
|
50
|
-
return
|
25
|
+
const upb_FieldDef *map_field_value(const upb_FieldDef *field) {
|
26
|
+
const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field);
|
27
|
+
return upb_MessageDef_FindFieldByNumber(entry, 2);
|
51
28
|
}
|
52
29
|
|
53
30
|
// -----------------------------------------------------------------------------
|
@@ -66,21 +43,21 @@ static size_t StringBuilder_SizeOf(size_t cap) {
|
|
66
43
|
return sizeof(StringBuilder) + cap;
|
67
44
|
}
|
68
45
|
|
69
|
-
StringBuilder*
|
46
|
+
StringBuilder *StringBuilder_New() {
|
70
47
|
const size_t cap = 128;
|
71
|
-
StringBuilder*
|
48
|
+
StringBuilder *builder = malloc(sizeof(*builder));
|
72
49
|
builder->size = 0;
|
73
50
|
builder->cap = cap;
|
74
51
|
builder->data = malloc(builder->cap);
|
75
52
|
return builder;
|
76
53
|
}
|
77
54
|
|
78
|
-
void StringBuilder_Free(StringBuilder*
|
55
|
+
void StringBuilder_Free(StringBuilder *b) {
|
79
56
|
free(b->data);
|
80
57
|
free(b);
|
81
58
|
}
|
82
59
|
|
83
|
-
void StringBuilder_Printf(StringBuilder*
|
60
|
+
void StringBuilder_Printf(StringBuilder *b, const char *fmt, ...) {
|
84
61
|
size_t have = b->cap - b->size;
|
85
62
|
size_t n;
|
86
63
|
va_list args;
|
@@ -104,60 +81,62 @@ void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...) {
|
|
104
81
|
b->size += n;
|
105
82
|
}
|
106
83
|
|
107
|
-
VALUE StringBuilder_ToRubyString(StringBuilder*
|
84
|
+
VALUE StringBuilder_ToRubyString(StringBuilder *b) {
|
108
85
|
VALUE ret = rb_str_new(b->data, b->size);
|
109
86
|
rb_enc_associate(ret, rb_utf8_encoding());
|
110
87
|
return ret;
|
111
88
|
}
|
112
89
|
|
113
|
-
static void StringBuilder_PrintEnum(StringBuilder*
|
114
|
-
const
|
115
|
-
const
|
116
|
-
if (
|
117
|
-
StringBuilder_Printf(b, ":%s",
|
90
|
+
static void StringBuilder_PrintEnum(StringBuilder *b, int32_t val,
|
91
|
+
const upb_EnumDef *e) {
|
92
|
+
const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(e, val);
|
93
|
+
if (ev) {
|
94
|
+
StringBuilder_Printf(b, ":%s", upb_EnumValueDef_Name(ev));
|
118
95
|
} else {
|
119
96
|
StringBuilder_Printf(b, "%" PRId32, val);
|
120
97
|
}
|
121
98
|
}
|
122
99
|
|
123
|
-
void StringBuilder_PrintMsgval(StringBuilder*
|
100
|
+
void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val,
|
124
101
|
TypeInfo info) {
|
125
102
|
switch (info.type) {
|
126
|
-
case
|
103
|
+
case kUpb_CType_Bool:
|
127
104
|
StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false");
|
128
105
|
break;
|
129
|
-
case
|
106
|
+
case kUpb_CType_Float: {
|
130
107
|
VALUE str = rb_inspect(DBL2NUM(val.float_val));
|
131
108
|
StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
|
132
109
|
break;
|
133
110
|
}
|
134
|
-
case
|
111
|
+
case kUpb_CType_Double: {
|
135
112
|
VALUE str = rb_inspect(DBL2NUM(val.double_val));
|
136
113
|
StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
|
137
114
|
break;
|
138
115
|
}
|
139
|
-
case
|
116
|
+
case kUpb_CType_Int32:
|
140
117
|
StringBuilder_Printf(b, "%" PRId32, val.int32_val);
|
141
118
|
break;
|
142
|
-
case
|
119
|
+
case kUpb_CType_UInt32:
|
143
120
|
StringBuilder_Printf(b, "%" PRIu32, val.uint32_val);
|
144
121
|
break;
|
145
|
-
case
|
122
|
+
case kUpb_CType_Int64:
|
146
123
|
StringBuilder_Printf(b, "%" PRId64, val.int64_val);
|
147
124
|
break;
|
148
|
-
case
|
125
|
+
case kUpb_CType_UInt64:
|
149
126
|
StringBuilder_Printf(b, "%" PRIu64, val.uint64_val);
|
150
127
|
break;
|
151
|
-
case
|
152
|
-
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
|
128
|
+
case kUpb_CType_String:
|
129
|
+
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
|
130
|
+
val.str_val.data);
|
153
131
|
break;
|
154
|
-
case
|
155
|
-
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
|
132
|
+
case kUpb_CType_Bytes:
|
133
|
+
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
|
134
|
+
val.str_val.data);
|
156
135
|
break;
|
157
|
-
case
|
136
|
+
case kUpb_CType_Enum:
|
158
137
|
StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef);
|
159
138
|
break;
|
160
|
-
case
|
139
|
+
case kUpb_CType_Message:
|
161
140
|
Message_PrintMessage(b, val.msg_val, info.def.msgdef);
|
162
141
|
break;
|
163
142
|
}
|
@@ -168,7 +147,9 @@ void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val,
|
|
168
147
|
// -----------------------------------------------------------------------------
|
169
148
|
|
170
149
|
typedef struct {
|
171
|
-
|
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.
|
172
153
|
VALUE pinned_objs;
|
173
154
|
} Arena;
|
174
155
|
|
@@ -179,50 +160,60 @@ static void Arena_mark(void *data) {
|
|
179
160
|
|
180
161
|
static void Arena_free(void *data) {
|
181
162
|
Arena *arena = data;
|
182
|
-
|
163
|
+
upb_Arena_Free(arena->arena);
|
183
164
|
xfree(arena);
|
184
165
|
}
|
185
166
|
|
186
167
|
static VALUE cArena;
|
187
168
|
|
188
169
|
const rb_data_type_t Arena_type = {
|
189
|
-
|
190
|
-
|
191
|
-
|
170
|
+
"Google::Protobuf::Internal::Arena",
|
171
|
+
{Arena_mark, Arena_free, NULL},
|
172
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
192
173
|
};
|
193
174
|
|
175
|
+
static void *ruby_upb_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
|
176
|
+
size_t size) {
|
177
|
+
if (size == 0) {
|
178
|
+
xfree(ptr);
|
179
|
+
return NULL;
|
180
|
+
} else {
|
181
|
+
return xrealloc(ptr, size);
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
upb_alloc ruby_upb_alloc = {&ruby_upb_allocfunc};
|
186
|
+
|
194
187
|
static VALUE Arena_alloc(VALUE klass) {
|
195
188
|
Arena *arena = ALLOC(Arena);
|
196
|
-
arena->arena =
|
189
|
+
arena->arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc);
|
197
190
|
arena->pinned_objs = Qnil;
|
198
191
|
return TypedData_Wrap_Struct(klass, &Arena_type, arena);
|
199
192
|
}
|
200
193
|
|
201
|
-
|
194
|
+
upb_Arena *Arena_get(VALUE _arena) {
|
202
195
|
Arena *arena;
|
203
196
|
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
204
197
|
return arena->arena;
|
205
198
|
}
|
206
199
|
|
207
|
-
void Arena_fuse(VALUE _arena,
|
200
|
+
void Arena_fuse(VALUE _arena, upb_Arena *other) {
|
208
201
|
Arena *arena;
|
209
202
|
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
210
|
-
if (!
|
203
|
+
if (!upb_Arena_Fuse(arena->arena, other)) {
|
211
204
|
rb_raise(rb_eRuntimeError,
|
212
205
|
"Unable to fuse arenas. This should never happen since Ruby does "
|
213
206
|
"not use initial blocks");
|
214
207
|
}
|
215
208
|
}
|
216
209
|
|
217
|
-
VALUE Arena_new() {
|
218
|
-
return Arena_alloc(cArena);
|
219
|
-
}
|
210
|
+
VALUE Arena_new() { return Arena_alloc(cArena); }
|
220
211
|
|
221
212
|
void Arena_Pin(VALUE _arena, VALUE obj) {
|
222
213
|
Arena *arena;
|
223
214
|
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
224
215
|
if (arena->pinned_objs == Qnil) {
|
225
|
-
arena->pinned_objs
|
216
|
+
RB_OBJ_WRITE(_arena, &arena->pinned_objs, rb_ary_new());
|
226
217
|
}
|
227
218
|
rb_ary_push(arena->pinned_objs, obj);
|
228
219
|
}
|
@@ -239,164 +230,48 @@ void Arena_register(VALUE module) {
|
|
239
230
|
// Object Cache
|
240
231
|
// -----------------------------------------------------------------------------
|
241
232
|
|
242
|
-
// A pointer -> Ruby Object cache that keeps references to Ruby wrapper
|
243
|
-
// objects. This allows us to look up any Ruby wrapper object by the address
|
244
|
-
// of the object it is wrapping. That way we can avoid ever creating two
|
245
|
-
// different wrapper objects for the same C object, which saves memory and
|
246
|
-
// preserves object identity.
|
247
|
-
//
|
248
|
-
// We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
|
249
|
-
// to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
|
250
|
-
// keys.
|
251
|
-
//
|
252
|
-
// We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
|
253
|
-
// means it may not be possible to fit a pointer into a Fixnum. Keys are
|
254
|
-
// pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
|
255
|
-
// they overflow and require allocating a Bignum, they could get collected
|
256
|
-
// prematurely, thus removing the cache entry. This happens on 64-bit Windows,
|
257
|
-
// on which pointers are 64 bits but longs are 32 bits. In this case, we enable
|
258
|
-
// the secondary Hash to hold the keys and prevent them from being collected.
|
259
|
-
|
260
|
-
#if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
|
261
|
-
#define USE_SECONDARY_MAP 0
|
262
|
-
#else
|
263
|
-
#define USE_SECONDARY_MAP 1
|
264
|
-
#endif
|
265
|
-
|
266
|
-
#if USE_SECONDARY_MAP
|
267
|
-
|
268
|
-
// Maps Numeric -> Object. The object is then used as a key into the WeakMap.
|
269
|
-
// This is needed for Ruby <2.7 where a number cannot be a key to WeakMap.
|
270
|
-
// The object is used only for its identity; it does not contain any data.
|
271
|
-
VALUE secondary_map = Qnil;
|
272
|
-
|
273
|
-
// Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
|
274
|
-
// iterates over the map which cannot happen in parallel with insertions, or
|
275
|
-
// Ruby will throw:
|
276
|
-
// can't add a new key into hash during iteration (RuntimeError)
|
277
|
-
VALUE secondary_map_mutex = Qnil;
|
278
|
-
|
279
|
-
// Lambda that will GC entries from the secondary map that are no longer present
|
280
|
-
// in the primary map.
|
281
|
-
VALUE gc_secondary_map_lambda = Qnil;
|
282
|
-
ID length;
|
283
|
-
|
284
|
-
extern VALUE weak_obj_cache;
|
285
|
-
|
286
|
-
static void SecondaryMap_Init() {
|
287
|
-
rb_gc_register_address(&secondary_map);
|
288
|
-
rb_gc_register_address(&gc_secondary_map_lambda);
|
289
|
-
rb_gc_register_address(&secondary_map_mutex);
|
290
|
-
secondary_map = rb_hash_new();
|
291
|
-
gc_secondary_map_lambda = rb_eval_string(
|
292
|
-
"->(secondary, weak) {\n"
|
293
|
-
" secondary.delete_if { |k, v| !weak.key?(v) }\n"
|
294
|
-
"}\n");
|
295
|
-
secondary_map_mutex = rb_mutex_new();
|
296
|
-
length = rb_intern("length");
|
297
|
-
}
|
298
|
-
|
299
|
-
// The secondary map is a regular Hash, and will never shrink on its own.
|
300
|
-
// The main object cache is a WeakMap that will automatically remove entries
|
301
|
-
// when the target object is no longer reachable, but unless we manually
|
302
|
-
// remove the corresponding entries from the secondary map, it will grow
|
303
|
-
// without bound.
|
304
|
-
//
|
305
|
-
// To avoid this unbounded growth we periodically remove entries from the
|
306
|
-
// secondary map that are no longer present in the WeakMap. The logic of
|
307
|
-
// how often to perform this GC is an artbirary tuning parameter that
|
308
|
-
// represents a straightforward CPU/memory tradeoff.
|
309
|
-
//
|
310
|
-
// Requires: secondary_map_mutex is held.
|
311
|
-
static void SecondaryMap_MaybeGC() {
|
312
|
-
PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
313
|
-
size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
|
314
|
-
size_t secondary_len = RHASH_SIZE(secondary_map);
|
315
|
-
if (secondary_len < weak_len) {
|
316
|
-
// Logically this case should not be possible: a valid entry cannot exist in
|
317
|
-
// the weak table unless there is a corresponding entry in the secondary
|
318
|
-
// table. It should *always* be the case that secondary_len >= weak_len.
|
319
|
-
//
|
320
|
-
// However ObjectSpace::WeakMap#length (and therefore weak_len) is
|
321
|
-
// unreliable: it overreports its true length by including non-live objects.
|
322
|
-
// However these non-live objects are not yielded in iteration, so we may
|
323
|
-
// have previously deleted them from the secondary map in a previous
|
324
|
-
// invocation of SecondaryMap_MaybeGC().
|
325
|
-
//
|
326
|
-
// In this case, we can't measure any waste, so we just return.
|
327
|
-
return;
|
328
|
-
}
|
329
|
-
size_t waste = secondary_len - weak_len;
|
330
|
-
// GC if we could remove at least 2000 entries or 20% of the table size
|
331
|
-
// (whichever is greater). Since the cost of the GC pass is O(N), we
|
332
|
-
// want to make sure that we condition this on overall table size, to
|
333
|
-
// avoid O(N^2) CPU costs.
|
334
|
-
size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
|
335
|
-
if (waste > threshold) {
|
336
|
-
rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2,
|
337
|
-
secondary_map, weak_obj_cache);
|
338
|
-
}
|
339
|
-
}
|
340
|
-
|
341
|
-
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
342
|
-
static VALUE SecondaryMap_Get(VALUE key, bool create) {
|
343
|
-
PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
344
|
-
VALUE ret = rb_hash_lookup(secondary_map, key);
|
345
|
-
if (ret == Qnil && create) {
|
346
|
-
SecondaryMap_MaybeGC();
|
347
|
-
ret = rb_class_new_instance(0, NULL, rb_cObject);
|
348
|
-
rb_hash_aset(secondary_map, key, ret);
|
349
|
-
}
|
350
|
-
return ret;
|
351
|
-
}
|
352
|
-
|
353
|
-
#endif
|
354
|
-
|
355
|
-
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
356
|
-
static VALUE ObjectCache_GetKey(const void* key, bool create) {
|
357
|
-
VALUE key_val = (VALUE)key;
|
358
|
-
PBRUBY_ASSERT((key_val & 3) == 0);
|
359
|
-
VALUE ret = LL2NUM(key_val >> 2);
|
360
|
-
#if USE_SECONDARY_MAP
|
361
|
-
ret = SecondaryMap_Get(ret, create);
|
362
|
-
#endif
|
363
|
-
return ret;
|
364
|
-
}
|
365
|
-
|
366
233
|
// Public ObjectCache API.
|
367
234
|
|
368
235
|
VALUE weak_obj_cache = Qnil;
|
369
236
|
ID item_get;
|
370
|
-
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");
|
371
242
|
|
372
|
-
static void ObjectCache_Init() {
|
373
243
|
rb_gc_register_address(&weak_obj_cache);
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
#if USE_SECONDARY_MAP
|
379
|
-
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"));
|
380
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));
|
381
254
|
}
|
382
255
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
VALUE
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
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);
|
394
269
|
}
|
395
270
|
|
396
271
|
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
397
|
-
VALUE ObjectCache_Get(const void*
|
398
|
-
VALUE
|
399
|
-
return rb_funcall(weak_obj_cache, item_get, 1,
|
272
|
+
VALUE ObjectCache_Get(const void *key) {
|
273
|
+
VALUE key_val = ObjectCache_GetKey(key);
|
274
|
+
return rb_funcall(weak_obj_cache, item_get, 1, key_val);
|
400
275
|
}
|
401
276
|
|
402
277
|
/*
|
@@ -407,9 +282,9 @@ VALUE ObjectCache_Get(const void* key) {
|
|
407
282
|
* unknown fields in submessages.
|
408
283
|
*/
|
409
284
|
static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) {
|
410
|
-
const
|
411
|
-
|
412
|
-
if (!
|
285
|
+
const upb_MessageDef *m;
|
286
|
+
upb_Message *msg = Message_GetMutable(msg_rb, &m);
|
287
|
+
if (!upb_Message_DiscardUnknown(msg, m, 128)) {
|
413
288
|
rb_raise(rb_eRuntimeError, "Messages nested too deeply.");
|
414
289
|
}
|
415
290
|
|
@@ -431,10 +306,10 @@ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
|
|
431
306
|
return Map_deep_copy(obj);
|
432
307
|
} else {
|
433
308
|
VALUE new_arena_rb = Arena_new();
|
434
|
-
|
435
|
-
const
|
436
|
-
const
|
437
|
-
|
309
|
+
upb_Arena *new_arena = Arena_get(new_arena_rb);
|
310
|
+
const upb_MessageDef *m;
|
311
|
+
const upb_Message *msg = Message_Get(obj, &m);
|
312
|
+
upb_Message *new_msg = Message_deep_copy(msg, m, new_arena);
|
438
313
|
return Message_GetRubyWrapper(new_msg, m, new_arena_rb);
|
439
314
|
}
|
440
315
|
}
|
@@ -445,13 +320,11 @@ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
|
|
445
320
|
|
446
321
|
// This must be named "Init_protobuf_c" because the Ruby module is named
|
447
322
|
// "protobuf_c" -- the VM looks for this symbol in our .so.
|
448
|
-
__attribute__
|
449
|
-
void Init_protobuf_c() {
|
450
|
-
ObjectCache_Init();
|
451
|
-
|
323
|
+
__attribute__((visibility("default"))) void Init_protobuf_c() {
|
452
324
|
VALUE google = rb_define_module("Google");
|
453
325
|
VALUE protobuf = rb_define_module_under(google, "Protobuf");
|
454
326
|
|
327
|
+
ObjectCache_Init(protobuf);
|
455
328
|
Arena_register(protobuf);
|
456
329
|
Defs_register(protobuf);
|
457
330
|
RepeatedField_register(protobuf);
|
@@ -465,6 +338,6 @@ void Init_protobuf_c() {
|
|
465
338
|
|
466
339
|
rb_define_singleton_method(protobuf, "discard_unknown",
|
467
340
|
Google_Protobuf_discard_unknown, 1);
|
468
|
-
rb_define_singleton_method(protobuf, "deep_copy",
|
469
|
-
|
341
|
+
rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy,
|
342
|
+
1);
|
470
343
|
}
|