blob: 41842f35963d6cfe398cfc989c468694252bcb94 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 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// An arena that consists of a single inlined block of |ArenaSize|. Useful to
6// avoid repeated calls to malloc/new and to improve memory locality. DCHECK's
7// if an allocation out of the arena ever fails in debug builds; falls back to
8// heap allocation in release builds.
9
10#ifndef QUICHE_QUIC_CORE_QUIC_ONE_BLOCK_ARENA_H_
11#define QUICHE_QUIC_CORE_QUIC_ONE_BLOCK_ARENA_H_
12
13#include <cstdint>
14
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr.h"
16#include "net/third_party/quiche/src/quic/core/quic_types.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
19
20namespace quic {
21
22template <uint32_t ArenaSize>
dschinazif25169a2019-10-23 08:12:18 -070023class QUIC_EXPORT_PRIVATE QuicOneBlockArena {
QUICHE teama6ef0a62019-03-07 20:34:33 -050024 static const uint32_t kMaxAlign = 8;
25
26 public:
27 QuicOneBlockArena();
28 QuicOneBlockArena(const QuicOneBlockArena&) = delete;
29 QuicOneBlockArena& operator=(const QuicOneBlockArena&) = delete;
30
31 // Instantiates an object of type |T| with |args|. |args| are perfectly
32 // forwarded to |T|'s constructor. The returned pointer's lifetime is
33 // controlled by QuicArenaScopedPtr.
34 template <typename T, typename... Args>
35 QuicArenaScopedPtr<T> New(Args&&... args);
36
37 private:
38 // Returns the size of |T| aligned up to |kMaxAlign|.
39 template <typename T>
40 static inline uint32_t AlignedSize() {
41 return ((sizeof(T) + (kMaxAlign - 1)) / kMaxAlign) * kMaxAlign;
42 }
43
44 // Actual storage.
45 // Subtle/annoying: the value '8' must be coded explicitly into the alignment
46 // declaration for MSVC.
47 QUIC_ALIGNED(8) char storage_[ArenaSize];
48 // Current offset into the storage.
49 uint32_t offset_;
50};
51
52template <uint32_t ArenaSize>
53QuicOneBlockArena<ArenaSize>::QuicOneBlockArena() : offset_(0) {}
54
55template <uint32_t ArenaSize>
56template <typename T, typename... Args>
57QuicArenaScopedPtr<T> QuicOneBlockArena<ArenaSize>::New(Args&&... args) {
58 DCHECK_LT(AlignedSize<T>(), ArenaSize)
59 << "Object is too large for the arena.";
60 static_assert(QUIC_ALIGN_OF(T) > 1,
61 "Objects added to the arena must be at least 2B aligned.");
62 if (QUIC_PREDICT_FALSE(offset_ > ArenaSize - AlignedSize<T>())) {
63 QUIC_BUG << "Ran out of space in QuicOneBlockArena at " << this
64 << ", max size was " << ArenaSize << ", failing request was "
65 << AlignedSize<T>() << ", end of arena was " << offset_;
66 return QuicArenaScopedPtr<T>(new T(std::forward<Args>(args)...));
67 }
68
69 void* buf = &storage_[offset_];
70 new (buf) T(std::forward<Args>(args)...);
71 offset_ += AlignedSize<T>();
72 return QuicArenaScopedPtr<T>(buf,
73 QuicArenaScopedPtr<T>::ConstructFrom::kArena);
74}
75
76// QuicConnections currently use around 1KB of polymorphic types which would
77// ordinarily be on the heap. Instead, store them inline in an arena.
78using QuicConnectionArena = QuicOneBlockArena<1024>;
79
80} // namespace quic
81
82#endif // QUICHE_QUIC_CORE_QUIC_ONE_BLOCK_ARENA_H_