aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/EmPalmHeap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/EmPalmHeap.cpp')
-rw-r--r--SrcShared/EmPalmHeap.cpp2263
1 files changed, 2263 insertions, 0 deletions
diff --git a/SrcShared/EmPalmHeap.cpp b/SrcShared/EmPalmHeap.cpp
new file mode 100644
index 0000000..6745edc
--- /dev/null
+++ b/SrcShared/EmPalmHeap.cpp
@@ -0,0 +1,2263 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1999-2001 Palm, Inc. or its subsidiaries.
+ All rights reserved.
+
+ This file is part of the Palm OS Emulator.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+\* ===================================================================== */
+
+#include "EmCommon.h"
+#include "EmPalmHeap.h"
+
+#include "ChunkFile.h" // Chunk, EmStreamChunk
+#include "EmErrCodes.h" // kError_CorruptedHeap_Foo
+#include "EmMemory.h" // CEnableFullAccess, EmMemGet32, EmMemGet16, EmMemGet8
+#include "ErrorHandling.h" // Errors::ReportErrCorruptedHeap
+#include "ROMStubs.h" // MemNumHeaps, MemHeapID, MemHeapPtr
+#include "SessionFile.h" // SessionFile
+
+#include <stdio.h> // sprintf
+
+
+// ===========================================================================
+// ¥ EmPalmHeap
+// ===========================================================================
+
+EmPalmHeapList EmPalmHeap::fgHeapList;
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Initialize [ STATIC ]
+ *
+ * DESCRIPTION: Standard initialization function. Responsible for
+ * initializing this sub-system when a new session is
+ * created. Will be followed by at least one call to
+ * Reset or Load.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::Initialize (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Reset [ STATIC ]
+ *
+ * DESCRIPTION: Re-initializes the PalmHeap sub-system. This function
+ * is called when the ROM is "rebooted" (which includes
+ * the initial boot-up after a ROM is loaded).
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::Reset (void)
+{
+ fgHeapList.clear ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Save [ STATIC ]
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::Save (SessionFile& f)
+{
+ const long kCurrentVersion = 1;
+
+ Chunk chunk;
+ EmStreamChunk s (chunk);
+
+ s << kCurrentVersion;
+
+ s << fgHeapList;
+
+ f.WriteHeapInfo (chunk);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Load [ STATIC ]
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::Load (SessionFile& f)
+{
+ Chunk chunk;
+ if (f.ReadHeapInfo (chunk))
+ {
+ long version;
+ EmStreamChunk s (chunk);
+
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> fgHeapList;
+ }
+ }
+ else
+ {
+ f.SetCanReload (false); // Need to reboot
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Dispose [ STATIC ]
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::Dispose (void)
+{
+ fgHeapList.clear ();
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapListBegin [ STATIC ]
+ *
+ * DESCRIPTION: Return an iterator representing the beginning of our
+ * list of heap objects.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The iterator.
+ *
+ ***********************************************************************/
+
+EmPalmHeapList::const_iterator EmPalmHeap::GetHeapListBegin (void)
+{
+ return fgHeapList.begin ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapListEnd [ STATIC ]
+ *
+ * DESCRIPTION: Return an iterator representing the end of our
+ * list of heap objects.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The iterator.
+ *
+ ***********************************************************************/
+
+EmPalmHeapList::const_iterator EmPalmHeap::GetHeapListEnd (void)
+{
+ return fgHeapList.end ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapByID [ STATIC ]
+ *
+ * DESCRIPTION: Find a heap based on its ID.
+ *
+ * PARAMETERS: heapID - the ID to test.
+ *
+ * RETURNED: The pointer to the heap object. If no heap object
+ * has that ID, NULL is returned.
+ *
+ ***********************************************************************/
+
+const EmPalmHeap* EmPalmHeap::GetHeapByID (UInt16 heapID)
+{
+ EmPalmHeapList::iterator iter = fgHeapList.begin ();
+
+ while (iter != fgHeapList.end ())
+ {
+ if (iter->fHeapID == heapID)
+ {
+ return &*iter;
+ }
+
+ ++iter;
+ }
+
+ return NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapByPtr [ STATIC ]
+ *
+ * DESCRIPTION: Find a heap based on a pointer.
+ *
+ * PARAMETERS: p - the pointer to test.
+ *
+ * RETURNED: The pointer to the heap object. If no heap object
+ * contains the pointer, NULL is returned.
+ *
+ ***********************************************************************/
+
+const EmPalmHeap* EmPalmHeap::GetHeapByPtr (emuptr p)
+{
+ return GetHeapByPtr ((MemPtr) p);
+}
+
+const EmPalmHeap* EmPalmHeap::GetHeapByPtr (MemPtr p)
+{
+ // !!! Could do a binary search here, if needed.
+
+ EmPalmHeapList::iterator iter = fgHeapList.begin ();
+
+ while (iter != fgHeapList.end ())
+ {
+ if (iter->Contains ((emuptr) p))
+ {
+ return &*iter;
+ }
+
+ ++iter;
+ }
+
+ return NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapByHdl [ STATIC ]
+ *
+ * DESCRIPTION: Find a heap based on a handle.
+ *
+ * PARAMETERS: h - the handle to test.
+ *
+ * RETURNED: The pointer to the heap object. If no heap object
+ * contains the handle, NULL is returned.
+ *
+ * !!! What to do when the handle and pointer aren't in the same heap?
+ *
+ ***********************************************************************/
+
+const EmPalmHeap* EmPalmHeap::GetHeapByHdl (MemHandle h)
+{
+ MemPtr p = DerefHandle (h);
+
+ if (p)
+ return GetHeapByPtr (p);
+
+ return NULL;
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::MemInitHeapTable [ STATIC ]
+ *
+ * DESCRIPTION: All new heaps have been created. Create objects to
+ * represent those heaps and add them to our list of heaps.
+ *
+ * PARAMETERS: Parameters passed to MemInitHeapTable
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::MemInitHeapTable (UInt16 cardNo)
+{
+ UInt16 numHeaps = ::MemNumHeaps (cardNo);
+
+ for (UInt16 heapIndex = 0; heapIndex < numHeaps; ++heapIndex)
+ {
+ UInt16 heapID = ::MemHeapID (cardNo, heapIndex);
+
+ // Add the heap, as long as it's not the dynamic heap. During
+ // bootup, the memory initialization sequence goes like:
+ //
+ // if hard reset required:
+ // MemCardFormat
+ // lay out the card
+ // MemStoreInit
+ // for each heap
+ // MemHeapInit
+ // MemInit
+ // for each card:
+ // MemInitHeapTable
+ // for each dynamic heap:
+ // MemHeapInit
+ // for each RAM heap:
+ // Unlock all chunks
+ // Compact
+ //
+ // Which means that if there's no hard reset, MemHeapInit
+ // has not been called on the dynamic heap at the time
+ // MemInitHeapTable is called. And since the dynamic heap
+ // is currently in a corrupted state (because the boot stack
+ // and initial LCD buffer have been whapped over it), we
+ // can't perform the heap walk we'd normally do when adding
+ // a heap object.
+
+ if (heapID != 0)
+ AddHeap (heapID);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::MemHeapInit [ STATIC ]
+ *
+ * DESCRIPTION: A new heap has been created. Create an object to
+ * represent that heap and add it to our list of heaps.
+ *
+ * PARAMETERS: Parameters passed to MemHeapInit
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::MemHeapInit (UInt16 heapID, Int16, Boolean)
+{
+ AddHeap (heapID);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::MemHeapCompact [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHeapFreeByOwnerID [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHeapScramble [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemChunkNew [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemChunkFree [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemPtrNew [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemPtrResize [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHandleNew [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHandleResize [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHandleFree [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemLocalIDToLockedPtr [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHandleLock [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHandleUnlock [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemHandleResetLock [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemPtrResetLock [ STATIC ]
+ * FUNCTION: EmPalmHeap::MemPtrUnlock [ STATIC ]
+ *
+ * DESCRIPTION: All of these functions alter the heap in some way.
+ * Resync our notion of the state of the heap with reality.
+ *
+ * PARAMETERS: Parameters to the Memory Manager functions that altered
+ * the heap.
+ *
+ * RETURNED: The chunks that cover the altered range of the heap
+ * are returned in the "delta" collection.
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::MemHeapCompact (UInt16 heapID, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemHeapFreeByOwnerID (UInt16 heapID, UInt16, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemHeapScramble (UInt16 heapID, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemChunkNew (UInt16 heapID, MemPtr p, UInt16 attr, EmPalmChunkList* delta)
+{
+ UNUSED_PARAM (p);
+ UNUSED_PARAM (attr);
+
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemChunkFree (EmPalmHeap* heap, EmPalmChunkList* delta)
+{
+// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemPtrNew (MemPtr p, EmPalmChunkList* delta)
+{
+ UNUSED_PARAM (p);
+// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (0));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemPtrResize (MemPtr p, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemHandleNew (MemHandle h, EmPalmChunkList* delta)
+{
+ UNUSED_PARAM (h);
+// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h));
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (0));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemHandleResize (MemHandle h, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemHandleFree (EmPalmHeap* heap, EmPalmChunkList* delta)
+{
+// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h));
+
+ if (heap)
+ heap->ResyncAll (delta);
+}
+
+void EmPalmHeap::MemLocalIDToLockedPtr (MemPtr p, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+
+ if (heap)
+ heap->ResyncPtr (p, delta);
+}
+
+void EmPalmHeap::MemHandleLock (MemHandle h, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h));
+
+ if (heap)
+ heap->ResyncHdl (h, delta);
+}
+
+void EmPalmHeap::MemHandleUnlock (MemHandle h, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h));
+
+ if (heap)
+ heap->ResyncHdl (h, delta);
+}
+
+void EmPalmHeap::MemHandleResetLock (MemHandle h, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h));
+
+ if (heap)
+ heap->ResyncHdl (h, delta);
+}
+
+void EmPalmHeap::MemPtrResetLock (MemPtr p, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+
+ if (heap)
+ heap->ResyncPtr (p, delta);
+}
+
+void EmPalmHeap::MemPtrUnlock (MemPtr p, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+
+ if (heap)
+ heap->ResyncPtr (p, delta);
+}
+
+void EmPalmHeap::MemPtrSetOwner (MemPtr p, EmPalmChunkList* delta)
+{
+ EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p));
+
+ if (heap)
+ heap->ResyncPtr (p, delta);
+}
+
+void EmPalmHeap::ValidateAllHeaps (void)
+{
+ EmPalmHeapList::iterator iter = fgHeapList.begin ();
+
+ while (iter != fgHeapList.end ())
+ {
+ (*iter).Validate ();
+ ++iter;
+ }
+}
+
+
+#pragma mark -
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::AddHeap [ STATIC ]
+ *
+ * DESCRIPTION: Add a heap based on its ID.
+ *
+ * PARAMETERS: heapID - the ID of the heap to add.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::AddHeap (UInt16 heapID)
+{
+ // Get information on the newly-created heap.
+
+ EmPalmHeap heap (heapID);
+
+ // Find where to add this heap to our list of heaps. We keep this
+ // list sorted by heap location for easy lookup on that basis.
+
+ EmPalmHeapList::iterator iter = fgHeapList.begin ();
+
+ while (iter != fgHeapList.end ())
+ {
+ // If we already had an entry for this heap, replace it.
+
+ if (iter->Start () == heap.Start ())
+ {
+ *iter = heap;
+ break;
+ }
+
+ // Found a place to insert this heap.
+
+ if (iter->Start () > heap.Start ())
+ {
+ fgHeapList.insert (iter, heap);
+ break;
+ }
+
+ ++iter;
+ }
+
+ // If the new heap couldn't be inserted before a currently existing
+ // heap, then add it to the end.
+
+ if (iter == fgHeapList.end ())
+ {
+ fgHeapList.push_back (heap);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::DerefHandle [ STATIC ]
+ *
+ * DESCRIPTION: Dereferences a handle and returns the pointer
+ *
+ * PARAMETERS: h - the handle to dereference
+ *
+ * RETURNED: The pointer associated with the handle.
+ *
+ ***********************************************************************/
+
+MemPtr EmPalmHeap::DerefHandle (MemHandle h)
+{
+ if (!h)
+ return NULL;
+
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ emuptr pp = (emuptr) memHandleUnProtect(h);
+ return (MemPtr) EmMemGet32 (pp);
+}
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::RecoverHandle [ STATIC ]
+ *
+ * DESCRIPTION: Finds a handle given a pointer.
+ *
+ * Note that MemPtrRecoverHandle calls memHandleProtect on
+ * the result even if it's NULL; we don't do that here.
+ *
+ * PARAMETERS: p - the pointer whose handle we want to find
+ *
+ * RETURNED: The handle associated with the pointer. NULL if the
+ * chunk was not allocated as a relocatable chunk or if
+ * it's a free chunk.
+ *
+ ***********************************************************************/
+
+MemHandle EmPalmHeap::RecoverHandle (MemPtr p)
+{
+ MemHandle h = NULL;
+
+ if (p)
+ {
+ const EmPalmHeap* heap = EmPalmHeap::GetHeapByPtr (p);
+
+ if (heap)
+ {
+ const EmPalmChunk* chunk = heap->GetChunkBodyContaining ((emuptr) p);
+
+ if (chunk && !chunk->Free () && chunk->HOffset ())
+ {
+ h = (MemHandle) (((emuptr) p) - chunk->HOffset () * 2 - chunk->HeaderSize ());
+
+#if _DEBUG
+ CEnableFullAccess munge; // Remove blocks on memory access.
+ EmAssert (EmMemGet32 ((emuptr) h) == (emuptr) p);
+#endif
+
+ h = memHandleProtect (h);
+ }
+ }
+ }
+
+ return h;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapVersion [ STATIC ]
+ *
+ * DESCRIPTION: Determine and return the version number of the given
+ * heap.
+ *
+ * PARAMETERS: heapPtr - a pointer to the header for the heap whose
+ * version is to be determined.
+ *
+ * RETURNED: The version number of the heap. Currently, these values
+ * are 1 (original heap format), 2 (allows for >64K heaps),
+ * and 3 (uses a free list for faster allocations).
+ *
+ ***********************************************************************/
+
+long EmPalmHeap::GetHeapVersion (emuptr heapHdr)
+{
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ long heapVersion = kVersionUnknown;
+
+ // Get the heap version. If bit 14 is set, it's a version 3 heap.
+ // If bit 15 is set, it's a version 2 heap. Otherwise, it's a
+ // version 1 heap.
+
+ uint16 flags = EmMemGet16 (heapHdr);
+
+ if ((flags & memHeapFlagVers4) != 0)
+ {
+ heapVersion = kVersion4; // free MP's on a list
+ }
+ else if ((flags & memHeapFlagVers3) != 0)
+ {
+ heapVersion = kVersion3; // has free list
+ }
+ else if ((flags & memHeapFlagVers2) != 0)
+ {
+ heapVersion = kVersion2; // > 64K
+ }
+ else
+ {
+ heapVersion = kVersion1; // original
+ }
+
+ return heapVersion;
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmHeap::EmPalmHeap (void) :
+ fVersion (kVersionUnknown),
+ fHeapID (-1),
+ fHeapHdrStart (0),
+ fHeapHdrSize (0),
+ fFirstChunk (0),
+ fFlags (0),
+ fSize (0),
+ fFirstFree (0),
+ fChunkHdrSize (0),
+ fChunkList (),
+ fMPTList ()
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: heapID - Palm OS ID for the heap we're to track.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmHeap::EmPalmHeap (UInt16 heapID) :
+ fVersion (kVersionUnknown),
+ fHeapID (heapID),
+ fHeapHdrStart (0),
+ fHeapHdrSize (0),
+ fFirstChunk (0),
+ fFlags (0),
+ fSize (0),
+ fFirstFree (0),
+ fChunkHdrSize (0),
+ fChunkList (),
+ fMPTList ()
+{
+ this->GetHeapHeaderInfo (heapID);
+ this->ResyncAll (NULL);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * Note: this version of the constructor doesn't work too
+ * well, since it doesn't determine the Palm OS heap ID.
+ *
+ * PARAMETERS: heapHdr - pointer to the heap header of the heap we're
+ * to track.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmHeap::EmPalmHeap (emuptr heapHdr) :
+ fVersion (kVersionUnknown),
+ fHeapID (-1),
+ fHeapHdrStart (0),
+ fHeapHdrSize (0),
+ fFirstChunk (0),
+ fFlags (0),
+ fSize (0),
+ fFirstFree (0),
+ fChunkHdrSize (0),
+ fChunkList (),
+ fMPTList ()
+{
+ this->GetHeapHeaderInfo (heapHdr);
+ this->ResyncAll (NULL);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap copy constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: other - EmPalmHeap object we're to clone.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmHeap::EmPalmHeap (const EmPalmHeap& other) :
+ fVersion (other.fVersion),
+ fHeapID (other.fHeapID),
+ fHeapHdrStart (other.fHeapHdrStart),
+ fHeapHdrSize (other.fHeapHdrSize),
+ fFirstChunk (other.fFirstChunk),
+ fFlags (other.fFlags),
+ fSize (other.fSize),
+ fFirstFree (other.fFirstFree),
+ fChunkHdrSize (other.fChunkHdrSize),
+ fChunkList (other.fChunkList),
+ fMPTList (other.fMPTList)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::~EmPalmHeap
+ *
+ * DESCRIPTION: Destroy the object. Delete all data members.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmHeap::~EmPalmHeap (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetChunkListBegin
+ *
+ * DESCRIPTION: Return an iterator representing the beginning of our
+ * list of chunk objects.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The iterator.
+ *
+ ***********************************************************************/
+
+EmPalmChunkList::const_iterator EmPalmHeap::GetChunkListBegin (void) const
+{
+ return fChunkList.begin ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetChunkListEnd
+ *
+ * DESCRIPTION: Return an iterator representing the end of our
+ * list of chunk objects.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The iterator.
+ *
+ ***********************************************************************/
+
+EmPalmChunkList::const_iterator EmPalmHeap::GetChunkListEnd (void) const
+{
+ return fChunkList.end ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetChunkReferencedBy
+ *
+ * DESCRIPTION: Iterate over our list of chunks, finding the one
+ * referenced by the given handle.
+ *
+ * PARAMETERS: h - test handle
+ *
+ * RETURNED: Pointer to chunk object containing the probe address.
+ * NULL if not found.
+ *
+ ***********************************************************************/
+
+const EmPalmChunk* EmPalmHeap::GetChunkReferencedBy (MemHandle h) const
+{
+ // !!! Could do a binary search here, if needed.
+
+ emuptr p = (emuptr) EmPalmHeap::DerefHandle (h);
+
+ ITERATE_CHUNKS (*this, iter, end)
+ {
+ if (iter->Contains (p))
+ {
+ return &*iter;
+ }
+
+ ++iter;
+ }
+
+ return NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetChunkContaining
+ *
+ * DESCRIPTION: Iterate over our list of chunks, finding the one
+ * containing the given pointer. The range includes the
+ * chunk header and trailer.
+ *
+ * PARAMETERS: p - probe address
+ *
+ * RETURNED: Pointer to chunk object containing the probe address.
+ * NULL if not found.
+ *
+ ***********************************************************************/
+
+const EmPalmChunk* EmPalmHeap::GetChunkContaining (emuptr p) const
+{
+ // !!! Could do a binary search here, if needed.
+
+ ITERATE_CHUNKS (*this, iter, end)
+ {
+ if (iter->Contains (p))
+ {
+ return &*iter;
+ }
+
+ ++iter;
+ }
+
+ return NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetChunkBodyContaining
+ *
+ * DESCRIPTION: Iterate over our list of chunks, finding the one
+ * containing the given pointer. The range does not
+ * include the chunk header or trailer.
+ *
+ * PARAMETERS: p - probe address
+ *
+ * RETURNED: Pointer to chunk object containing the probe address.
+ * NULL if not found.
+ *
+ ***********************************************************************/
+
+const EmPalmChunk* EmPalmHeap::GetChunkBodyContaining (emuptr p) const
+{
+ // !!! Could do a binary search here, if needed.
+
+ ITERATE_CHUNKS (*this, iter, end)
+ {
+ if (iter->BodyContains (p))
+ {
+ return &*iter;
+ }
+
+ ++iter;
+ }
+
+ return NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetMPTListBegin
+ *
+ * DESCRIPTION: Return an iterator representing the beginning of our
+ * list of master pointer table objects.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The iterator.
+ *
+ ***********************************************************************/
+
+EmPalmMPTList::const_iterator EmPalmHeap::GetMPTListBegin (void) const
+{
+ return fMPTList.begin ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetMPTListEnd
+ *
+ * DESCRIPTION: Return an iterator representing the end of our
+ * list of master pointer table objects.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The iterator.
+ *
+ ***********************************************************************/
+
+EmPalmMPTList::const_iterator EmPalmHeap::GetMPTListEnd (void) const
+{
+ return fMPTList.end ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Tracked
+ *
+ * DESCRIPTION: Return whether or not we should track the contents of
+ * this heap. For performance reasons, we currently
+ * track only the dynamic heap.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: True if we track this heap's contents.
+ *
+ ***********************************************************************/
+
+Bool EmPalmHeap::Tracked (void) const
+{
+ return this->Dynamic ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::ReadOnly
+ *
+ * DESCRIPTION: Return whether or not this heap is read-only
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool EmPalmHeap::ReadOnly (void) const
+{
+ return (fFlags & memHeapFlagReadOnly) != 0;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Dynamic
+ *
+ * DESCRIPTION: Return whether or not this heap is the (a?) dynamic heap.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool EmPalmHeap::Dynamic (void) const
+{
+ // This is probably the wrong test. I think there's a Palm OS call
+ // that indicates which heap(s) is/are dynamic.
+
+ return fHeapID == 0;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::Validate
+ *
+ * DESCRIPTION: Check to see that our chunk collection matches what's
+ * actually there.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::Validate (void)
+{
+ if (!this->Tracked ())
+ return;
+
+ EmPalmChunkList newList;
+ emuptr chunkHdr = this->DataStart ();
+
+ while (1)
+ {
+ // Get information about the current chunk.
+
+ EmPalmChunk chunk (*this, chunkHdr);
+
+ // If the size is zero, we've reached the sentinel at the end.
+
+ if (chunk.Size () == 0)
+ {
+ break;
+ }
+
+ // See if this chunk looks valid. An exception is thrown if not.
+
+ chunk.Validate (*this);
+
+ // Push this guy onto our list.
+
+ newList.push_back (chunk);
+
+ // Go on to next chunk.
+
+ chunkHdr += chunk.Size ();
+ }
+
+ EmPalmChunkList delta;
+ this->GenerateDeltas (newList, fChunkList, delta);
+ EmAssert (delta.size () == 0);
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapHeaderInfo
+ *
+ * DESCRIPTION: Scarf information out of the heap header.
+ *
+ * PARAMETERS: heapID - the heapID of the heap to query.
+ *
+ * RETURNED: Nothing, but many data members are filled in.
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::GetHeapHeaderInfo (UInt16 heapID)
+{
+ MemPtr heapHdr = MemHeapPtr (heapID);
+ if (heapHdr)
+ this->GetHeapHeaderInfo ((emuptr) heapHdr);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GetHeapHeaderInfo
+ *
+ * DESCRIPTION: Scarf up information about the managed heap.
+ *
+ * PARAMETERS: heapHdr - the pointer to the heap to query.
+ *
+ * RETURNED: Nothing, but many data members are filled in.
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::GetHeapHeaderInfo (emuptr heapHdr)
+{
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+
+ // Save the pointer to the beginning of the heap. This pointer
+ // points to a struct, the definition of which changes depending
+ // on the heap version.
+
+ fHeapHdrStart = heapHdr;
+
+
+ // Get the heap version so we know the layout of the header.
+
+ fVersion = GetHeapVersion (fHeapHdrStart);
+
+
+ /*
+ Heap layout
+
+ flags: // Always here, always 2 bytes
+ size // 2 bytes in V1, 4 otherwise
+ firstFreeChunkOffset // Only in V3
+ mstrPtrTbl
+ numEntries // always 2 bytes long
+ nextTblOffset // 2 bytes in V1, 4 otherwise
+ mstrP [numEntries]
+ ...chunks...
+ */
+
+
+ switch (fVersion)
+ {
+ case kVersion1:
+ {
+ fFlags = EmMemGet16 (fHeapHdrStart);
+ fSize = EmMemGet16 (fHeapHdrStart + offsetof (Mem1HeapHeaderType, size));
+ fFirstFree = EmMemNULL;
+ fChunkHdrSize = sizeof (Mem1ChunkHeaderType);
+ fHeapHdrSize = offsetof (Mem1HeapHeaderType, mstrPtrTbl);
+
+ EmPalmMPT mpt (*this, this->MptStart ());
+ fFirstChunk = this->MptStart () + mpt.Size ();
+
+ // In version 1 heaps, a zero in the size field means 64K.
+
+ if (fSize == 0)
+ {
+ fSize = 64 * 1024L;
+ }
+ break;
+ }
+
+ case kVersion2:
+ {
+ fFlags = EmMemGet16 (fHeapHdrStart);
+ fSize = EmMemGet32 (fHeapHdrStart + offsetof (Mem2HeapHeaderType, size));
+ fFirstFree = EmMemNULL;
+ fChunkHdrSize = sizeof (MemChunkHeaderType);
+ fHeapHdrSize = offsetof (Mem2HeapHeaderType, mstrPtrTbl);
+
+ EmPalmMPT mpt (*this, this->MptStart ());
+ fFirstChunk = this->MptStart () + mpt.Size ();
+ break;
+ }
+
+ case kVersion3:
+ case kVersion4:
+ {
+ fFlags = EmMemGet16 (fHeapHdrStart);
+ fSize = EmMemGet32 (fHeapHdrStart + offsetof (MemHeapHeaderType, size));
+ fFirstFree = EmMemGet32 (fHeapHdrStart + offsetof (MemHeapHeaderType, firstFreeChunkOffset));
+ fChunkHdrSize = sizeof (MemChunkHeaderType);
+ fHeapHdrSize = offsetof (MemHeapHeaderType, mstrPtrTbl);
+
+ EmPalmMPT mpt (*this, this->MptStart ());
+ fFirstChunk = this->MptStart () + mpt.Size ();
+ break;
+ }
+
+ default:
+ EmAssert (false);
+ break;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::ResyncAll
+ *
+ * DESCRIPTION: Resynchronize our notion about the contents of the heap
+ * this object wraps up.
+ *
+ * PARAMETERS: delta - optional collection to receive the list of
+ * chunks that are different between the current and
+ * previous states of the heap. This collection is
+ * used when remarking what parts of the heap can be
+ * accessed by different processes.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::ResyncAll (EmPalmChunkList* delta)
+{
+ this->ResyncMPTList ();
+ this->ResyncChunkList (delta);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::ResyncMPTList
+ *
+ * DESCRIPTION: Resynchronize our notion of what master pointer tables
+ * exist in this heap. Does nothing if this heap is
+ * not a "tracked" heap (see the Tracked method).
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::ResyncMPTList (void)
+{
+ if (!this->Tracked ())
+ return;
+
+ emuptr p = this->MptStart ();
+
+ fMPTList.clear ();
+
+ while (1)
+ {
+ EmPalmMPT mpt (*this, p);
+
+ // See if this table looks valid. An exception is thrown if not.
+
+ mpt.Validate (*this);
+
+ fMPTList.push_back (mpt);
+
+ if (mpt.NextTableOffset () == 0)
+ break;
+
+ p = this->fHeapHdrStart + mpt.NextTableOffset ();
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::ResyncChunkList
+ *
+ * DESCRIPTION: Resynchronize our notion of what memory chunks
+ * exist in this heap. Does nothing if this heap is
+ * not a "tracked" heap (see the Tracked method).
+ *
+ * PARAMETERS: delta - optional collection to receive the list of
+ * chunks that are different between the current and
+ * previous states of the heap. This collection is
+ * used when remarking what parts of the heap can be
+ * accessed by different processes.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::ResyncChunkList (EmPalmChunkList* delta)
+{
+ if (!this->Tracked ())
+ return;
+
+ EmPalmChunkList oldList;
+
+ if (delta)
+ oldList = fChunkList;
+
+ emuptr chunkHdr = this->DataStart ();
+
+ fChunkList.clear ();
+
+ while (1)
+ {
+ // Get information about the current chunk.
+
+ EmPalmChunk chunk (*this, chunkHdr);
+
+ // If the size is zero, we've reached the sentinel at the end.
+
+ if (chunk.Size () == 0)
+ {
+ break;
+ }
+
+ // See if this chunk looks valid. An exception is thrown if not.
+
+ chunk.Validate (*this);
+
+ // Push this guy onto our list.
+
+ fChunkList.push_back (chunk);
+
+ // Go on to next chunk.
+
+ chunkHdr += chunk.Size ();
+ }
+
+ if (delta)
+ this->GenerateDeltas (oldList, fChunkList, *delta);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::ResyncPtr
+ *
+ * DESCRIPTION: Resynchronize information about a single particular
+ * chunk. This routine works by assuming that (a) the
+ * chunk already exists in the chunk list and that (b)
+ * only minor changes have been made to the chunk (like
+ * its lockcount having been changed). This routine
+ * should not be called if the chunk has been moved or
+ * resized, since by implication that means that more
+ * than one chunk has changed.
+ *
+ * Does nothing if the heap is not "tracked".
+ *
+ * PARAMETERS: p - pointer to the body of the chunk that changed.
+ *
+ * delta - optional collection to receive the list of
+ * chunks that are different between the current and
+ * previous states of the heap. This collection is
+ * used when remarking what parts of the heap can be
+ * accessed by different processes.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::ResyncPtr (MemPtr p, EmPalmChunkList* delta)
+{
+ if (!this->Tracked ())
+ return;
+
+ EmPalmChunkList::iterator iter = fChunkList.begin ();
+
+ emuptr chunkStart = ((emuptr) p) - fChunkHdrSize;
+
+ while (iter != fChunkList.end ())
+ {
+ if (iter->HeaderStart () == chunkStart)
+ {
+ *iter = EmPalmChunk (*this, chunkStart);
+
+ if (delta)
+ delta->push_back (*iter);
+
+ return;
+ }
+
+ ++iter;
+ }
+
+ EmAssert (false);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::ResyncHdl
+ *
+ * DESCRIPTION: Resynchronize information about a single particular
+ * chunk. This routine works by assuming that (a) the
+ * chunk already exists in the chunk list and that (b)
+ * only minor changes have been made to the chunk (like
+ * its lockcount having been changed). This routine
+ * should not be called if the chunk has been moved or
+ * resized, since by implication that means that more
+ * than one chunk has changed.
+ *
+ * Does nothing if the heap is not "tracked".
+ *
+ * PARAMETERS: h - handle of the chunk that changed.
+ *
+ * delta - optional collection to receive the list of
+ * chunks that are different between the current and
+ * previous states of the heap. This collection is
+ * used when remarking what parts of the heap can be
+ * accessed by different processes.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::ResyncHdl (MemHandle h, EmPalmChunkList* delta)
+{
+ if (!this->Tracked ())
+ return;
+
+ MemPtr p = DerefHandle (h);
+
+ if (p)
+ ResyncPtr (p, delta);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmHeap::GenerateDeltas
+ *
+ * DESCRIPTION: Given the current heap state and a previous heap state,
+ * generate the list of chunks that have changed between
+ * the two states.
+ *
+ * PARAMETERS: oldList - a previous heap state.
+ * newList - the current heap state.
+ * delta - container for changed chunks.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmPalmHeap::GenerateDeltas (const EmPalmChunkList& oldList,
+ const EmPalmChunkList& newList,
+ EmPalmChunkList& delta)
+{
+ // Get iterators for the "before" and "after" chunk lists.
+
+ bool alreadyPushed = false;
+ EmPalmChunkList::const_iterator oldIter = oldList.begin ();
+ EmPalmChunkList::const_iterator newIter = newList.begin ();
+
+ // Clear out the containing receiving the results.
+
+ delta.clear ();
+
+ // Iterate over the "before" and "after" chunk lists until
+ // we reach the end of one of them.
+
+ while (oldIter != oldList.end () && newIter != newList.end ())
+ {
+ // If the two chunks currently being examined are the same,
+ // then the heaps are in sync at this point; proceed to the
+ // next chunks in both heap lists.
+
+ if (oldIter->CompareForDelta (*newIter))
+ {
+ ++oldIter;
+ ++newIter;
+ alreadyPushed = false;
+ continue;
+ }
+
+ // There is a difference between the two chunks. If we haven't
+ // already done so, record the difference by pushing the chunk
+ // from the "after" chunk list onto "delta".
+
+ if (!alreadyPushed)
+ {
+ delta.push_back (*newIter);
+ alreadyPushed = true;
+ }
+
+ // Try to find where the heap sync up again. If we increment
+ // the "after" iterator, make sure we invalid the flag that
+ // says we already added that chunk to the "delta" list.
+
+ if (oldIter->HeaderStart () < newIter->HeaderStart ())
+ {
+ ++oldIter;
+ }
+ else if (oldIter->HeaderStart () > newIter->HeaderStart ())
+ {
+ ++newIter;
+ alreadyPushed = false;
+ }
+ else
+ {
+ ++oldIter;
+ ++newIter;
+ alreadyPushed = false;
+ }
+ }
+
+ // If we reached the end of the "before" list, any remaining
+ // chunks on the "after" list are differences that need to be
+ // added to the "delta" container.
+
+ while (newIter != newList.end ())
+ {
+ delta.push_back (*newIter);
+ ++newIter;
+ }
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmMPT constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmMPT::EmPalmMPT (void) :
+ fVersion (kVersionUnknown),
+ fMptHdrStart (0),
+ fMptHdrSize (0),
+ fSize (0),
+ fNumEntries (0),
+ fNextTblOffset (0)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmMPT constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: heap - heap wrapper object containing this MPT.
+ * mptHdr - pointer to the master pointer table.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmMPT::EmPalmMPT (const EmPalmHeap& heap, emuptr mptHdr) :
+ fVersion (kVersionUnknown),
+ fMptHdrStart (0),
+ fMptHdrSize (0),
+ fSize (0),
+ fNumEntries (0),
+ fNextTblOffset (0)
+{
+ this->GetMPTInfo (heap, mptHdr);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmMPT copy constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: other - MPT object we're to clone.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmMPT::EmPalmMPT (const EmPalmMPT& other) :
+ fVersion (other.fVersion),
+ fMptHdrStart (other.fMptHdrStart),
+ fMptHdrSize (other.fMptHdrSize),
+ fSize (other.fSize),
+ fNumEntries (other.fNumEntries),
+ fNextTblOffset (other.fNextTblOffset)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmMPT::~EmPalmMPT
+ *
+ * DESCRIPTION: Destroy the object. Delete all data members.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmMPT::~EmPalmMPT (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmMPT::Validate
+ *
+ * DESCRIPTION: Validate that the master pointer table looks valid.
+ *
+ * PARAMETERS: heap - heap containing the master pointe table
+ *
+ * RETURNED: Nothing (an exception is thrown on error).
+ *
+ ***********************************************************************/
+
+void EmPalmMPT::Validate (const EmPalmHeap& /*heap*/) const
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmMPT::GetMPTInfo
+ *
+ * DESCRIPTION: Scarf up information about the managed master pointer
+ * table.
+ *
+ * PARAMETERS: heap - heap object containing this master pointer table.
+ * mptHdr - pointer to the master pointer table contained
+ * in the heap.
+ *
+ * RETURNED: Nothing, but many data members are filled in.
+ *
+ ***********************************************************************/
+
+void EmPalmMPT::GetMPTInfo (const EmPalmHeap& heap, emuptr mptHdr)
+{
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ switch (heap.Version ())
+ {
+ case EmPalmHeap::kVersion1:
+ fVersion = kVersion1;
+
+ fMptHdrStart = mptHdr;
+ fMptHdrSize = sizeof (Mem1MstrPtrTableType);
+
+ fNumEntries = EmMemGet16 (mptHdr + offsetof (Mem1MstrPtrTableType, numEntries));
+ fNextTblOffset = EmMemGet16 (mptHdr + offsetof (Mem1MstrPtrTableType, nextTblOffset));
+ break;
+
+ case EmPalmHeap::kVersion2:
+ case EmPalmHeap::kVersion3:
+ case EmPalmHeap::kVersion4:
+ fVersion = kVersion2;
+
+ fMptHdrStart = mptHdr;
+ fMptHdrSize = sizeof (MemMstrPtrTableType);
+
+ fNumEntries = EmMemGet16 (mptHdr + offsetof (MemMstrPtrTableType, numEntries));
+ fNextTblOffset = EmMemGet32 (mptHdr + offsetof (MemMstrPtrTableType, nextTblOffset));
+ break;
+
+ default:
+ EmAssert (false);
+ break;
+ }
+
+ fSize = fMptHdrSize + fNumEntries * sizeof (MemPtr);
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmChunk::EmPalmChunk (void) :
+ fVersion (kVersionUnknown),
+ fChunkHdrStart (0),
+ fChunkHdrSize (0),
+ fFree (0),
+ fMoved (0),
+ fUnused2 (0),
+ fUnused3 (0),
+ fSizeAdj (0),
+ fSize (0),
+ fLockCount (0),
+ fOwner (0),
+ fHOffset (0)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: heap - heap wrapper object containing this chunk.
+ * chunkHdr - pointer to the header of the chunk we're to
+ * wrap up.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmChunk::EmPalmChunk (const EmPalmHeap& heap, emuptr chunkHdr) :
+ fVersion (kVersionUnknown),
+ fChunkHdrStart (0),
+ fChunkHdrSize (0),
+ fFree (0),
+ fMoved (0),
+ fUnused2 (0),
+ fUnused3 (0),
+ fSizeAdj (0),
+ fSize (0),
+ fLockCount (0),
+ fOwner (0),
+ fHOffset (0)
+{
+ this->GetChunkInfo (heap, chunkHdr);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk copy constructor
+ *
+ * DESCRIPTION: Create the object. Initialize all data members.
+ *
+ * PARAMETERS: other - chunk object we're to clone.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmChunk::EmPalmChunk (const EmPalmChunk& other) :
+ fVersion (other.fVersion),
+ fChunkHdrStart (other.fChunkHdrStart),
+ fChunkHdrSize (other.fChunkHdrSize),
+ fFree (other.fFree),
+ fMoved (other.fMoved),
+ fUnused2 (other.fUnused2),
+ fUnused3 (other.fUnused3),
+ fSizeAdj (other.fSizeAdj),
+ fSize (other.fSize),
+ fLockCount (other.fLockCount),
+ fOwner (other.fOwner),
+ fHOffset (other.fHOffset)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk destructor
+ *
+ * DESCRIPTION: Destroy the object. Delete all data members.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmPalmChunk::~EmPalmChunk (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk::Validate
+ *
+ * DESCRIPTION: Validate that the chunk looks valid.
+ *
+ * PARAMETERS: heap - heap containing the master pointe table
+ *
+ * RETURNED: Nothing (an exception is thrown on error).
+ *
+ ***********************************************************************/
+
+void EmPalmChunk::Validate (const EmPalmHeap& heap) const
+{
+ try
+ {
+ // Make sure the chunk is in the heap (this should always be true).
+ // !!! It's not...determine why and document.
+
+ if (!heap.Contains (fChunkHdrStart))
+ {
+ throw (kError_CorruptedHeap_ChunkNotInHeap);
+ }
+
+ // Check the size.
+
+ if (this->End () > heap.End ())
+ {
+ char buffer[20];
+
+ // !!! There's a problem here. These variables are set before the
+ // variable that uses them. Thus, replacements based on these variables
+ // are made before they're ready. The result is that %chunk_size and
+ // %chunk_max still appear in the final message. I'm not sure how, but
+ // this needs to be addressed and fixed...
+
+ sprintf (buffer, "%0x08X", (int) this->Size ());
+ Errors::SetParameter ("%chunk_size", buffer);
+
+ sprintf (buffer, "%0x08X", (int) heap.Size ());
+ Errors::SetParameter ("%chunk_max", buffer);
+
+ throw (kError_CorruptedHeap_ChunkTooLarge);
+ }
+
+ // These bits should not be set.
+
+ if (fUnused2 || fUnused3)
+ {
+ throw (kError_CorruptedHeap_InvalidFlags);
+ }
+
+ if (!fFree)
+ {
+ // If it's a movable chunk, validate that the handle offset
+ // references the handle that points back to the chunk.
+
+ if (fHOffset)
+ {
+ // Get the master pointer to this block. If hOffset is bogus, then
+ // this pointer may be bogus, too.
+
+ emuptr h = fChunkHdrStart - fHOffset * 2;
+
+ // Make sure it is in a master pointer block.
+
+ ITERATE_MPTS(heap, iter, end)
+ {
+ // See if "h" is in this array. If so, break from the loop.
+
+ if (iter->TableContains (h))
+ {
+ break;
+ }
+
+ ++iter;
+ }
+
+ if (iter == end)
+ {
+ throw (kError_CorruptedHeap_HOffsetNotInMPT);
+ }
+
+ // "h" is in a master pointer table. Make sure "h" points back
+ // to the block it's supposed to.
+
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ if (EmMemGet32 (h) != this->BodyStart())
+ {
+ throw (kError_CorruptedHeap_HOffsetNotBackPointing);
+ }
+ }
+
+ // If it's not a movable chunk, it must have a max lock count.
+
+ else
+ {
+ if (fLockCount != memPtrLockCount)
+ {
+ throw (kError_CorruptedHeap_InvalidLockCount);
+ }
+ }
+ }
+
+ // !!! Walk the heap and make sure that fChunkHdrStart is found?
+ }
+ catch (ErrCode err)
+ {
+ // This will throw an EmExceptionReset object.
+
+ Errors::ReportErrCorruptedHeap (err, this->fChunkHdrStart);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk::CompareForDelta
+ *
+ * DESCRIPTION: Compare two chunks to see if they're "close enough"
+ * when determining if something significant has changed.
+ *
+ * PARAMETERS: lhs - chunk to compare "*this" to.
+ *
+ * RETURNED: True if the two chunks are "equal enough".
+ *
+ ***********************************************************************/
+
+Bool EmPalmChunk::CompareForDelta (const EmPalmChunk& lhs) const
+{
+ return
+ fVersion == lhs.fVersion &&
+ fChunkHdrStart == lhs.fChunkHdrStart &&
+ fChunkHdrSize == lhs.fChunkHdrSize &&
+ fFree == lhs.fFree &&
+ fMoved == lhs.fMoved &&
+// fUnused2 == lhs.fUnused2 &&
+// fUnused3 == lhs.fUnused3 &&
+ fSizeAdj == lhs.fSizeAdj &&
+ fSize == lhs.fSize &&
+ (fLockCount > 0) == (lhs.fLockCount > 0) &&
+// fOwner == lhs.fOwner &&
+ fHOffset == lhs.fHOffset;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmPalmChunk::GetChunkInfo
+ *
+ * DESCRIPTION: Scarf up information about the managed chunk.
+ *
+ * PARAMETERS: heapHdr - the pointer to the heap to query.
+ * chunkHdr - pointer to the header of the chunk in the
+ * heap we're to query.
+ *
+ * RETURNED: Nothing, but many data members are filled in.
+ *
+ ***********************************************************************/
+
+void EmPalmChunk::GetChunkInfo (const EmPalmHeap& heap, emuptr chunkHdr)
+{
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ switch (heap.Version ())
+ {
+ case EmPalmHeap::kVersion1:
+ {
+ fVersion = kVersion1;
+ fChunkHdrStart = chunkHdr;
+ fChunkHdrSize = sizeof (Mem1ChunkHeaderType);
+
+ UInt16 size = EmMemGet16 (chunkHdr + offsetof (Mem1ChunkHeaderType, size));
+
+ if (size == 0)
+ {
+ // Leave now. We're at the end of the heap. If we're at the end of RAM,
+ // too, attempts to access subsequent fields will cause a bus error.
+
+ break;
+ }
+
+ UInt8 lockOwner = EmMemGet8 (chunkHdr + offsetof (Mem1ChunkHeaderType, lockOwner));
+ UInt8 flags = EmMemGet8 (chunkHdr + offsetof (Mem1ChunkHeaderType, flags));
+ Int16 hOffset = EmMemGet16 (chunkHdr + offsetof (Mem1ChunkHeaderType, hOffset));
+
+ fFree = (flags & memChunkFlagFree) != 0;
+ fMoved = (flags & memChunkFlagUnused1) != 0;
+ fUnused2 = (flags & memChunkFlagUnused2) != 0;
+ fUnused3 = (flags & memChunkFlagUnused3) != 0;
+ fSizeAdj = (flags & mem1ChunkFlagSizeAdj);
+ fSize = size;
+ fLockCount = (lockOwner & mem1ChunkLockMask) >> 4;
+ fOwner = (lockOwner & mem1ChunkOwnerMask);
+ fHOffset = hOffset;
+
+ break;
+ }
+
+ case EmPalmHeap::kVersion2:
+ case EmPalmHeap::kVersion3:
+ case EmPalmHeap::kVersion4:
+ {
+ fVersion = kVersion2;
+ fChunkHdrStart = chunkHdr;
+ fChunkHdrSize = sizeof (MemChunkHeaderType);
+
+ UInt32 part1 = EmMemGet32 (chunkHdr);
+ UInt32 part2 = 0;
+
+ if ((part1 & 0x00FFFFFF) != 0)
+ {
+ part2 = EmMemGet32 (chunkHdr + 4);
+ }
+
+ fFree = (part1 & 0x80000000) != 0;
+ fMoved = (part1 & 0x40000000) != 0;
+ fUnused2 = (part1 & 0x20000000) != 0;
+ fUnused3 = (part1 & 0x10000000) != 0;
+ fSizeAdj = (part1 & 0x0F000000) >> 24;
+ fSize = (part1 & 0x00FFFFFF);
+ fLockCount = (part2 & 0xF0000000) >> 28;
+ fOwner = (part2 & 0x0F000000) >> 24;
+ fHOffset = (part2 & 0x00FFFFFF);
+
+ // hOffset is a signed value; make sure we keep it that way
+ // when we extract it by hand.
+
+ if ((fHOffset & 0x00800000) != 0)
+ {
+ fHOffset |= 0xFF000000;
+ }
+
+ break;
+ }
+
+ default:
+ EmAssert (false);
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ operator << (EmStream&, EmPalmChunk&)
+// ---------------------------------------------------------------------------
+
+EmStream& operator << (EmStream& s, const EmPalmChunk& chunk)
+{
+ const long kVersion = 1;
+
+ s << kVersion;
+
+ s << chunk.fVersion;
+
+ s << chunk.fChunkHdrStart;
+ s << chunk.fChunkHdrSize;
+
+ s << chunk.fFree;
+ s << chunk.fMoved;
+ s << chunk.fUnused2;
+ s << chunk.fUnused3;
+ s << chunk.fSizeAdj;
+ s << chunk.fSize;
+
+ s << chunk.fLockCount;
+ s << chunk.fOwner;
+ s << chunk.fHOffset;
+
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ operator >> (EmStream&, EmPalmChunk&)
+// ---------------------------------------------------------------------------
+
+EmStream& operator >> (EmStream& s, EmPalmChunk& chunk)
+{
+ long version;
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> chunk.fVersion;
+
+ s >> chunk.fChunkHdrStart;
+ s >> chunk.fChunkHdrSize;
+
+ s >> chunk.fFree;
+ s >> chunk.fMoved;
+ s >> chunk.fUnused2;
+ s >> chunk.fUnused3;
+ s >> chunk.fSizeAdj;
+ s >> chunk.fSize;
+
+ s >> chunk.fLockCount;
+ s >> chunk.fOwner;
+ s >> chunk.fHOffset;
+ }
+
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ operator << (EmStream&, EmPalmMPT&)
+// ---------------------------------------------------------------------------
+
+EmStream& operator << (EmStream& s, const EmPalmMPT& mpt)
+{
+ const long kVersion = 1;
+
+ s << kVersion;
+
+ s << mpt.fVersion;
+
+ s << mpt.fMptHdrStart;
+ s << mpt.fMptHdrSize;
+ s << mpt.fSize;
+
+ s << mpt.fNumEntries;
+ s << mpt.fNextTblOffset;
+
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ operator >> (EmStream&, EmPalmMPT&)
+// ---------------------------------------------------------------------------
+
+EmStream& operator >> (EmStream& s, EmPalmMPT& mpt)
+{
+ long version;
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> mpt.fVersion;
+
+ s >> mpt.fMptHdrStart;
+ s >> mpt.fMptHdrSize;
+ s >> mpt.fSize;
+
+ s >> mpt.fNumEntries;
+ s >> mpt.fNextTblOffset;
+ }
+
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ operator << (EmStream&, EmPalmHeap&)
+// ---------------------------------------------------------------------------
+
+EmStream& operator << (EmStream& s, const EmPalmHeap& heap)
+{
+ const long kVersion = 1;
+
+ s << kVersion;
+
+ s << heap.fVersion;
+ s << heap.fHeapID;
+
+ s << heap.fHeapHdrStart;
+ s << heap.fHeapHdrSize;
+ s << heap.fFirstChunk;
+
+ s << heap.fFlags;
+ s << heap.fSize;
+ s << heap.fFirstFree;
+ s << heap.fChunkHdrSize;
+
+ s << heap.fChunkList;
+ s << heap.fMPTList;
+
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ operator >> (EmStream&, EmPalmHeap&)
+// ---------------------------------------------------------------------------
+
+EmStream& operator >> (EmStream& s, EmPalmHeap& heap)
+{
+ long version;
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> heap.fVersion;
+ s >> heap.fHeapID;
+
+ s >> heap.fHeapHdrStart;
+ s >> heap.fHeapHdrSize;
+ s >> heap.fFirstChunk;
+
+ s >> heap.fFlags;
+ s >> heap.fSize;
+ s >> heap.fFirstFree;
+ s >> heap.fChunkHdrSize;
+
+ s >> heap.fChunkList;
+ s >> heap.fMPTList;
+ }
+
+ return s;
+}
+