blob: 555e1282bced430e84c0e15a2e8b78d801294702 [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Hector Dearmane1e56b62018-02-21 19:11:58 +000017#ifndef INCLUDE_PERFETTO_PROTOZERO_MESSAGE_H_
18#define INCLUDE_PERFETTO_PROTOZERO_MESSAGE_H_
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000019
20#include <assert.h>
21#include <stdint.h>
22#include <string.h>
23
24#include <type_traits>
25
Oystein Eftevaaga812a942018-03-23 11:52:32 -070026#include "perfetto/base/export.h"
Primiano Tucci3a918872017-12-18 10:53:39 +010027#include "perfetto/base/logging.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000028#include "perfetto/protozero/contiguous_memory_range.h"
29#include "perfetto/protozero/proto_utils.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000030#include "perfetto/protozero/scattered_stream_writer.h"
31
Florian Mayer60d1e132018-01-26 15:00:52 +000032namespace perfetto {
33namespace shm_fuzz {
34class FakeProducer;
35} // namespace shm_fuzz
36} // namespace perfetto
37
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000038namespace protozero {
39
Hector Dearmanaaa4c192018-02-19 11:57:35 +000040class MessageHandleBase;
Florian Mayer8a8044f2018-01-11 16:03:09 +000041
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000042// Base class extended by the proto C++ stubs generated by the ProtoZero
43// compiler. This class provides the minimal runtime required to support
44// append-only operations and is designed for performance. None of the methods
45// require any dynamic memory allocation.
Oystein Eftevaaga812a942018-03-23 11:52:32 -070046class PERFETTO_EXPORT Message {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000047 public:
Hector Dearmanaaa4c192018-02-19 11:57:35 +000048 friend class MessageHandleBase;
Florian Mayer60d1e132018-01-26 15:00:52 +000049 // Grant end_to_end_shared_memory_fuzzer access in order to write raw
50 // bytes into the buffer.
51 friend class ::perfetto::shm_fuzz::FakeProducer;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000052 // Adjust the |nested_messages_arena_| size when changing this, or the
53 // static_assert in the .cc file will bark.
54 static constexpr uint32_t kMaxNestingDepth = 8;
55
Hector Dearmanaaa4c192018-02-19 11:57:35 +000056 // Ctor and Dtor of Message are never called, with the exeception
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000057 // of root (non-nested) messages. Nested messages are allocated via placement
58 // new in the |nested_messages_arena_| and implictly destroyed when the arena
59 // of the root message goes away. This is fine as long as all the fields are
60 // PODs, which is checked by the static_assert in the ctor (see the Reset()
61 // method in the .cc file).
Hector Dearmanaaa4c192018-02-19 11:57:35 +000062 Message() = default;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000063
64 // Clears up the state, allowing the message to be reused as a fresh one.
65 void Reset(ScatteredStreamWriter*);
66
67 // Commits all the changes to the buffer (backfills the size field of this and
68 // all nested messages) and seals the message. Returns the size of the message
69 // (and all nested sub-messages), without taking into account any chunking.
70 // Finalize is idempotent and can be called several times w/o side effects.
Primiano Tucci3a918872017-12-18 10:53:39 +010071 uint32_t Finalize();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000072
73 // Optional. If is_valid() == true, the corresponding memory region (its
74 // length == proto_utils::kMessageLengthFieldSize) is backfilled with the size
Primiano Tucci3a918872017-12-18 10:53:39 +010075 // of this message (minus |size_already_written| below). This is the mechanism
76 // used by messages to backfill their corresponding size field in the parent
77 // message.
78 uint8_t* size_field() const { return size_field_; }
79 void set_size_field(uint8_t* size_field) { size_field_ = size_field; }
80
81 // This is to deal with case of backfilling the size of a root (non-nested)
82 // message which is split into multiple chunks. Upon finalization only the
83 // partial size that lies in the last chunk has to be backfilled.
84 void inc_size_already_written(uint32_t sz) { size_already_written_ += sz; }
85
Hector Dearmanaaa4c192018-02-19 11:57:35 +000086 Message* nested_message() { return nested_message_; }
Primiano Tucci3a918872017-12-18 10:53:39 +010087
88 bool is_finalized() const { return finalized_; }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000089
Florian Mayer8a8044f2018-01-11 16:03:09 +000090#if PERFETTO_DCHECK_IS_ON()
Hector Dearmanaaa4c192018-02-19 11:57:35 +000091 void set_handle(MessageHandleBase* handle) { handle_ = handle; }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000092#endif
93
94 // Proto types: uint64, uint32, int64, int32, bool, enum.
95 template <typename T>
96 void AppendVarInt(uint32_t field_id, T value) {
97 if (nested_message_)
98 EndNestedMessage();
99
100 uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
101 uint8_t* pos = buffer;
102
103 pos = proto_utils::WriteVarInt(proto_utils::MakeTagVarInt(field_id), pos);
104 // WriteVarInt encodes signed values in two's complement form.
105 pos = proto_utils::WriteVarInt(value, pos);
106 WriteToStream(buffer, pos);
107 }
108
109 // Proto types: sint64, sint32.
110 template <typename T>
111 void AppendSignedVarInt(uint32_t field_id, T value) {
112 AppendVarInt(field_id, proto_utils::ZigZagEncode(value));
113 }
114
115 // Proto types: bool, enum (small).
116 // Faster version of AppendVarInt for tiny numbers.
117 void AppendTinyVarInt(uint32_t field_id, int32_t value) {
Primiano Tucci3a918872017-12-18 10:53:39 +0100118 PERFETTO_DCHECK(0 <= value && value < 0x80);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000119 if (nested_message_)
120 EndNestedMessage();
121
122 uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
123 uint8_t* pos = buffer;
124 // MakeTagVarInt gets super optimized here for constexpr.
125 pos = proto_utils::WriteVarInt(proto_utils::MakeTagVarInt(field_id), pos);
126 *pos++ = static_cast<uint8_t>(value);
127 WriteToStream(buffer, pos);
128 }
129
130 // Proto types: fixed64, sfixed64, fixed32, sfixed32, double, float.
131 template <typename T>
132 void AppendFixed(uint32_t field_id, T value) {
133 if (nested_message_)
134 EndNestedMessage();
135
136 uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
137 uint8_t* pos = buffer;
138
139 pos = proto_utils::WriteVarInt(proto_utils::MakeTagFixed<T>(field_id), pos);
140 memcpy(pos, &value, sizeof(T));
141 pos += sizeof(T);
142 // TODO: Optimize memcpy performance, see http://crbug.com/624311 .
143 WriteToStream(buffer, pos);
144 }
145
146 void AppendString(uint32_t field_id, const char* str);
147 void AppendBytes(uint32_t field_id, const void* value, size_t size);
148
149 // Begins a nested message, using the static storage provided by the parent
150 // class (see comment in |nested_messages_arena_|). The nested message ends
151 // either when Finalize() is called or when any other Append* method is called
152 // in the parent class.
153 // The template argument T is supposed to be a stub class auto generated from
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000154 // a .proto, hence a subclass of Message.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000155 template <class T>
156 T* BeginNestedMessage(uint32_t field_id) {
157 // This is to prevent subclasses (which should be autogenerated, though), to
158 // introduce extra state fields (which wouldn't be initialized by Reset()).
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000159 static_assert(std::is_base_of<Message, T>::value,
160 "T must be a subclass of Message");
161 static_assert(sizeof(T) == sizeof(Message),
162 "Message subclasses cannot introduce extra state.");
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000163 T* message = reinterpret_cast<T*>(nested_messages_arena_);
164 BeginNestedMessageInternal(field_id, message);
165 return message;
166 }
167
168 private:
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000169 Message(const Message&) = delete;
170 Message& operator=(const Message&) = delete;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000171
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000172 void BeginNestedMessageInternal(uint32_t field_id, Message*);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000173
174 // Called by Finalize and Append* methods.
175 void EndNestedMessage();
176
177 void WriteToStream(const uint8_t* src_begin, const uint8_t* src_end) {
Primiano Tucci3a918872017-12-18 10:53:39 +0100178 PERFETTO_DCHECK(!finalized_);
Hector Dearman8bf3e252018-01-26 11:33:58 +0000179 PERFETTO_DCHECK(src_begin <= src_end);
Primiano Tucci3a918872017-12-18 10:53:39 +0100180 const uint32_t size = static_cast<uint32_t>(src_end - src_begin);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000181 stream_writer_->WriteBytes(src_begin, size);
182 size_ += size;
183 }
184
185 // Only POD fields are allowed. This class's dtor is never called.
186 // See the comment on the static_assert in the the corresponding .cc file.
187
188 // The stream writer interface used for the serialization.
189 ScatteredStreamWriter* stream_writer_;
190
Primiano Tucci3a918872017-12-18 10:53:39 +0100191 uint8_t* size_field_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000192
Primiano Tucci3a918872017-12-18 10:53:39 +0100193 // Keeps track of the size of the current message.
194 uint32_t size_;
195
196 // See comment for inc_size_already_written().
197 uint32_t size_already_written_;
198
199 // When true, no more changes to the message are allowed. This is to DCHECK
200 // attempts of writing to a message which has been Finalize()-d.
201 bool finalized_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000202
203 // Used to detect attemps to create messages with a nesting level >
204 // kMaxNestingDepth. |nesting_depth_| == 0 for root (non-nested) messages.
205 uint8_t nesting_depth_;
206
Florian Mayer8a8044f2018-01-11 16:03:09 +0000207#if PERFETTO_DCHECK_IS_ON()
208 // Current generation of message. Incremented on Reset.
209 // Used to detect stale handles.
210 uint32_t generation_;
211
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000212 MessageHandleBase* handle_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000213#endif
214
215 // Pointer to the last child message created through BeginNestedMessage(), if
216 // any, nullptr otherwise. There is no need to keep track of more than one
217 // message per nesting level as the proto-zero API contract mandates that
218 // nested fields can be filled only in a stacked fashion. In other words,
219 // nested messages are finalized and sealed when any other field is set in the
220 // parent message (or the parent message itself is finalized) and cannot be
221 // accessed anymore afterwards.
Primiano Tucci3a918872017-12-18 10:53:39 +0100222 // TODO(primiano): optimization: I think that nested_message_, when non-null.
223 // will always be @ (this) + offsetof(nested_messages_arena_).
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000224 Message* nested_message_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000225
226 // The root message owns the storage for all its nested messages, up to a max
227 // of kMaxNestingDepth levels (see the .cc file). Note that the boundaries of
228 // the arena are meaningful only for the root message.
229 // Unfortunately we cannot put the sizeof() math here because we cannot sizeof
230 // the current class in a header. However the .cc file has a static_assert
231 // that guarantees that (see the Reset() method in the .cc file).
232 alignas(sizeof(void*)) uint8_t nested_messages_arena_[512];
233
234 // DO NOT add any fields below |nested_messages_arena_|. The memory layout of
235 // nested messages would overflow the storage allocated by the root message.
236};
237
238} // namespace protozero
239
Hector Dearmane1e56b62018-02-21 19:11:58 +0000240#endif // INCLUDE_PERFETTO_PROTOZERO_MESSAGE_H_