1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef StackArena_h
8 #define StackArena_h
9 
10 #include "nsError.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/MemoryReporting.h"
13 
14 namespace mozilla {
15 
16 struct StackBlock;
17 struct StackMark;
18 class AutoStackArena;
19 
20 // Private helper class for AutoStackArena.
21 class StackArena {
22  private:
23   friend class AutoStackArena;
24   StackArena();
25   ~StackArena();
26 
27   // Memory management functions.
28   void* Allocate(size_t aSize);
29   void Push();
30   void Pop();
31 
32   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
33 
34   // Our current position in memory.
35   size_t mPos;
36 
37   // A list of memory blocks. Usually there is only one
38   // but if we overrun our stack size we can get more memory.
39   StackBlock* mBlocks;
40 
41   // The current block.
42   StackBlock* mCurBlock;
43 
44   // Our stack of mark where push has been called.
45   StackMark* mMarks;
46 
47   // The current top of the mark list.
48   uint32_t mStackTop;
49 
50   // The size of the mark array.
51   uint32_t mMarkLength;
52 };
53 
54 // Class for stack scoped arena memory allocations.
55 //
56 // Callers who wish to allocate memory whose lifetime corresponds to the
57 // lifetime of a stack-allocated object can use this class.  First,
58 // declare an AutoStackArena object on the stack.  Then all subsequent
59 // calls to Allocate will allocate memory from an arena pool that will
60 // be freed when that variable goes out of scope.  Nesting is allowed.
61 //
62 // Individual allocations cannot exceed StackBlock::MAX_USABLE_SIZE
63 // bytes.
64 //
65 class MOZ_RAII AutoStackArena {
66  public:
AutoStackArena()67   AutoStackArena() : mOwnsStackArena(false) {
68     if (!gStackArena) {
69       gStackArena = new StackArena();
70       mOwnsStackArena = true;
71     }
72     gStackArena->Push();
73   }
74 
~AutoStackArena()75   ~AutoStackArena() {
76     gStackArena->Pop();
77     if (mOwnsStackArena) {
78       delete gStackArena;
79       gStackArena = nullptr;
80     }
81   }
82 
Allocate(size_t aSize)83   static void* Allocate(size_t aSize) { return gStackArena->Allocate(aSize); }
84 
85  private:
86   static StackArena* gStackArena;
87   bool mOwnsStackArena;
88 };
89 
90 }  // namespace mozilla
91 
92 #endif
93