1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "StackArena.h"
6 #include "nsAlgorithm.h"
11 // A block of memory that the stack will chop up and hand out.
13 // Subtract sizeof(StackBlock*) to give space for the |mNext| field.
14 static const size_t MAX_USABLE_SIZE
= 4096 - sizeof(StackBlock
*);
17 char mBlock
[MAX_USABLE_SIZE
];
19 // Another block of memory that would only be created if our stack
23 StackBlock() : mNext(nullptr) { }
27 static_assert(sizeof(StackBlock
) == 4096, "StackBlock must be 4096 bytes");
29 // We hold an array of marks. A push pushes a mark on the stack.
32 // The block of memory from which we are currently handing out chunks.
35 // Our current position in the block.
39 StackArena
* AutoStackArena::gStackArena
;
41 StackArena::StackArena()
46 // Allocate our stack memory.
47 mBlocks
= new StackBlock();
54 StackArena::~StackArena()
59 StackBlock
* toDelete
= mBlocks
;
60 mBlocks
= mBlocks
->mNext
;
66 StackArena::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
69 StackBlock
*block
= mBlocks
;
71 n
+= aMallocSizeOf(block
);
74 n
+= aMallocSizeOf(mMarks
);
78 static const int STACK_ARENA_MARK_INCREMENT
= 50;
83 // Resize the mark array if we overrun it. Failure to allocate the
84 // mark array is not fatal; we just won't free to that mark. This
85 // allows callers not to worry about error checking.
86 if (mStackTop
>= mMarkLength
) {
87 uint32_t newLength
= mStackTop
+ STACK_ARENA_MARK_INCREMENT
;
88 StackMark
* newMarks
= new StackMark
[newLength
];
91 memcpy(newMarks
, mMarks
, sizeof(StackMark
)*mMarkLength
);
93 // Fill in any marks that we couldn't allocate during a prior call
95 for (; mMarkLength
< mStackTop
; ++mMarkLength
) {
96 NS_NOTREACHED("should only hit this on out-of-memory");
97 newMarks
[mMarkLength
].mBlock
= mCurBlock
;
98 newMarks
[mMarkLength
].mPos
= mPos
;
102 mMarkLength
= newLength
;
106 // Set a mark at the top (if we can).
107 NS_ASSERTION(mStackTop
< mMarkLength
, "out of memory");
108 if (mStackTop
< mMarkLength
) {
109 mMarks
[mStackTop
].mBlock
= mCurBlock
;
110 mMarks
[mStackTop
].mPos
= mPos
;
117 StackArena::Allocate(size_t aSize
)
119 NS_ASSERTION(mStackTop
> 0, "Allocate called without Push");
121 // Align to a multiple of 8.
122 aSize
= NS_ROUNDUP
<size_t>(aSize
, 8);
124 // On stack overflow, grab another block.
125 if (mPos
+ aSize
>= StackBlock::MAX_USABLE_SIZE
) {
126 NS_ASSERTION(aSize
<= StackBlock::MAX_USABLE_SIZE
,
127 "Requested memory is greater that our block size!!");
128 if (mCurBlock
->mNext
== nullptr) {
129 mCurBlock
->mNext
= new StackBlock();
132 mCurBlock
= mCurBlock
->mNext
;
136 // Return the chunk they need.
137 void *result
= mCurBlock
->mBlock
+ mPos
;
147 NS_ASSERTION(mStackTop
> 0, "unmatched pop");
150 if (mStackTop
>= mMarkLength
) {
151 // We couldn't allocate the marks array at the time of the push, so
152 // we don't know where we're freeing to.
153 NS_NOTREACHED("out of memory");
154 if (mStackTop
== 0) {
155 // But we do know if we've completely pushed the stack.
163 // Mark the "freed" memory with 0xdd to help with debugging of memory
164 // allocation problems.
166 StackBlock
*block
= mMarks
[mStackTop
].mBlock
, *block_end
= mCurBlock
;
167 size_t pos
= mMarks
[mStackTop
].mPos
;
168 for (; block
!= block_end
; block
= block
->mNext
, pos
= 0) {
169 memset(block
->mBlock
+ pos
, 0xdd, sizeof(block
->mBlock
) - pos
);
171 memset(block
->mBlock
+ pos
, 0xdd, mPos
- pos
);
175 mCurBlock
= mMarks
[mStackTop
].mBlock
;
176 mPos
= mMarks
[mStackTop
].mPos
;
179 } // namespace mozilla