1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: fnd_FrameHeap.h
4
5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 24310 $
14 *---------------------------------------------------------------------------*/
15
16 /*! @file
17 @brief フレームヒープに関するAPIの宣言
18
19 */
20
21 #ifndef NN_FND_FND_FRAMEHEAP_H_
22 #define NN_FND_FND_FRAMEHEAP_H_
23
24 #include <nn/types.h>
25 #include <nn/fnd/fnd_Allocator.h>
26 #include <nn/fnd/fnd_HeapBase.h>
27 #include <nn/fnd/fnd_MemoryRange.h>
28 #include <nn/Assert.h>
29 #include <nn/os.h>
30
31 #ifdef __cplusplus
32
33 #define NN_FND_FRAMEHEAP_FREE_HEAD 1
34 #define NN_FND_FRAMEHEAP_FREE_TAIL 2
35 #define NN_FND_FRAMEHEAP_FREE_ALL (NN_FND_FRAMEHEAP_FREE_HEAD | NN_FND_FRAMEHEAP_FREE_TAIL)
36
37 #define NN_FND_FRAMEHEAP_ADJUST_TAIL 1
38 #define NN_FND_FRAMEHEAP_ADJUST_HEAD -1
39
40 namespace nn { namespace fnd {
41
42 /*!
43 @brief フレームヒープのベースクラスです。
44
45 このクラスのインスタンスを直接作成することはできません。
46 */
47 class FrameHeapBase : public HeapBase
48 {
49 public:
50
51 class State;
52
53 protected:
54
FrameHeapBase()55 FrameHeapBase() : m_Addr(0) {}
56
57 FrameHeapBase(uptr addr, size_t size, bit32 option = 0) : m_Addr(0) { Initialize(addr, size, option); }
58
59 template <class MemoryBlock>
60 FrameHeapBase(const MemoryBlock& block, bit32 option = 0) : m_Addr(0) { Initialize(block.GetAddress(), block.GetSize(), option); }
61
62 void Initialize(uptr addr, size_t size, bit32 option = 0);
63
Finalize()64 void Finalize() { m_Addr = 0; }
65
~FrameHeapBase()66 virtual ~FrameHeapBase() { Finalize(); }
67
68 void* Allocate(size_t size, s32 alignment);
69
70 size_t ResizeBlock(void* p, size_t newSize);
71
72 void FreeAll(int mode);
73
FreeV(void *)74 virtual void FreeV(void*) {}
75
76 State SaveState();
77
78 void RestoreState(State state);
79
80 MemoryRange Adjust(int mode);
81
82 size_t GetAllocatableSize(s32 alignment) const;
83
GetStartAddress()84 virtual void* GetStartAddress() const { return reinterpret_cast<void*>(m_Addr); }
85
GetTotalSize()86 virtual size_t GetTotalSize() const { return m_Size; }
87
88 virtual void Dump() const;
89
90 virtual bool HasAddress(const void* addr) const;
91
92 private:
93 uptr m_Addr;
94 size_t m_Size;
95 uptr m_CurrentHead;
96 uptr m_CurrentTail;
97 };
98
99 /*!
100 @brief フレームヒープの状態を表すクラスです。
101 */
102 class FrameHeapBase::State
103 {
104 public:
105
106 /*!
107 @brief コンストラクタです。
108
109 @param heap フレームヒープを指定します。
110 */
State(FrameHeapBase & heap)111 explicit State(FrameHeapBase& heap) : m_Head(heap.m_CurrentHead), m_Tail(heap.m_CurrentTail) {}
112
113 /*!
114 @brief コンストラクタです。初期化は行いません。
115 */
State()116 State() : m_Head(0), m_Tail(0) {}
117
118 private:
119 uptr m_Head;
120 uptr m_Tail;
121
State(uptr head,uptr tail)122 explicit State(uptr head, uptr tail) : m_Head(head), m_Tail(tail) {}
123
124 friend class FrameHeapBase;
125 };
126
Allocate(size_t size,s32 alignment)127 inline void* FrameHeapBase::Allocate(size_t size, s32 alignment)
128 {
129 NN_TASSERT_(size > 0);
130 NN_TASSERT_(alignment != 0);
131 uptr ret;
132
133 if ( alignment == 0 )
134 {
135 NN_TPANIC_("invalid argument: alignment == 0");
136 }
137
138 if ( alignment > 0 ) {
139 ret = RoundUp(m_CurrentHead, alignment);
140 uptr current = ret + size;
141
142 if (current > m_CurrentTail)
143 {
144 return 0;
145 }
146
147 m_CurrentHead = current;
148 }
149 else
150 {
151 uptr current = ret = RoundDown(m_CurrentTail-size, -alignment);
152
153 if (current < m_CurrentHead)
154 {
155 return 0;
156 }
157
158 m_CurrentTail = current;
159 }
160
161
162 // フィルオプション
163 DebugFillMemory(ret, size, HEAP_FILL_TYPE_ALLOC);
164 FillMemoryZero(ret, size);
165
166 return reinterpret_cast<void*>(ret);
167 }
168
FreeAll(int mode)169 inline void FrameHeapBase::FreeAll(int mode)
170 {
171 NN_TASSERT_( mode == NN_FND_FRAMEHEAP_FREE_HEAD ||
172 mode == NN_FND_FRAMEHEAP_FREE_TAIL ||
173 mode == NN_FND_FRAMEHEAP_FREE_ALL);
174
175 if ( mode & NN_FND_FRAMEHEAP_FREE_HEAD )
176 {
177 DebugFillMemory(m_Addr, m_CurrentHead - m_Addr, HEAP_FILL_TYPE_FREE);
178 this->m_CurrentHead = this->m_Addr;
179 }
180
181 if ( mode & NN_FND_FRAMEHEAP_FREE_TAIL )
182 {
183 DebugFillMemory(m_CurrentTail, m_Addr + m_Size - m_CurrentTail, HEAP_FILL_TYPE_FREE);
184 this->m_CurrentTail = this->m_Addr + this->m_Size;
185 }
186 }
187
ResizeBlock(void * p,size_t newSize)188 inline size_t FrameHeapBase::ResizeBlock(void* p, size_t newSize)
189 {
190 // TODO: debug_fill
191 uptr& addr = reinterpret_cast<uptr&>(p);
192 NN_TASSERT_(m_Addr <= addr && addr < m_CurrentTail);
193 NN_TASSERT_(addr <= m_CurrentHead);
194 uptr current = addr + newSize;
195 if (current < m_CurrentTail)
196 {
197 if ( current < this->m_CurrentHead )
198 {
199 DebugFillMemory(current, this->m_CurrentHead - current, HEAP_FILL_TYPE_FREE);
200 }
201 if ( this->m_CurrentHead < current )
202 {
203 FillMemoryZero(this->m_CurrentHead, current - this->m_CurrentHead);
204 }
205 this->m_CurrentHead = current;
206 return newSize;
207 }
208 else
209 {
210 return 0;
211 }
212 }
213
Adjust(int mode)214 inline MemoryRange FrameHeapBase::Adjust(int mode)
215 {
216 // TODO: debug_fill
217 if ( mode == 0 )
218 {
219 NN_TPANIC_("invalid argument: mode == 0");
220 }
221
222 if ( mode > 0 )
223 {
224 if ( m_CurrentTail != m_Addr + m_Size )
225 {
226 NN_TPANIC_("invalid call: tail used");
227 }
228
229 DebugFillMemory(m_CurrentHead, m_Addr + m_Size - m_CurrentHead, HEAP_FILL_TYPE_FREE);
230
231 uptr oldtail = m_Addr + m_Size;
232 this->m_Size = m_CurrentHead - m_Addr;
233 this->m_CurrentTail = m_CurrentHead;
234 return MemoryRange(this->m_CurrentTail, oldtail);
235 }
236 else
237 {
238 if ( m_CurrentHead != m_Addr )
239 {
240 NN_TPANIC_("invalid call: head used");
241 }
242
243 DebugFillMemory(m_Addr, m_CurrentTail - m_Addr, HEAP_FILL_TYPE_FREE);
244
245 uptr oldhead = m_Addr;
246 this->m_Size = m_Addr + m_Size - m_CurrentTail;
247 this->m_CurrentHead = m_CurrentTail;
248 this->m_Addr = m_CurrentTail;
249 return MemoryRange(oldhead, m_Addr);
250 }
251 }
252
SaveState()253 inline FrameHeapBase::State FrameHeapBase::SaveState()
254 {
255 return State(m_CurrentHead, m_CurrentTail);
256 }
257
RestoreState(FrameHeapBase::State state)258 inline void FrameHeapBase::RestoreState(FrameHeapBase::State state)
259 {
260 NN_TASSERT_(this->m_Addr <= state.m_Head && state.m_Head <= this->m_Addr + this->m_Size);
261 NN_TASSERT_(this->m_Addr <= state.m_Tail && state.m_Tail <= this->m_Addr + this->m_Size);
262 NN_TASSERT_(state.m_Head <= this->m_CurrentHead);
263 NN_TASSERT_(state.m_Tail >= this->m_CurrentTail);
264
265 this->m_CurrentHead = state.m_Head;
266 this->m_CurrentTail = state.m_Tail;
267
268 DebugFillMemory(m_CurrentHead, m_CurrentTail - m_CurrentHead, HEAP_FILL_TYPE_FREE);
269 }
270
GetAllocatableSize(s32 alignment)271 inline size_t FrameHeapBase::GetAllocatableSize(s32 alignment) const
272 {
273 NN_TASSERT_(alignment != 0);
274
275 if ( alignment == 0 )
276 {
277 NN_TPANIC_("invalid argument: alignment == 0");
278 }
279
280 if ( alignment < 0 )
281 {
282 alignment = -alignment;
283 }
284
285 uptr addr = RoundUp(m_CurrentHead, alignment);
286 if (addr <= m_CurrentTail)
287 {
288 return m_CurrentTail - addr;
289 }
290 else
291 {
292 return 0;
293 }
294 }
295
HasAddress(const void * addr)296 inline bool FrameHeapBase::HasAddress(const void* addr) const
297 {
298 return m_Addr <= reinterpret_cast<uptr>(addr)
299 && reinterpret_cast<uptr>(addr) < (m_Addr+m_Size);
300 }
301
302 /*!
303 @brief フレームヒープのためのクラステンプレートです。
304
305 このクラステンプレートを実体化したクラスでは、
306 指定したロックポリシーによって、排他制御が行われます。
307 ロックポリシーは @ref nn::os::LockPolicy クラスの内部で宣言される
308 クラスもしくはクラステンプレートを実体化したクラスを指定することができます。
309 上述のクラス以外を LockPolicy に指定した場合の動作・互換性は保障されません。
310
311 ロックされるのは、ヒープ内の操作に対してのみであり、
312 ヒープの階層化に対する操作などを行う場合は、適切な排他処理などが別途必要となります。
313
314 @tparam LockPolicy ヒープに対する操作を行うときのロックポリシーを指定します。
315 */
316 template <class LockPolicy>
317 class FrameHeapTemplate : public FrameHeapBase, private LockPolicy::LockObject
318 {
319 private:
320 typedef FrameHeapBase Base;
321 typedef typename LockPolicy::LockObject LockObject;
322 typedef typename LockPolicy::ScopedLock ScopedLock;
323 public:
324
325 /*!
326 @brief コンストラクタです。初期化は行いません。
327 */
FrameHeapTemplate()328 FrameHeapTemplate() {}
329
330 /*!
331 @brief コンストラクタです。フレームヒープの初期化を行います。
332
333 @param[in] addr フレームヒープに割り当てるメモリブロックの先頭アドレスを指定します。
334 @param[in] size フレームヒープに割り当てるメモリブロックのサイズを指定します。
335 @param[in] option オプションを指定します。未実装です。
336 */
337 FrameHeapTemplate(uptr addr, size_t size, bit32 option = 0) { Initialize(addr, size, option); }
338
339 /*!
340 @brief コンストラクタです。フレームヒープの初期化を行います。
341
342 @param[in] block フレームヒープに割り当てるメモリブロックを指定します。
343 @param[in] option オプションを指定します。
344 */
345 template <class MemoryBlock>
346 FrameHeapTemplate(const MemoryBlock& block, bit32 option = 0) { Initialize(block.GetAddress(), block.GetSize(), option); }
347
348 /*!
349 @brief ヒープ内にフレームヒープを作成します。
350
351 この関数により作成したヒープは @ref HeapBase::Destroy により解放してください。
352
353 FrameHeap自身をaddrとsizeで指定した領域内に作成します。
354 このため、指定した領域の大きさから sizeof(FrameHeap) の大きさだけ少ない領域をヒープとして割り当てます。
355
356 placementによりFrameHeapオブジェクト自身の配置場所を指定します。
357 placementに HEAP_INFOPLACEMENT_HEAD を指定すると領域の先頭(addr から addr+sizeof(FrameHeap) までの領域)にFrameHeapオブジェクト自身を配置します。
358 placementに HEAP_INFOPLACEMENT_TAIL を指定すると領域の末尾(addr+size-sizeof(FrameHeap) から addr+size までの領域)にFrameHeapオブジェクト自身を配置します。
359
360 @param[in] parent addr を領域内に持つ親のヒープを指定します。
361 @param[in] addr フレームヒープに割り当てるメモリブロックの先頭アドレスを指定します。
362 parent で指定されたヒープで確保されたメモリブロックを指定してください。
363 @param[in] size フレームヒープに割り当てるメモリブロックのサイズを指定します。
364 @param[in] option オプションを指定します。未実装です。
365 @param[in] placement 管理領域(FrameHeapオブジェクト)の配置場所を指定します。
366
367 @return 作成したヒープを返します。
368 */
369 static FrameHeapTemplate* Create(HeapBase* parent, void* addr, size_t size, bit32 option = 0, bit32 placement = HEAP_INFOPLACEMENT_HEAD);
370
371 /*!
372 @brief フレームヒープの初期化を行います。
373
374 @param[in] addr フレームヒープに割り当てるメモリブロックの先頭アドレスを指定します。
375 @param[in] size フレームヒープに割り当てるメモリブロックのサイズを指定します。
376 @param[in] option オプションを指定します。
377
378 @return 無し。
379 */
380 void Initialize(uptr addr, size_t size, bit32 option = 0)
381 {
382 Base::Initialize(addr, size, option);
383 LockObject::Initialize();
384 }
385
386 /*!
387 @brief ヒープを破棄します。
388
389 @return 無し。
390 */
Finalize()391 void Finalize()
392 {
393 LockObject::Finalize();
394 Base::Finalize();
395 }
396
397 /*!
398 @brief デストラクタです。内部でFinalize()を呼びます。
399
400 @return 無し。
401 */
~FrameHeapTemplate()402 virtual ~FrameHeapTemplate() {}
403
404 /*!
405 @brief フレームヒープからメモリを確保します。
406
407 @param[in] size 確保するメモリブロックのサイズ(バイト)を指定します。
408 @param[in] alignment アラインメントを指定します。4,8,16,32,-4,-8,-16,-32のいずれかの値が指定できます。
409
410 @return 確保したメモリブロックの先頭アドレスを返します。
411
412 正のアライメントを指定すると、ヒープの先頭からメモリを確保し、負のアライメントを指定するとヒープの末尾からメモリを確保します。
413 */
414 void* Allocate(size_t size, s32 alignment = DEFAULT_ALIGNMENT)
415 {
416 ScopedLock lk(*this);
417 return Base::Allocate(size, alignment);
418 }
419
420 /*!
421 @brief フレームヒープから最後に確保したメモリブロックの大きさを変更します。
422
423 前方から確保したメモリブロックに対してのみ使用できます。
424
425 @param[in] p 最後に確保したメモリブロックの先頭アドレスを指定します。
426 @param[in] newSize 変更後のサイズ
427
428 @return 成功すると成功後のサイズを返します。
429 */
ResizeBlock(void * p,size_t newSize)430 size_t ResizeBlock(void* p, size_t newSize)
431 {
432 ScopedLock lk(*this);
433 return Base::ResizeBlock(p, newSize);
434 }
435
436 /*!
437 @brief フレームヒープから確保したメモリブロックを全て解放します。
438
439 mode に NN_FND_FRAMEHEAP_FREE_HEAD を指定することで前方から確保したメモリブロックを一括して解放します。
440
441 mode に NN_FND_FRAMEHEAP_FREE_TAIL を指定することで後方から確保したメモリブロックを一括して解放します。
442
443 mode に NN_FND_FRAMEHEAP_FREE_ALL を指定することで、ヒープから確保した全てのメモリブロックを一括して解放します。MEM_FRMHEAP_FREE_HEAD と MEM_FRMHEAP_FREE_TAIL を同時に指定した場合と同じです。
444
445 @param[in] mode メモリブロックの解放方法
446
447 @return 無し。
448 */
449 void Free(int mode = NN_FND_FRAMEHEAP_FREE_ALL)
450 {
451 ScopedLock lk(*this);
452 Base::FreeAll(mode);
453 }
454
455 /*!
456 @brief 他の種類のヒープと整合性を取るために定義されており、この関数を呼び出すことはできません。
457
458 @param[in] p 解放するメモリブロックの先頭アドレスを指定します。
459
460 @return 無し。
461 */
FreeV(void *)462 virtual void FreeV(void*) { NN_TASSERT_(0); }
463
464 class ScopedFrame;
465
466 /*!
467 @brief フレームヒープの状態を保存します。
468
469 @return フレームヒープの状態を返します。
470 */
SaveState()471 State SaveState()
472 {
473 ScopedLock lk(*this);
474 return Base::SaveState();
475 }
476
477 /*!
478 @brief フレームヒープの状態を復元します。
479
480 @param[in] state フレームヒープの状態を指定します。
481
482 @return 無し。
483 */
RestoreState(State state)484 void RestoreState(State state)
485 {
486 ScopedLock lk(*this);
487 Base::RestoreState(state);
488 }
489
490 /*!
491 @brief フレームヒープのサイズを、確保したメモリブロックを包含する最小のサイズに変更します。
492
493 mode に NN_FND_FRAMEHEAP_ADJUST_TAIL(もしくは、正の値)を指定することで、後方の空き領域を捨てる形でフレームヒープ領域の先端位置を変更します。
494 後方にメモリブロックを確保している場合は失敗します。
495
496 mode に NN_FND_FRAMEHEAP_ADJUST_HEAD(もしくは、負の値)を指定することで、前方の空き領域を捨てる形でフレームヒープ領域の末端位置を変更します。
497 前方にメモリブロックを確保している場合は失敗します。
498
499 @param[in] mode メモリブロックを縮小する方向を指定します。
500
501 @return ヒープが縮小されることにより空いたメモリ領域の範囲を返します。
502 */
503 MemoryRange Adjust(int mode = NN_FND_FRAMEHEAP_ADJUST_TAIL)
504 {
505 ScopedLock lk(*this);
506 return Base::Adjust(mode);
507 }
508
509 /*!
510 @brief フレームヒープから確保可能なメモリブロックのサイズを取得します。
511
512 @param[in] alignment アラインメントを指定します。
513
514 @return フレームヒープから確保可能なメモリブロックのサイズを返します。
515 */
516 size_t GetAllocatableSize(s32 alignment = DEFAULT_ALIGNMENT) const
517 {
518 ScopedLock lk(*this);
519 return Base::GetAllocatableSize(alignment);
520 }
521
522 /*!
523 @brief フレームヒープのメモリ領域の開始アドレスを取得します。
524
525 @return フレームヒープのメモリ領域の開始アドレスをを返します。
526 */
GetStartAddress()527 virtual void* GetStartAddress() const
528 {
529 ScopedLock lk(*this);
530 return Base::GetStartAddress();
531 }
532
533 /*!
534 @brief フレームヒープに割り当てられているメモリサイズを取得します。
535
536 @return フレームヒープに割り当てられているメモリサイズを返します。
537 */
GetTotalSize()538 virtual size_t GetTotalSize() const
539 {
540 ScopedLock lk(*this);
541 return Base::GetTotalSize();
542 }
543
544 /*!
545 @brief 指定したアドレスがヒープに含まれているか調べます。
546
547 @param[in] addr 調べたいアドレスを指定します。
548
549 @return ヒープに含まれていれば true を返し、含まれていなければ false を返します。
550 */
HasAddress(const void * addr)551 virtual bool HasAddress(const void* addr) const
552 {
553 ScopedLock lk(*this);
554 return Base::HasAddress(addr);
555 }
556
557 /*!
558 @brief ヒープ内部の情報を表示します。(デバッグ用)
559
560 @return 無し。
561 */
Dump()562 virtual void Dump() const { Base::Dump(); };
563
564 // FrameHeap のアロケータはサポートしない
565 //class Allocator;
566
567 private:
568 uptr m_Addr;
569 size_t m_Size;
570 uptr m_CurrentHead; // 空き領域の最初のアドレス
571 uptr m_CurrentTail; // 空き領域の最後のアドレス+4
572 bit32 m_Option;
573 };
574
575 /*!
576 @brief スコープごとにフレームヒープの状態を保存するクラスです。
577 */
578 template <class LockPolicy>
579 class FrameHeapTemplate<LockPolicy>::ScopedFrame
580 {
581 public:
582 /*!
583 @brief コンストラクタです。指定されたフレームヒープの内部状態を保存します。
584
585 @param heap フレームヒープを指定します。フレームヒープの状態を保存します。
586 */
ScopedFrame(FrameHeapTemplate<LockPolicy> & heap)587 explicit ScopedFrame(FrameHeapTemplate<LockPolicy>& heap) : m_State(heap), m_Heap(heap) {}
588 /*!
589 @brief デストラクタです。フレームヒープの内部状態を復元します。
590 */
~ScopedFrame()591 ~ScopedFrame() { m_Heap.RestoreState(m_State); }
592
593 private:
594 FrameHeapTemplate<LockPolicy>::State m_State;
595 FrameHeapTemplate<LockPolicy>& m_Heap;
596 };
597
598 /*!
599 @brief ロック操作をしないスレッドアンセーフなフレームヒープを表す型です。
600 */
601 typedef FrameHeapTemplate<nn::os::LockPolicy::NoLock> FrameHeap;
602
603 /*!
604 @brief ヒープごとに用意されるクリティカルセクションで保護された、スレッドセーフなフレームヒープを表す型です。
605 */
606 typedef FrameHeapTemplate<nn::os::LockPolicy::Object<nn::os::CriticalSection> > ThreadSafeFrameHeap;
607
608 template <class LockPolicy>
Create(HeapBase * parent,void * addr,size_t size,bit32 option,bit32 placement)609 FrameHeapTemplate<LockPolicy>* FrameHeapTemplate<LockPolicy>::Create(HeapBase* parent, void* addr, size_t size, bit32 option, bit32 placement)
610 {
611 FrameHeapTemplate* heap;
612
613 if ( parent->FindHeap(addr) != parent ) return 0;
614
615 if ( placement == HEAP_INFOPLACEMENT_HEAD )
616 {
617 heap = new (addr) FrameHeapTemplate(reinterpret_cast<uptr>(addr)+sizeof(FrameHeapTemplate), static_cast<size_t>(size - sizeof(FrameHeapTemplate)), option);
618 }
619 else if ( placement == HEAP_INFOPLACEMENT_TAIL )
620 {
621 void* placeaddr = reinterpret_cast<void*>(reinterpret_cast<uptr>(addr)+static_cast<size_t>(size - sizeof(FrameHeapTemplate)));
622 heap = new (placeaddr) FrameHeapTemplate(reinterpret_cast<uptr>(addr), static_cast<size_t>(size - sizeof(FrameHeapTemplate)), option);
623 }
624 else
625 {
626 return 0;
627 }
628
629 heap->SetParent(parent);
630 return heap;
631 }
632
633 }}
634
635 #endif
636
637 #endif
638