1 /*
2  * Copyright (C) 2020 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 
17 #include "perfetto/protozero/message_arena.h"
18 
19 #include <atomic>
20 #include <type_traits>
21 
22 #include "perfetto/base/logging.h"
23 #include "perfetto/protozero/message_handle.h"
24 
25 namespace protozero {
26 
MessageArena()27 MessageArena::MessageArena() {
28   // The code below assumes that there is always at least one block.
29   blocks_.emplace_front();
30   static_assert(std::alignment_of<decltype(blocks_.back().storage[0])>::value >=
31                     alignof(Message),
32                 "MessageArea's storage is not properly aligned");
33 }
34 
35 MessageArena::~MessageArena() = default;
36 
NewMessage()37 Message* MessageArena::NewMessage() {
38   PERFETTO_DCHECK(!blocks_.empty());  // Should never become empty.
39 
40   Block* block = &blocks_.back();
41   if (PERFETTO_UNLIKELY(block->entries >= Block::kCapacity)) {
42     blocks_.emplace_back();
43     block = &blocks_.back();
44   }
45   const auto idx = block->entries++;
46   void* storage = &block->storage[idx];
47   PERFETTO_ASAN_UNPOISON(storage, sizeof(Message));
48   return new (storage) Message();
49 }
50 
DeleteLastMessageInternal()51 void MessageArena::DeleteLastMessageInternal() {
52   PERFETTO_DCHECK(!blocks_.empty());  // Should never be empty, see below.
53   Block* block = &blocks_.back();
54   PERFETTO_DCHECK(block->entries > 0);
55 
56   // This is the reason why there is no ~Message() call here.
57   // MessageArea::Reset() (see header) also relies on dtor being trivial.
58   static_assert(std::is_trivially_destructible<Message>::value,
59                 "Message must be trivially destructible");
60 
61   --block->entries;
62   PERFETTO_ASAN_POISON(&block->storage[block->entries], sizeof(Message));
63 
64   // Don't remove the first block to avoid malloc/free calls when the root
65   // message is reset. Hitting the allocator all the times is a waste of time.
66   if (block->entries == 0 && blocks_.size() > 1) {
67     blocks_.pop_back();
68   }
69 }
70 
71 }  // namespace protozero
72