12a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci/*
22a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * Copyright (C) 2017 The Android Open Source Project
32a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci *
42a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * Licensed under the Apache License, Version 2.0 (the "License");
52a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * you may not use this file except in compliance with the License.
62a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * You may obtain a copy of the License at
72a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci *
82a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci *      http://www.apache.org/licenses/LICENSE-2.0
92a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci *
102a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * Unless required by applicable law or agreed to in writing, software
112a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * distributed under the License is distributed on an "AS IS" BASIS,
122a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * See the License for the specific language governing permissions and
142a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci * limitations under the License.
152a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci */
162a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
17e1e56b63c369ffe22dc30fb2eeaac1556266d3ecHector Dearman#include "perfetto/protozero/message.h"
182a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
192a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#include <type_traits>
202a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
214f9b6d7b7b2ad7b86e1577a18dc6e2df91b98164Primiano Tucci#include "perfetto/base/logging.h"
22e1e56b63c369ffe22dc30fb2eeaac1556266d3ecHector Dearman#include "perfetto/protozero/message_handle.h"
232a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
242a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
252a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// The memcpy() for float and double below needs to be adjusted if we want to
262a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// support big endian CPUs. There doesn't seem to be a compelling need today.
272a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#error Unimplemented for big endian archs.
282a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#endif
292a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
302a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tuccinamespace protozero {
312a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
322a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// static
33aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanconstexpr uint32_t Message::kMaxNestingDepth;
342a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
352a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// Do NOT put any code in the constructor or use default initialization.
362a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// Use the Reset() method below instead. See the header for the reason why.
372a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
382a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// This method is called to initialize both root and nested messages.
39aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanvoid Message::Reset(ScatteredStreamWriter* stream_writer) {
402a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci// Older versions of libstdcxx don't have is_trivially_constructible.
412a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20170516
42aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman  static_assert(std::is_trivially_constructible<Message>::value,
43aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman                "Message must be trivially constructible");
442a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#endif
452a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
46aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman  static_assert(std::is_trivially_destructible<Message>::value,
47aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman                "Message must be trivially destructible");
482a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
492a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  static_assert(
50aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman      sizeof(Message::nested_messages_arena_) >=
51aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman          kMaxNestingDepth *
52aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman              (sizeof(Message) - sizeof(Message::nested_messages_arena_)),
53aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearman      "Message::nested_messages_arena_ is too small");
542a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
552a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  stream_writer_ = stream_writer;
562a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  size_ = 0;
573a91887aa1252133dc1250459271ad574be69e27Primiano Tucci  size_field_ = nullptr;
583a91887aa1252133dc1250459271ad574be69e27Primiano Tucci  size_already_written_ = 0;
592a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  nested_message_ = nullptr;
602a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  nesting_depth_ = 0;
613a91887aa1252133dc1250459271ad574be69e27Primiano Tucci  finalized_ = false;
628a8044f71ef345f8c41d4e566461db4454d7a933Florian Mayer#if PERFETTO_DCHECK_IS_ON()
632a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  handle_ = nullptr;
648a8044f71ef345f8c41d4e566461db4454d7a933Florian Mayer  generation_++;
652a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#endif
662a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}
672a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
68aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanvoid Message::AppendString(uint32_t field_id, const char* str) {
692a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  AppendBytes(field_id, str, strlen(str));
702a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}
712a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
72aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanvoid Message::AppendBytes(uint32_t field_id, const void* src, size_t size) {
732a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  if (nested_message_)
742a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci    EndNestedMessage();
752a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
76d7d1be012aea4ed5229a74b22c588ca8d7d527f4Primiano Tucci  PERFETTO_DCHECK(size < proto_utils::kMaxMessageLength);
772a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  // Write the proto preamble (field id, type and length of the field).
782a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
792a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  uint8_t* pos = buffer;
802a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  pos = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
812a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci                                 pos);
822a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  pos = proto_utils::WriteVarInt(static_cast<uint32_t>(size), pos);
832a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  WriteToStream(buffer, pos);
842a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
852a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  const uint8_t* src_u8 = reinterpret_cast<const uint8_t*>(src);
862a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  WriteToStream(src_u8, src_u8 + size);
872a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}
882a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
89aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanuint32_t Message::Finalize() {
902c1b2d8098a0f4492fae12739786ef950875f209Hector Dearman  if (finalized_)
912c1b2d8098a0f4492fae12739786ef950875f209Hector Dearman    return size_;
922c1b2d8098a0f4492fae12739786ef950875f209Hector Dearman
932a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  if (nested_message_)
942a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci    EndNestedMessage();
952a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
962a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  // Write the length of the nested message a posteriori, using a leading-zero
972a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  // redundant varint encoding.
983a91887aa1252133dc1250459271ad574be69e27Primiano Tucci  if (size_field_) {
993a91887aa1252133dc1250459271ad574be69e27Primiano Tucci    PERFETTO_DCHECK(!finalized_);
100d7d1be012aea4ed5229a74b22c588ca8d7d527f4Primiano Tucci    PERFETTO_DCHECK(size_ < proto_utils::kMaxMessageLength);
1013a91887aa1252133dc1250459271ad574be69e27Primiano Tucci    PERFETTO_DCHECK(size_ >= size_already_written_);
1023a91887aa1252133dc1250459271ad574be69e27Primiano Tucci    proto_utils::WriteRedundantVarInt(size_ - size_already_written_,
1033a91887aa1252133dc1250459271ad574be69e27Primiano Tucci                                      size_field_);
1043a91887aa1252133dc1250459271ad574be69e27Primiano Tucci    size_field_ = nullptr;
1052a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  }
1062a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
1073a91887aa1252133dc1250459271ad574be69e27Primiano Tucci  finalized_ = true;
1088a8044f71ef345f8c41d4e566461db4454d7a933Florian Mayer#if PERFETTO_DCHECK_IS_ON()
1092a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  if (handle_)
1102a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci    handle_->reset_message();
1112a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci#endif
1122a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
1132a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  return size_;
1142a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}
1152a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
116aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanvoid Message::BeginNestedMessageInternal(uint32_t field_id, Message* message) {
1172a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  if (nested_message_)
1182a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci    EndNestedMessage();
1192a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
1202a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  // Write the proto preamble for the nested message.
1212a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  uint8_t data[proto_utils::kMaxTagEncodedSize];
1222a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  uint8_t* data_end = proto_utils::WriteVarInt(
1232a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci      proto_utils::MakeTagLengthDelimited(field_id), data);
1242a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  WriteToStream(data, data_end);
1252a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
1262a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  message->Reset(stream_writer_);
127d7d1be012aea4ed5229a74b22c588ca8d7d527f4Primiano Tucci  PERFETTO_CHECK(nesting_depth_ < kMaxNestingDepth);
1282a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  message->nesting_depth_ = nesting_depth_ + 1;
1292a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
1302a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  // The length of the nested message cannot be known upfront. So right now
1312a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  // just reserve the bytes to encode the size after the nested message is done.
1322a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  message->set_size_field(
1332a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci      stream_writer_->ReserveBytes(proto_utils::kMessageLengthFieldSize));
1342a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  size_ += proto_utils::kMessageLengthFieldSize;
1352a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  nested_message_ = message;
1362a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}
1372a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
138aaa4c1997f110dee086ee93b83bfc7ac11bfc102Hector Dearmanvoid Message::EndNestedMessage() {
1392a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  size_ += nested_message_->Finalize();
1402a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci  nested_message_ = nullptr;
1412a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}
1422a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci
1432a29ac77885d86bcbd878ac7adb1789c9f9cffa4Primiano Tucci}  // namespace protozero
144