| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/trace_event/v2/append_only_proto_message.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/trace_event/v2/proto_utils.h" |
| 9 #include "build/build_config.h" |
| 10 |
| 11 |
| 12 // TODO size vs length naming inconsistency. |
| 13 // TODO bitmap for mandatory / optional fields |
| 14 |
| 15 namespace { |
| 16 |
| 17 enum { |
| 18 PROTO_VARINT = 0, |
| 19 PROTO_FIXED_64BIT = 1, |
| 20 PROTO_LENGTH_LIMITED = 2, |
| 21 PROTO_FIXED_32BIT = 5, |
| 22 }; |
| 23 |
| 24 } // namespace |
| 25 |
| 26 namespace base { |
| 27 namespace trace_event { |
| 28 namespace v2 { |
| 29 |
| 30 // static |
| 31 const size_t AppendOnlyProtoMessage::kMaxMessageLength = |
| 32 1ul << (AppendOnlyProtoMessage::kMaxMessageLengthFieldSize * 7); |
| 33 |
| 34 AppendOnlyProtoMessage::AppendOnlyProtoMessage() |
| 35 : buffer_(nullptr), |
| 36 size_(0), |
| 37 write_size_field_on_finalization_(false), |
| 38 size_already_written_(0), |
| 39 current_nested_message_(nullptr), |
| 40 sealed_(false) {} |
| 41 |
| 42 AppendOnlyProtoMessage::~AppendOnlyProtoMessage() {} |
| 43 |
| 44 size_t AppendOnlyProtoMessage::Finalize() { |
| 45 if (sealed_) |
| 46 return size_; |
| 47 |
| 48 if (current_nested_message_) |
| 49 EndNestedMessage(); |
| 50 |
| 51 if (write_size_field_on_finalization_) { |
| 52 // Write the length of the nested message a posteriori, forcing a 32-bit |
| 53 // leading-zero varint. This is a slight bending of the proto encoding, |
| 54 // essentially size = 7 gets encoded as 0x87,0x80,0x80,0x00 instead of 0x07. |
| 55 // The problem here is that we cannot know upfront how big the nested messag
e |
| 56 // was. There is precedent for this (TODO link internal bug). |
| 57 // TODO optimization: upon beginmessage we could get a promise of the max |
| 58 // length of the submessage to avoid wasting 2 bytes if we know upfront that |
| 59 // the message is going to be always < 64k. |
| 60 DCHECK_LT(size_, kMaxMessageLength); |
| 61 uint8_t word[kMaxMessageLengthFieldSize]; |
| 62 ProtoUtils::EncodeRedundantVarIntUnsigned(size_ - size_already_written_, |
| 63 kMaxMessageLengthFieldSize, |
| 64 word); |
| 65 buffer_->WriteReservedBytes(size_field_, word, kMaxMessageLengthFieldSize); |
| 66 } |
| 67 |
| 68 // No more changes allowed. |
| 69 sealed_ = true; |
| 70 return size_; |
| 71 } |
| 72 |
| 73 void AppendOnlyProtoMessage::WriteToBuffer(const uint8_t* src, size_t size) { |
| 74 buffer_->WriteBytes(src, size); |
| 75 size_ += size; |
| 76 } |
| 77 |
| 78 void AppendOnlyProtoMessage::AppendVarIntSigned(uint32_t field_id, |
| 79 int64_t value) { |
| 80 // TODO ZigZag encoding. |
| 81 AppendVarIntUnsigned(field_id, value); // HACK, this is not supporting signed
. |
| 82 } |
| 83 |
| 84 void AppendOnlyProtoMessage::AppendVarIntUnsigned(uint32_t field_id, |
| 85 uint64_t value) { |
| 86 if (current_nested_message_) |
| 87 EndNestedMessage(); |
| 88 |
| 89 uint8_t data[32]; |
| 90 size_t data_size; |
| 91 data_size = ProtoUtils::EncodeVarIntUnsigned(ProtoUtils::GetVarIntFieldHeader(
field_id), data); |
| 92 data_size += ProtoUtils::EncodeVarIntUnsigned(value, &data[data_size]); |
| 93 WriteToBuffer(data, data_size); |
| 94 } |
| 95 |
| 96 void AppendOnlyProtoMessage::AppendFloat(uint32_t field_id, float value) { |
| 97 if (current_nested_message_) |
| 98 EndNestedMessage(); |
| 99 |
| 100 uint8_t data[32]; |
| 101 size_t data_size; |
| 102 data_size = ProtoUtils::EncodeVarIntUnsigned(ProtoUtils::GetFixed32FieldHeader
(field_id), data); |
| 103 |
| 104 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 105 memcpy(&data[data_size], &value, sizeof(value)); |
| 106 #else |
| 107 #error big-endian encoding not implemented. |
| 108 #endif |
| 109 |
| 110 data_size += sizeof(value); |
| 111 WriteToBuffer(data, data_size); |
| 112 } |
| 113 |
| 114 void AppendOnlyProtoMessage::AppendDouble(uint32_t field_id, double value) { |
| 115 if (current_nested_message_) |
| 116 EndNestedMessage(); |
| 117 |
| 118 uint8_t data[32]; |
| 119 size_t data_size; |
| 120 data_size = ProtoUtils::EncodeVarIntUnsigned(ProtoUtils::GetFixed64FieldHeader
(field_id), data); |
| 121 memcpy(&data[data_size], &value, sizeof(value)); |
| 122 data_size += sizeof(value); |
| 123 WriteToBuffer(data, data_size); |
| 124 } |
| 125 |
| 126 void AppendOnlyProtoMessage::AppendString(uint32_t field_id, const char* str) { |
| 127 if (current_nested_message_) |
| 128 EndNestedMessage(); |
| 129 |
| 130 const size_t str_length = strlen(str); |
| 131 AppendBytes(field_id, str, str_length); |
| 132 } |
| 133 |
| 134 void AppendOnlyProtoMessage::AppendBytes(uint32_t field_id, const void* value, s
ize_t size) { |
| 135 if (current_nested_message_) |
| 136 EndNestedMessage(); |
| 137 |
| 138 // Write the proto preamble (field id, type and length of the buffer). |
| 139 uint8_t data[32]; |
| 140 size_t data_size; |
| 141 data_size = ProtoUtils::EncodeVarIntUnsigned(ProtoUtils::GetLengthLimitedField
Header(field_id), data); |
| 142 data_size += ProtoUtils::EncodeVarIntUnsigned(size, &data[data_size]); |
| 143 WriteToBuffer(data, data_size); |
| 144 |
| 145 // Write the actual buffer. |
| 146 WriteToBuffer(reinterpret_cast<const uint8_t*>(value), size); |
| 147 } |
| 148 |
| 149 void AppendOnlyProtoMessage::BeginNestedMessage( |
| 150 uint32_t field_id, |
| 151 AppendOnlyProtoMessage* message) { |
| 152 if (current_nested_message_) |
| 153 EndNestedMessage(); |
| 154 |
| 155 message->set_buffer_writer(buffer_writer()); |
| 156 uint8_t data[32]; |
| 157 size_t data_size; |
| 158 data_size = ProtoUtils::EncodeVarIntUnsigned(ProtoUtils::GetLengthLimitedField
Header(field_id), data); |
| 159 WriteToBuffer(data, data_size); |
| 160 |
| 161 // The length of the nested message cannot be known upfront. So right now |
| 162 // just reserve the bytes to encode the size after the nested message is done. |
| 163 message->set_write_size_field_on_finalization(buffer_->ReserveBytes(kMaxMessag
eLengthFieldSize)); |
| 164 current_nested_message_ = message; |
| 165 } |
| 166 |
| 167 void AppendOnlyProtoMessage::EndNestedMessage() { |
| 168 size_ += current_nested_message_->Finalize(); |
| 169 current_nested_message_ = nullptr; |
| 170 } |
| 171 |
| 172 } // namespace v2 |
| 173 } // namespace trace_event |
| 174 } // namespace base |
| OLD | NEW |