1 // 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. 7 // QUICHE_DCHECK's if an allocation out of the arena ever fails in debug builds; 8 // falls back to 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 15 #include "absl/base/optimization.h" 16 #include "quiche/quic/core/quic_arena_scoped_ptr.h" 17 #include "quiche/quic/core/quic_types.h" 18 #include "quiche/quic/platform/api/quic_bug_tracker.h" 19 #include "quiche/quic/platform/api/quic_logging.h" 20 21 namespace quic { 22 23 template <uint32_t ArenaSize> 24 class QUICHE_EXPORT QuicOneBlockArena { 25 static const uint32_t kMaxAlign = 8; 26 27 public: QuicOneBlockArena()28 QuicOneBlockArena() : offset_(0) {} 29 QuicOneBlockArena(const QuicOneBlockArena&) = delete; 30 QuicOneBlockArena& operator=(const QuicOneBlockArena&) = delete; 31 32 // Instantiates an object of type |T| with |args|. |args| are perfectly 33 // forwarded to |T|'s constructor. The returned pointer's lifetime is 34 // controlled by QuicArenaScopedPtr. 35 template <typename T, typename... Args> New(Args &&...args)36 QuicArenaScopedPtr<T> New(Args&&... args) { 37 QUICHE_DCHECK_LT(AlignedSize<T>(), ArenaSize) 38 << "Object is too large for the arena."; 39 static_assert(alignof(T) > 1, 40 "Objects added to the arena must be at least 2B aligned."); 41 if (ABSL_PREDICT_FALSE(offset_ > ArenaSize - AlignedSize<T>())) { 42 QUIC_BUG(quic_bug_10593_1) 43 << "Ran out of space in QuicOneBlockArena at " << this 44 << ", max size was " << ArenaSize << ", failing request was " 45 << AlignedSize<T>() << ", end of arena was " << offset_; 46 return QuicArenaScopedPtr<T>(new T(std::forward<Args>(args)...)); 47 } 48 49 void* buf = &storage_[offset_]; 50 new (buf) T(std::forward<Args>(args)...); 51 offset_ += AlignedSize<T>(); 52 return QuicArenaScopedPtr<T>(buf, 53 QuicArenaScopedPtr<T>::ConstructFrom::kArena); 54 } 55 56 private: 57 // Returns the size of |T| aligned up to |kMaxAlign|. 58 template <typename T> AlignedSize()59 static inline uint32_t AlignedSize() { 60 return ((sizeof(T) + (kMaxAlign - 1)) / kMaxAlign) * kMaxAlign; 61 } 62 63 // Actual storage. 64 // Subtle/annoying: the value '8' must be coded explicitly into the alignment 65 // declaration for MSVC. 66 alignas(8) char storage_[ArenaSize]; 67 // Current offset into the storage. 68 uint32_t offset_; 69 }; 70 71 // QuicConnections currently use around 1KB of polymorphic types which would 72 // ordinarily be on the heap. Instead, store them inline in an arena. 73 using QuicConnectionArena = QuicOneBlockArena<1380>; 74 75 } // namespace quic 76 77 #endif // QUICHE_QUIC_CORE_QUIC_ONE_BLOCK_ARENA_H_ 78