blob: 843f76de203ad8e9e5c6c50ec571671a57abe449 [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#include "perfetto/protozero/message.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000018
19#include <type_traits>
20
21#include "perfetto/base/logging.h"
Hector Dearmane1e56b62018-02-21 19:11:58 +000022#include "perfetto/protozero/message_handle.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000023
24#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
25// The memcpy() for float and double below needs to be adjusted if we want to
26// support big endian CPUs. There doesn't seem to be a compelling need today.
27#error Unimplemented for big endian archs.
28#endif
29
30namespace protozero {
31
32// static
Hector Dearmanaaa4c192018-02-19 11:57:35 +000033constexpr uint32_t Message::kMaxNestingDepth;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000034
35// Do NOT put any code in the constructor or use default initialization.
36// Use the Reset() method below instead. See the header for the reason why.
37
38// This method is called to initialize both root and nested messages.
Hector Dearmanaaa4c192018-02-19 11:57:35 +000039void Message::Reset(ScatteredStreamWriter* stream_writer) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000040// Older versions of libstdcxx don't have is_trivially_constructible.
41#if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20170516
Hector Dearmanaaa4c192018-02-19 11:57:35 +000042 static_assert(std::is_trivially_constructible<Message>::value,
43 "Message must be trivially constructible");
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000044#endif
45
Hector Dearmanaaa4c192018-02-19 11:57:35 +000046 static_assert(std::is_trivially_destructible<Message>::value,
47 "Message must be trivially destructible");
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000048
49 static_assert(
Hector Dearmanaaa4c192018-02-19 11:57:35 +000050 sizeof(Message::nested_messages_arena_) >=
51 kMaxNestingDepth *
52 (sizeof(Message) - sizeof(Message::nested_messages_arena_)),
53 "Message::nested_messages_arena_ is too small");
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000054
55 stream_writer_ = stream_writer;
56 size_ = 0;
Primiano Tucci3a918872017-12-18 10:53:39 +010057 size_field_ = nullptr;
58 size_already_written_ = 0;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000059 nested_message_ = nullptr;
60 nesting_depth_ = 0;
Primiano Tucci3a918872017-12-18 10:53:39 +010061 finalized_ = false;
Florian Mayer8a8044f2018-01-11 16:03:09 +000062#if PERFETTO_DCHECK_IS_ON()
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000063 handle_ = nullptr;
Florian Mayer8a8044f2018-01-11 16:03:09 +000064 generation_++;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000065#endif
66}
67
Hector Dearmanaaa4c192018-02-19 11:57:35 +000068void Message::AppendString(uint32_t field_id, const char* str) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000069 AppendBytes(field_id, str, strlen(str));
70}
71
Hector Dearmanaaa4c192018-02-19 11:57:35 +000072void Message::AppendBytes(uint32_t field_id, const void* src, size_t size) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000073 if (nested_message_)
74 EndNestedMessage();
75
76 PERFETTO_DCHECK(size < proto_utils::kMaxMessageLength);
77 // Write the proto preamble (field id, type and length of the field).
78 uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
79 uint8_t* pos = buffer;
80 pos = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
81 pos);
82 pos = proto_utils::WriteVarInt(static_cast<uint32_t>(size), pos);
83 WriteToStream(buffer, pos);
84
85 const uint8_t* src_u8 = reinterpret_cast<const uint8_t*>(src);
86 WriteToStream(src_u8, src_u8 + size);
87}
88
Hector Dearmanaaa4c192018-02-19 11:57:35 +000089uint32_t Message::Finalize() {
Hector Dearman2c1b2d82018-02-06 20:36:24 +000090 if (finalized_)
91 return size_;
92
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000093 if (nested_message_)
94 EndNestedMessage();
95
96 // Write the length of the nested message a posteriori, using a leading-zero
97 // redundant varint encoding.
Primiano Tucci3a918872017-12-18 10:53:39 +010098 if (size_field_) {
99 PERFETTO_DCHECK(!finalized_);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000100 PERFETTO_DCHECK(size_ < proto_utils::kMaxMessageLength);
Primiano Tucci3a918872017-12-18 10:53:39 +0100101 PERFETTO_DCHECK(size_ >= size_already_written_);
102 proto_utils::WriteRedundantVarInt(size_ - size_already_written_,
103 size_field_);
104 size_field_ = nullptr;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000105 }
106
Primiano Tucci3a918872017-12-18 10:53:39 +0100107 finalized_ = true;
Florian Mayer8a8044f2018-01-11 16:03:09 +0000108#if PERFETTO_DCHECK_IS_ON()
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000109 if (handle_)
110 handle_->reset_message();
111#endif
112
113 return size_;
114}
115
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000116void Message::BeginNestedMessageInternal(uint32_t field_id, Message* message) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000117 if (nested_message_)
118 EndNestedMessage();
119
120 // Write the proto preamble for the nested message.
121 uint8_t data[proto_utils::kMaxTagEncodedSize];
122 uint8_t* data_end = proto_utils::WriteVarInt(
123 proto_utils::MakeTagLengthDelimited(field_id), data);
124 WriteToStream(data, data_end);
125
126 message->Reset(stream_writer_);
127 PERFETTO_CHECK(nesting_depth_ < kMaxNestingDepth);
128 message->nesting_depth_ = nesting_depth_ + 1;
129
130 // The length of the nested message cannot be known upfront. So right now
131 // just reserve the bytes to encode the size after the nested message is done.
132 message->set_size_field(
133 stream_writer_->ReserveBytes(proto_utils::kMessageLengthFieldSize));
134 size_ += proto_utils::kMessageLengthFieldSize;
135 nested_message_ = message;
136}
137
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000138void Message::EndNestedMessage() {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000139 size_ += nested_message_->Finalize();
140 nested_message_ = nullptr;
141}
142
143} // namespace protozero