blob: 8d689ac88bad82c2ec33c6fdd42ebb9ca9599d78 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34//
35// DynamicMessage is implemented by constructing a data structure which
36// has roughly the same memory layout as a generated message would have.
37// Then, we use GeneratedMessageReflection to implement our reflection
38// interface. All the other operations we need to implement (e.g.
39// parsing, copying, etc.) are already implemented in terms of
temporal779f61c2008-08-13 03:15:00 +000040// Reflection, so the rest is easy.
temporal40ee5512008-07-10 02:12:20 +000041//
42// The up side of this strategy is that it's very efficient. We don't
43// need to use hash_maps or generic representations of fields. The
44// down side is that this is a low-level memory management hack which
45// can be tricky to get right.
46//
47// As mentioned in the header, we only expose a DynamicMessageFactory
48// publicly, not the DynamicMessage class itself. This is because
49// GenericMessageReflection wants to have a pointer to a "default"
50// copy of the class, with all fields initialized to their default
51// values. We only want to construct one of these per message type,
52// so DynamicMessageFactory stores a cache of default messages for
53// each type it sees (each unique Descriptor pointer). The code
54// refers to the "default" copy of the class as the "prototype".
55//
56// Note on memory allocation: This module often calls "operator new()"
57// to allocate untyped memory, rather than calling something like
58// "new uint8[]". This is because "operator new()" means "Give me some
59// space which I can use as I please." while "new uint8[]" means "Give
60// me an array of 8-bit integers.". In practice, the later may return
61// a pointer that is not aligned correctly for general use. I believe
62// Item 8 of "More Effective C++" discusses this in more detail, though
63// I don't have the book on me right now so I'm not sure.
64
65#include <algorithm>
66#include <google/protobuf/stubs/hash.h>
Jisi Liu46e8ff62015-10-05 11:59:43 -070067#include <memory>
68#ifndef _SHARED_PTR_H
69#include <google/protobuf/stubs/shared_ptr.h>
70#endif
temporal40ee5512008-07-10 02:12:20 +000071
72#include <google/protobuf/stubs/common.h>
Feng Xiaoe841bac2015-12-11 17:09:20 -080073#include <google/protobuf/stubs/scoped_ptr.h>
temporal40ee5512008-07-10 02:12:20 +000074
75#include <google/protobuf/dynamic_message.h>
76#include <google/protobuf/descriptor.h>
77#include <google/protobuf/descriptor.pb.h>
kenton@google.com80b1d622009-07-29 01:13:20 +000078#include <google/protobuf/generated_message_util.h>
temporal40ee5512008-07-10 02:12:20 +000079#include <google/protobuf/generated_message_reflection.h>
Feng Xiao6ef984a2014-11-10 17:34:54 -080080#include <google/protobuf/arenastring.h>
Feng Xiaof157a562014-11-14 11:50:31 -080081#include <google/protobuf/map_field_inl.h>
temporal40ee5512008-07-10 02:12:20 +000082#include <google/protobuf/reflection_ops.h>
83#include <google/protobuf/repeated_field.h>
Feng Xiaof157a562014-11-14 11:50:31 -080084#include <google/protobuf/map_type_handler.h>
temporal40ee5512008-07-10 02:12:20 +000085#include <google/protobuf/extension_set.h>
86#include <google/protobuf/wire_format.h>
Feng Xiaoeee38b02015-08-22 18:25:48 -070087#include <google/protobuf/map_field.h>
temporal40ee5512008-07-10 02:12:20 +000088
89namespace google {
90namespace protobuf {
91
92using internal::WireFormat;
93using internal::ExtensionSet;
94using internal::GeneratedMessageReflection;
Feng Xiaof157a562014-11-14 11:50:31 -080095using internal::MapField;
Feng Xiaoeee38b02015-08-22 18:25:48 -070096using internal::DynamicMapField;
temporal40ee5512008-07-10 02:12:20 +000097
98
Feng Xiao6ef984a2014-11-10 17:34:54 -080099using internal::ArenaStringPtr;
100
temporal40ee5512008-07-10 02:12:20 +0000101// ===================================================================
102// Some helper tables and functions...
103
104namespace {
105
Feng Xiaof157a562014-11-14 11:50:31 -0800106bool IsMapFieldInApi(const FieldDescriptor* field) {
107 return field->is_map();
108}
109
temporal40ee5512008-07-10 02:12:20 +0000110// Compute the byte size of the in-memory representation of the field.
111int FieldSpaceUsed(const FieldDescriptor* field) {
112 typedef FieldDescriptor FD; // avoid line wrapping
113 if (field->label() == FD::LABEL_REPEATED) {
114 switch (field->cpp_type()) {
115 case FD::CPPTYPE_INT32 : return sizeof(RepeatedField<int32 >);
116 case FD::CPPTYPE_INT64 : return sizeof(RepeatedField<int64 >);
117 case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField<uint32 >);
118 case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField<uint64 >);
119 case FD::CPPTYPE_DOUBLE : return sizeof(RepeatedField<double >);
120 case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField<float >);
121 case FD::CPPTYPE_BOOL : return sizeof(RepeatedField<bool >);
122 case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >);
Feng Xiaof157a562014-11-14 11:50:31 -0800123 case FD::CPPTYPE_MESSAGE:
124 if (IsMapFieldInApi(field)) {
Feng Xiaoeee38b02015-08-22 18:25:48 -0700125 return sizeof(DynamicMapField);
Feng Xiaof157a562014-11-14 11:50:31 -0800126 } else {
127 return sizeof(RepeatedPtrField<Message>);
128 }
temporal40ee5512008-07-10 02:12:20 +0000129
130 case FD::CPPTYPE_STRING:
kenton@google.comfccb1462009-12-18 02:11:36 +0000131 switch (field->options().ctype()) {
132 default: // TODO(kenton): Support other string reps.
133 case FieldOptions::STRING:
134 return sizeof(RepeatedPtrField<string>);
135 }
temporal40ee5512008-07-10 02:12:20 +0000136 break;
137 }
138 } else {
139 switch (field->cpp_type()) {
140 case FD::CPPTYPE_INT32 : return sizeof(int32 );
141 case FD::CPPTYPE_INT64 : return sizeof(int64 );
142 case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
143 case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
144 case FD::CPPTYPE_DOUBLE : return sizeof(double );
145 case FD::CPPTYPE_FLOAT : return sizeof(float );
146 case FD::CPPTYPE_BOOL : return sizeof(bool );
147 case FD::CPPTYPE_ENUM : return sizeof(int );
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000148
149 case FD::CPPTYPE_MESSAGE:
150 return sizeof(Message*);
temporal40ee5512008-07-10 02:12:20 +0000151
152 case FD::CPPTYPE_STRING:
kenton@google.comfccb1462009-12-18 02:11:36 +0000153 switch (field->options().ctype()) {
154 default: // TODO(kenton): Support other string reps.
155 case FieldOptions::STRING:
Feng Xiao6ef984a2014-11-10 17:34:54 -0800156 return sizeof(ArenaStringPtr);
kenton@google.comfccb1462009-12-18 02:11:36 +0000157 }
temporal40ee5512008-07-10 02:12:20 +0000158 break;
159 }
160 }
161
162 GOOGLE_LOG(DFATAL) << "Can't get here.";
163 return 0;
164}
165
jieluo@google.com4de8f552014-07-18 00:47:59 +0000166// Compute the byte size of in-memory representation of the oneof fields
167// in default oneof instance.
168int OneofFieldSpaceUsed(const FieldDescriptor* field) {
169 typedef FieldDescriptor FD; // avoid line wrapping
170 switch (field->cpp_type()) {
171 case FD::CPPTYPE_INT32 : return sizeof(int32 );
172 case FD::CPPTYPE_INT64 : return sizeof(int64 );
173 case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
174 case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
175 case FD::CPPTYPE_DOUBLE : return sizeof(double );
176 case FD::CPPTYPE_FLOAT : return sizeof(float );
177 case FD::CPPTYPE_BOOL : return sizeof(bool );
178 case FD::CPPTYPE_ENUM : return sizeof(int );
179
180 case FD::CPPTYPE_MESSAGE:
181 return sizeof(Message*);
182
183 case FD::CPPTYPE_STRING:
184 switch (field->options().ctype()) {
185 default:
186 case FieldOptions::STRING:
Feng Xiao6ef984a2014-11-10 17:34:54 -0800187 return sizeof(ArenaStringPtr);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000188 }
189 break;
190 }
191
192 GOOGLE_LOG(DFATAL) << "Can't get here.";
193 return 0;
194}
195
temporal40ee5512008-07-10 02:12:20 +0000196inline int DivideRoundingUp(int i, int j) {
197 return (i + (j - 1)) / j;
198}
199
temporal779f61c2008-08-13 03:15:00 +0000200static const int kSafeAlignment = sizeof(uint64);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000201static const int kMaxOneofUnionSize = sizeof(uint64);
temporal779f61c2008-08-13 03:15:00 +0000202
kenton@google.comd0580ea2008-11-07 02:07:18 +0000203inline int AlignTo(int offset, int alignment) {
204 return DivideRoundingUp(offset, alignment) * alignment;
205}
206
temporal779f61c2008-08-13 03:15:00 +0000207// Rounds the given byte offset up to the next offset aligned such that any
208// type may be stored at it.
209inline int AlignOffset(int offset) {
kenton@google.comd0580ea2008-11-07 02:07:18 +0000210 return AlignTo(offset, kSafeAlignment);
temporal779f61c2008-08-13 03:15:00 +0000211}
212
temporal40ee5512008-07-10 02:12:20 +0000213#define bitsizeof(T) (sizeof(T) * 8)
214
215} // namespace
216
217// ===================================================================
218
219class DynamicMessage : public Message {
220 public:
temporal779f61c2008-08-13 03:15:00 +0000221 struct TypeInfo {
222 int size;
223 int has_bits_offset;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000224 int oneof_case_offset;
temporal779f61c2008-08-13 03:15:00 +0000225 int unknown_fields_offset;
226 int extensions_offset;
Feng Xiaoc25d9fe2014-11-26 16:15:29 -0800227 int is_default_instance_offset;
temporal779f61c2008-08-13 03:15:00 +0000228
229 // Not owned by the TypeInfo.
230 DynamicMessageFactory* factory; // The factory that created this object.
231 const DescriptorPool* pool; // The factory's DescriptorPool.
232 const Descriptor* type; // Type of this DynamicMessage.
233
234 // Warning: The order in which the following pointers are defined is
235 // important (the prototype must be deleted *before* the offsets).
Jisi Liu46e8ff62015-10-05 11:59:43 -0700236 google::protobuf::scoped_array<int> offsets;
237 google::protobuf::scoped_ptr<const GeneratedMessageReflection> reflection;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000238 // Don't use a scoped_ptr to hold the prototype: the destructor for
239 // DynamicMessage needs to know whether it is the prototype, and does so by
240 // looking back at this field. This would assume details about the
241 // implementation of scoped_ptr.
242 const DynamicMessage* prototype;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000243 void* default_oneof_instance;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000244
jieluo@google.com4de8f552014-07-18 00:47:59 +0000245 TypeInfo() : prototype(NULL), default_oneof_instance(NULL) {}
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000246
247 ~TypeInfo() {
248 delete prototype;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000249 operator delete(default_oneof_instance);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000250 }
temporal779f61c2008-08-13 03:15:00 +0000251 };
252
253 DynamicMessage(const TypeInfo* type_info);
temporal40ee5512008-07-10 02:12:20 +0000254 ~DynamicMessage();
255
256 // Called on the prototype after construction to initialize message fields.
temporal779f61c2008-08-13 03:15:00 +0000257 void CrossLinkPrototypes();
temporal40ee5512008-07-10 02:12:20 +0000258
259 // implements Message ----------------------------------------------
260
261 Message* New() const;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800262 Message* New(::google::protobuf::Arena* arena) const;
263 ::google::protobuf::Arena* GetArena() const { return NULL; };
temporal40ee5512008-07-10 02:12:20 +0000264
265 int GetCachedSize() const;
266 void SetCachedSize(int size) const;
267
kenton@google.com80b1d622009-07-29 01:13:20 +0000268 Metadata GetMetadata() const;
temporal40ee5512008-07-10 02:12:20 +0000269
jieluo@google.com4de8f552014-07-18 00:47:59 +0000270
temporal40ee5512008-07-10 02:12:20 +0000271 private:
272 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800273 DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena);
274 void SharedCtor();
temporal40ee5512008-07-10 02:12:20 +0000275
temporal779f61c2008-08-13 03:15:00 +0000276 inline bool is_prototype() const {
277 return type_info_->prototype == this ||
278 // If type_info_->prototype is NULL, then we must be constructing
279 // the prototype now, which means we must be the prototype.
280 type_info_->prototype == NULL;
281 }
temporal40ee5512008-07-10 02:12:20 +0000282
temporal779f61c2008-08-13 03:15:00 +0000283 inline void* OffsetToPointer(int offset) {
284 return reinterpret_cast<uint8*>(this) + offset;
285 }
286 inline const void* OffsetToPointer(int offset) const {
287 return reinterpret_cast<const uint8*>(this) + offset;
288 }
289
290 const TypeInfo* type_info_;
temporal40ee5512008-07-10 02:12:20 +0000291 // TODO(kenton): Make this an atomic<int> when C++ supports it.
292 mutable int cached_byte_size_;
293};
294
temporal779f61c2008-08-13 03:15:00 +0000295DynamicMessage::DynamicMessage(const TypeInfo* type_info)
296 : type_info_(type_info),
temporal40ee5512008-07-10 02:12:20 +0000297 cached_byte_size_(0) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800298 SharedCtor();
299}
300
301DynamicMessage::DynamicMessage(const TypeInfo* type_info,
302 ::google::protobuf::Arena* arena)
303 : type_info_(type_info),
304 cached_byte_size_(0) {
305 SharedCtor();
306}
307
308void DynamicMessage::SharedCtor() {
temporal40ee5512008-07-10 02:12:20 +0000309 // We need to call constructors for various fields manually and set
310 // default values where appropriate. We use placement new to call
311 // constructors. If you haven't heard of placement new, I suggest Googling
312 // it now. We use placement new even for primitive types that don't have
313 // constructors for consistency. (In theory, placement new should be used
314 // any time you are trying to convert untyped memory to typed memory, though
315 // in practice that's not strictly necessary for types that don't have a
316 // constructor.)
temporal779f61c2008-08-13 03:15:00 +0000317
318 const Descriptor* descriptor = type_info_->type;
319
jieluo@google.com4de8f552014-07-18 00:47:59 +0000320 // Initialize oneof cases.
321 for (int i = 0 ; i < descriptor->oneof_decl_count(); ++i) {
322 new(OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32) * i))
323 uint32(0);
324 }
325
Feng Xiaoc25d9fe2014-11-26 16:15:29 -0800326 if (type_info_->is_default_instance_offset != -1) {
327 *reinterpret_cast<bool*>(
328 OffsetToPointer(type_info_->is_default_instance_offset)) = false;
329 }
330
temporal779f61c2008-08-13 03:15:00 +0000331 new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
332
333 if (type_info_->extensions_offset != -1) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000334 new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet;
temporal779f61c2008-08-13 03:15:00 +0000335 }
336
temporal40ee5512008-07-10 02:12:20 +0000337 for (int i = 0; i < descriptor->field_count(); i++) {
338 const FieldDescriptor* field = descriptor->field(i);
temporal779f61c2008-08-13 03:15:00 +0000339 void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000340 if (field->containing_oneof()) {
341 continue;
342 }
temporal40ee5512008-07-10 02:12:20 +0000343 switch (field->cpp_type()) {
344#define HANDLE_TYPE(CPPTYPE, TYPE) \
345 case FieldDescriptor::CPPTYPE_##CPPTYPE: \
346 if (!field->is_repeated()) { \
347 new(field_ptr) TYPE(field->default_value_##TYPE()); \
348 } else { \
349 new(field_ptr) RepeatedField<TYPE>(); \
350 } \
351 break;
352
353 HANDLE_TYPE(INT32 , int32 );
354 HANDLE_TYPE(INT64 , int64 );
355 HANDLE_TYPE(UINT32, uint32);
356 HANDLE_TYPE(UINT64, uint64);
357 HANDLE_TYPE(DOUBLE, double);
358 HANDLE_TYPE(FLOAT , float );
359 HANDLE_TYPE(BOOL , bool );
360#undef HANDLE_TYPE
361
362 case FieldDescriptor::CPPTYPE_ENUM:
363 if (!field->is_repeated()) {
364 new(field_ptr) int(field->default_value_enum()->number());
365 } else {
366 new(field_ptr) RepeatedField<int>();
367 }
368 break;
369
370 case FieldDescriptor::CPPTYPE_STRING:
kenton@google.comfccb1462009-12-18 02:11:36 +0000371 switch (field->options().ctype()) {
372 default: // TODO(kenton): Support other string reps.
373 case FieldOptions::STRING:
374 if (!field->is_repeated()) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800375 const string* default_value;
kenton@google.comfccb1462009-12-18 02:11:36 +0000376 if (is_prototype()) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800377 default_value = &field->default_value_string();
kenton@google.comfccb1462009-12-18 02:11:36 +0000378 } else {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800379 default_value =
380 &(reinterpret_cast<const ArenaStringPtr*>(
kenton@google.comfccb1462009-12-18 02:11:36 +0000381 type_info_->prototype->OffsetToPointer(
Feng Xiao6ef984a2014-11-10 17:34:54 -0800382 type_info_->offsets[i]))->Get(NULL));
kenton@google.comfccb1462009-12-18 02:11:36 +0000383 }
Feng Xiao6ef984a2014-11-10 17:34:54 -0800384 ArenaStringPtr* asp = new(field_ptr) ArenaStringPtr();
385 asp->UnsafeSetDefault(default_value);
temporal40ee5512008-07-10 02:12:20 +0000386 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000387 new(field_ptr) RepeatedPtrField<string>();
temporal40ee5512008-07-10 02:12:20 +0000388 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000389 break;
390 }
temporal40ee5512008-07-10 02:12:20 +0000391 break;
392
393 case FieldDescriptor::CPPTYPE_MESSAGE: {
kenton@google.com80b1d622009-07-29 01:13:20 +0000394 if (!field->is_repeated()) {
395 new(field_ptr) Message*(NULL);
396 } else {
Feng Xiaof157a562014-11-14 11:50:31 -0800397 if (IsMapFieldInApi(field)) {
Feng Xiaoeee38b02015-08-22 18:25:48 -0700398 new (field_ptr) DynamicMapField(
399 type_info_->factory->GetPrototypeNoLock(field->message_type()));
Feng Xiaof157a562014-11-14 11:50:31 -0800400 } else {
401 new (field_ptr) RepeatedPtrField<Message>();
402 }
temporal40ee5512008-07-10 02:12:20 +0000403 }
404 break;
405 }
406 }
407 }
408}
409
410DynamicMessage::~DynamicMessage() {
temporal779f61c2008-08-13 03:15:00 +0000411 const Descriptor* descriptor = type_info_->type;
412
413 reinterpret_cast<UnknownFieldSet*>(
414 OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet();
415
416 if (type_info_->extensions_offset != -1) {
417 reinterpret_cast<ExtensionSet*>(
418 OffsetToPointer(type_info_->extensions_offset))->~ExtensionSet();
419 }
420
temporal40ee5512008-07-10 02:12:20 +0000421 // We need to manually run the destructors for repeated fields and strings,
Dongjoon Hyun7a9040f2016-01-14 22:12:03 -0800422 // just as we ran their constructors in the DynamicMessage constructor.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000423 // We also need to manually delete oneof fields if it is set and is string
424 // or message.
temporal40ee5512008-07-10 02:12:20 +0000425 // Additionally, if any singular embedded messages have been allocated, we
426 // need to delete them, UNLESS we are the prototype message of this type,
427 // in which case any embedded messages are other prototypes and shouldn't
428 // be touched.
temporal40ee5512008-07-10 02:12:20 +0000429 for (int i = 0; i < descriptor->field_count(); i++) {
430 const FieldDescriptor* field = descriptor->field(i);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000431 if (field->containing_oneof()) {
432 void* field_ptr = OffsetToPointer(
433 type_info_->oneof_case_offset
434 + sizeof(uint32) * field->containing_oneof()->index());
435 if (*(reinterpret_cast<const uint32*>(field_ptr)) ==
436 field->number()) {
437 field_ptr = OffsetToPointer(type_info_->offsets[
438 descriptor->field_count() + field->containing_oneof()->index()]);
439 if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
440 switch (field->options().ctype()) {
441 default:
Feng Xiao6ef984a2014-11-10 17:34:54 -0800442 case FieldOptions::STRING: {
443 const ::std::string* default_value =
444 &(reinterpret_cast<const ArenaStringPtr*>(
445 type_info_->prototype->OffsetToPointer(
446 type_info_->offsets[i]))->Get(NULL));
Feng Xiaoeee38b02015-08-22 18:25:48 -0700447 reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
448 default_value, NULL);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000449 break;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800450 }
jieluo@google.com4de8f552014-07-18 00:47:59 +0000451 }
452 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
453 delete *reinterpret_cast<Message**>(field_ptr);
454 }
455 }
456 continue;
457 }
temporal779f61c2008-08-13 03:15:00 +0000458 void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
temporal40ee5512008-07-10 02:12:20 +0000459
460 if (field->is_repeated()) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000461 switch (field->cpp_type()) {
462#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
463 case FieldDescriptor::CPPTYPE_##UPPERCASE : \
464 reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
465 ->~RepeatedField<LOWERCASE>(); \
466 break
467
468 HANDLE_TYPE( INT32, int32);
469 HANDLE_TYPE( INT64, int64);
470 HANDLE_TYPE(UINT32, uint32);
471 HANDLE_TYPE(UINT64, uint64);
472 HANDLE_TYPE(DOUBLE, double);
473 HANDLE_TYPE( FLOAT, float);
474 HANDLE_TYPE( BOOL, bool);
475 HANDLE_TYPE( ENUM, int);
476#undef HANDLE_TYPE
477
478 case FieldDescriptor::CPPTYPE_STRING:
kenton@google.comfccb1462009-12-18 02:11:36 +0000479 switch (field->options().ctype()) {
480 default: // TODO(kenton): Support other string reps.
481 case FieldOptions::STRING:
482 reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
483 ->~RepeatedPtrField<string>();
484 break;
485 }
kenton@google.com80b1d622009-07-29 01:13:20 +0000486 break;
487
488 case FieldDescriptor::CPPTYPE_MESSAGE:
Feng Xiaof157a562014-11-14 11:50:31 -0800489 if (IsMapFieldInApi(field)) {
Feng Xiaoeee38b02015-08-22 18:25:48 -0700490 reinterpret_cast<DynamicMapField*>(field_ptr)->~DynamicMapField();
Feng Xiaof157a562014-11-14 11:50:31 -0800491 } else {
492 reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
493 ->~RepeatedPtrField<Message>();
494 }
kenton@google.com80b1d622009-07-29 01:13:20 +0000495 break;
496 }
temporal40ee5512008-07-10 02:12:20 +0000497
498 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000499 switch (field->options().ctype()) {
500 default: // TODO(kenton): Support other string reps.
501 case FieldOptions::STRING: {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800502 const ::std::string* default_value =
503 &(reinterpret_cast<const ArenaStringPtr*>(
504 type_info_->prototype->OffsetToPointer(
505 type_info_->offsets[i]))->Get(NULL));
Feng Xiaoeee38b02015-08-22 18:25:48 -0700506 reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
507 default_value, NULL);
kenton@google.comfccb1462009-12-18 02:11:36 +0000508 break;
temporal40ee5512008-07-10 02:12:20 +0000509 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000510 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000511 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
512 if (!is_prototype()) {
513 Message* message = *reinterpret_cast<Message**>(field_ptr);
514 if (message != NULL) {
515 delete message;
516 }
temporal40ee5512008-07-10 02:12:20 +0000517 }
518 }
519 }
temporal40ee5512008-07-10 02:12:20 +0000520}
521
temporal779f61c2008-08-13 03:15:00 +0000522void DynamicMessage::CrossLinkPrototypes() {
temporal40ee5512008-07-10 02:12:20 +0000523 // This should only be called on the prototype message.
524 GOOGLE_CHECK(is_prototype());
525
temporal779f61c2008-08-13 03:15:00 +0000526 DynamicMessageFactory* factory = type_info_->factory;
527 const Descriptor* descriptor = type_info_->type;
528
temporal40ee5512008-07-10 02:12:20 +0000529 // Cross-link default messages.
temporal779f61c2008-08-13 03:15:00 +0000530 for (int i = 0; i < descriptor->field_count(); i++) {
531 const FieldDescriptor* field = descriptor->field(i);
532 void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000533 if (field->containing_oneof()) {
534 field_ptr = reinterpret_cast<uint8*>(
535 type_info_->default_oneof_instance) + type_info_->offsets[i];
536 }
temporal40ee5512008-07-10 02:12:20 +0000537
kenton@google.com80b1d622009-07-29 01:13:20 +0000538 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
539 !field->is_repeated()) {
temporal40ee5512008-07-10 02:12:20 +0000540 // For fields with message types, we need to cross-link with the
541 // prototype for the field's type.
kenton@google.com80b1d622009-07-29 01:13:20 +0000542 // For singular fields, the field is just a pointer which should
543 // point to the prototype.
544 *reinterpret_cast<const Message**>(field_ptr) =
kenton@google.comfccb1462009-12-18 02:11:36 +0000545 factory->GetPrototypeNoLock(field->message_type());
temporal40ee5512008-07-10 02:12:20 +0000546 }
547 }
Feng Xiaoc25d9fe2014-11-26 16:15:29 -0800548
549 // Set as the default instance -- this affects field-presence semantics for
550 // proto3.
551 if (type_info_->is_default_instance_offset != -1) {
552 void* is_default_instance_ptr =
553 OffsetToPointer(type_info_->is_default_instance_offset);
554 *reinterpret_cast<bool*>(is_default_instance_ptr) = true;
555 }
temporal40ee5512008-07-10 02:12:20 +0000556}
557
558Message* DynamicMessage::New() const {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000559 void* new_base = operator new(type_info_->size);
temporal779f61c2008-08-13 03:15:00 +0000560 memset(new_base, 0, type_info_->size);
561 return new(new_base) DynamicMessage(type_info_);
temporal40ee5512008-07-10 02:12:20 +0000562}
563
Feng Xiao6ef984a2014-11-10 17:34:54 -0800564Message* DynamicMessage::New(::google::protobuf::Arena* arena) const {
565 if (arena != NULL) {
566 Message* message = New();
567 arena->Own(message);
568 return message;
569 } else {
570 return New();
571 }
572}
573
temporal40ee5512008-07-10 02:12:20 +0000574int DynamicMessage::GetCachedSize() const {
575 return cached_byte_size_;
576}
577
578void DynamicMessage::SetCachedSize(int size) const {
579 // This is theoretically not thread-compatible, but in practice it works
580 // because if multiple threads write this simultaneously, they will be
581 // writing the exact same value.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000582 GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
temporal40ee5512008-07-10 02:12:20 +0000583 cached_byte_size_ = size;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000584 GOOGLE_SAFE_CONCURRENT_WRITES_END();
temporal40ee5512008-07-10 02:12:20 +0000585}
586
kenton@google.com80b1d622009-07-29 01:13:20 +0000587Metadata DynamicMessage::GetMetadata() const {
588 Metadata metadata;
589 metadata.descriptor = type_info_->type;
590 metadata.reflection = type_info_->reflection.get();
591 return metadata;
temporal40ee5512008-07-10 02:12:20 +0000592}
593
594// ===================================================================
595
596struct DynamicMessageFactory::PrototypeMap {
temporal779f61c2008-08-13 03:15:00 +0000597 typedef hash_map<const Descriptor*, const DynamicMessage::TypeInfo*> Map;
temporal40ee5512008-07-10 02:12:20 +0000598 Map map_;
599};
600
601DynamicMessageFactory::DynamicMessageFactory()
kenton@google.comfccb1462009-12-18 02:11:36 +0000602 : pool_(NULL), delegate_to_generated_factory_(false),
603 prototypes_(new PrototypeMap) {
temporal40ee5512008-07-10 02:12:20 +0000604}
605
606DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
kenton@google.comfccb1462009-12-18 02:11:36 +0000607 : pool_(pool), delegate_to_generated_factory_(false),
608 prototypes_(new PrototypeMap) {
temporal40ee5512008-07-10 02:12:20 +0000609}
610
611DynamicMessageFactory::~DynamicMessageFactory() {
612 for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
613 iter != prototypes_->map_.end(); ++iter) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000614 DeleteDefaultOneofInstance(iter->second->type,
615 iter->second->offsets.get(),
616 iter->second->default_oneof_instance);
temporal40ee5512008-07-10 02:12:20 +0000617 delete iter->second;
618 }
619}
620
temporal40ee5512008-07-10 02:12:20 +0000621const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000622 MutexLock lock(&prototypes_mutex_);
623 return GetPrototypeNoLock(type);
624}
625
626const Message* DynamicMessageFactory::GetPrototypeNoLock(
627 const Descriptor* type) {
628 if (delegate_to_generated_factory_ &&
629 type->file()->pool() == DescriptorPool::generated_pool()) {
630 return MessageFactory::generated_factory()->GetPrototype(type);
631 }
632
temporal779f61c2008-08-13 03:15:00 +0000633 const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
temporal40ee5512008-07-10 02:12:20 +0000634 if (*target != NULL) {
635 // Already exists.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000636 return (*target)->prototype;
temporal40ee5512008-07-10 02:12:20 +0000637 }
638
temporal779f61c2008-08-13 03:15:00 +0000639 DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
640 *target = type_info;
641
642 type_info->type = type;
643 type_info->pool = (pool_ == NULL) ? type->file()->pool() : pool_;
644 type_info->factory = this;
645
temporal40ee5512008-07-10 02:12:20 +0000646 // We need to construct all the structures passed to
647 // GeneratedMessageReflection's constructor. This includes:
648 // - A block of memory that contains space for all the message's fields.
649 // - An array of integers indicating the byte offset of each field within
650 // this block.
651 // - A big bitfield containing a bit for each field indicating whether
652 // or not that field is set.
653
654 // Compute size and offsets.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000655 int* offsets = new int[type->field_count() + type->oneof_decl_count()];
temporal779f61c2008-08-13 03:15:00 +0000656 type_info->offsets.reset(offsets);
temporal40ee5512008-07-10 02:12:20 +0000657
temporal40ee5512008-07-10 02:12:20 +0000658 // Decide all field offsets by packing in order.
temporal779f61c2008-08-13 03:15:00 +0000659 // We place the DynamicMessage object itself at the beginning of the allocated
660 // space.
661 int size = sizeof(DynamicMessage);
662 size = AlignOffset(size);
temporal40ee5512008-07-10 02:12:20 +0000663
temporal779f61c2008-08-13 03:15:00 +0000664 // Next the has_bits, which is an array of uint32s.
Feng Xiaoc25d9fe2014-11-26 16:15:29 -0800665 if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
666 type_info->has_bits_offset = -1;
667 } else {
668 type_info->has_bits_offset = size;
669 int has_bits_array_size =
670 DivideRoundingUp(type->field_count(), bitsizeof(uint32));
671 size += has_bits_array_size * sizeof(uint32);
672 size = AlignOffset(size);
673 }
674
675 // The is_default_instance member, if any.
676 if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
677 type_info->is_default_instance_offset = size;
678 size += sizeof(bool);
679 size = AlignOffset(size);
680 } else {
681 type_info->is_default_instance_offset = -1;
682 }
temporal779f61c2008-08-13 03:15:00 +0000683
jieluo@google.com4de8f552014-07-18 00:47:59 +0000684 // The oneof_case, if any. It is an array of uint32s.
685 if (type->oneof_decl_count() > 0) {
686 type_info->oneof_case_offset = size;
687 size += type->oneof_decl_count() * sizeof(uint32);
688 size = AlignOffset(size);
689 }
690
temporal779f61c2008-08-13 03:15:00 +0000691 // The ExtensionSet, if any.
692 if (type->extension_range_count() > 0) {
693 type_info->extensions_offset = size;
694 size += sizeof(ExtensionSet);
695 size = AlignOffset(size);
696 } else {
697 // No extensions.
698 type_info->extensions_offset = -1;
temporal40ee5512008-07-10 02:12:20 +0000699 }
700
kenton@google.comd0580ea2008-11-07 02:07:18 +0000701 // All the fields.
temporal779f61c2008-08-13 03:15:00 +0000702 for (int i = 0; i < type->field_count(); i++) {
kenton@google.comd0580ea2008-11-07 02:07:18 +0000703 // Make sure field is aligned to avoid bus errors.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000704 // Oneof fields do not use any space.
705 if (!type->field(i)->containing_oneof()) {
706 int field_size = FieldSpaceUsed(type->field(i));
707 size = AlignTo(size, min(kSafeAlignment, field_size));
708 offsets[i] = size;
709 size += field_size;
710 }
711 }
712
713 // The oneofs.
714 for (int i = 0; i < type->oneof_decl_count(); i++) {
715 size = AlignTo(size, kSafeAlignment);
716 offsets[type->field_count() + i] = size;
717 size += kMaxOneofUnionSize;
temporal779f61c2008-08-13 03:15:00 +0000718 }
temporal40ee5512008-07-10 02:12:20 +0000719
temporal779f61c2008-08-13 03:15:00 +0000720 // Add the UnknownFieldSet to the end.
721 size = AlignOffset(size);
722 type_info->unknown_fields_offset = size;
723 size += sizeof(UnknownFieldSet);
724
725 // Align the final size to make sure no clever allocators think that
726 // alignment is not necessary.
727 size = AlignOffset(size);
728 type_info->size = size;
729
730 // Allocate the prototype.
731 void* base = operator new(size);
temporal40ee5512008-07-10 02:12:20 +0000732 memset(base, 0, size);
Feng Xiaoeee38b02015-08-22 18:25:48 -0700733 // The prototype in type_info has to be set before creating the prototype
734 // instance on memory. e.g., message Foo { map<int32, Foo> a = 1; }. When
735 // creating prototype for Foo, prototype of the map entry will also be
736 // created, which needs the address of the prototype of Foo (the value in
737 // map). To break the cyclic dependency, we have to assgin the address of
738 // prototype into type_info first.
739 type_info->prototype = static_cast<DynamicMessage*>(base);
temporal779f61c2008-08-13 03:15:00 +0000740 DynamicMessage* prototype = new(base) DynamicMessage(type_info);
temporal40ee5512008-07-10 02:12:20 +0000741
temporal779f61c2008-08-13 03:15:00 +0000742 // Construct the reflection object.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000743 if (type->oneof_decl_count() > 0) {
744 // Compute the size of default oneof instance and offsets of default
745 // oneof fields.
746 int oneof_size = 0;
747 for (int i = 0; i < type->oneof_decl_count(); i++) {
748 for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
749 const FieldDescriptor* field = type->oneof_decl(i)->field(j);
750 int field_size = OneofFieldSpaceUsed(field);
751 oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size));
752 offsets[field->index()] = oneof_size;
753 oneof_size += field_size;
754 }
755 }
756 // Construct default oneof instance.
757 type_info->default_oneof_instance = ::operator new(oneof_size);
758 ConstructDefaultOneofInstance(type_info->type,
759 type_info->offsets.get(),
760 type_info->default_oneof_instance);
761 type_info->reflection.reset(
762 new GeneratedMessageReflection(
763 type_info->type,
764 type_info->prototype,
765 type_info->offsets.get(),
766 type_info->has_bits_offset,
767 type_info->unknown_fields_offset,
768 type_info->extensions_offset,
769 type_info->default_oneof_instance,
770 type_info->oneof_case_offset,
771 type_info->pool,
772 this,
Feng Xiao6ef984a2014-11-10 17:34:54 -0800773 type_info->size,
Feng Xiaoc25d9fe2014-11-26 16:15:29 -0800774 -1 /* arena_offset */,
775 type_info->is_default_instance_offset));
jieluo@google.com4de8f552014-07-18 00:47:59 +0000776 } else {
777 type_info->reflection.reset(
778 new GeneratedMessageReflection(
779 type_info->type,
780 type_info->prototype,
781 type_info->offsets.get(),
782 type_info->has_bits_offset,
783 type_info->unknown_fields_offset,
784 type_info->extensions_offset,
785 type_info->pool,
786 this,
Feng Xiao6ef984a2014-11-10 17:34:54 -0800787 type_info->size,
Feng Xiaoc25d9fe2014-11-26 16:15:29 -0800788 -1 /* arena_offset */,
789 type_info->is_default_instance_offset));
jieluo@google.com4de8f552014-07-18 00:47:59 +0000790 }
temporal779f61c2008-08-13 03:15:00 +0000791 // Cross link prototypes.
792 prototype->CrossLinkPrototypes();
793
794 return prototype;
temporal40ee5512008-07-10 02:12:20 +0000795}
796
jieluo@google.com4de8f552014-07-18 00:47:59 +0000797void DynamicMessageFactory::ConstructDefaultOneofInstance(
798 const Descriptor* type,
799 const int offsets[],
800 void* default_oneof_instance) {
801 for (int i = 0; i < type->oneof_decl_count(); i++) {
802 for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
803 const FieldDescriptor* field = type->oneof_decl(i)->field(j);
804 void* field_ptr = reinterpret_cast<uint8*>(
805 default_oneof_instance) + offsets[field->index()];
806 switch (field->cpp_type()) {
807#define HANDLE_TYPE(CPPTYPE, TYPE) \
808 case FieldDescriptor::CPPTYPE_##CPPTYPE: \
809 new(field_ptr) TYPE(field->default_value_##TYPE()); \
810 break;
811
812 HANDLE_TYPE(INT32 , int32 );
813 HANDLE_TYPE(INT64 , int64 );
814 HANDLE_TYPE(UINT32, uint32);
815 HANDLE_TYPE(UINT64, uint64);
816 HANDLE_TYPE(DOUBLE, double);
817 HANDLE_TYPE(FLOAT , float );
818 HANDLE_TYPE(BOOL , bool );
819#undef HANDLE_TYPE
820
821 case FieldDescriptor::CPPTYPE_ENUM:
822 new(field_ptr) int(field->default_value_enum()->number());
823 break;
824 case FieldDescriptor::CPPTYPE_STRING:
825 switch (field->options().ctype()) {
826 default:
827 case FieldOptions::STRING:
Feng Xiao6ef984a2014-11-10 17:34:54 -0800828 ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
829 asp->UnsafeSetDefault(&field->default_value_string());
jieluo@google.com4de8f552014-07-18 00:47:59 +0000830 break;
831 }
832 break;
833
834 case FieldDescriptor::CPPTYPE_MESSAGE: {
835 new(field_ptr) Message*(NULL);
836 break;
837 }
838 }
839 }
840 }
841}
842
843void DynamicMessageFactory::DeleteDefaultOneofInstance(
844 const Descriptor* type,
845 const int offsets[],
846 void* default_oneof_instance) {
847 for (int i = 0; i < type->oneof_decl_count(); i++) {
848 for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
849 const FieldDescriptor* field = type->oneof_decl(i)->field(j);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000850 if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
851 switch (field->options().ctype()) {
852 default:
853 case FieldOptions::STRING:
854 break;
855 }
856 }
857 }
858 }
859}
860
temporal40ee5512008-07-10 02:12:20 +0000861} // namespace protobuf
temporal40ee5512008-07-10 02:12:20 +0000862} // namespace google