//===- PoolAllocatorBitMask.cpp - Implementation of poolallocator runtime -===//
// 
//                       The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// This file is one possible implementation of the LLVM pool allocator runtime
// library.
//
// This uses the 'Ptr1' field to maintain a linked list of slabs that are either
// empty or are partially allocated from.  The 'Ptr2' field of the PoolTy is
// used to track a linked list of slabs which are full, ie, all elements have
// been allocated from them.
//
//===----------------------------------------------------------------------===//
// NOTE:
//  1) Some of the bounds checking code may appear strange.  The reason is that
//     it is manually inlined to squeeze out some more performance.  Please
//     don't change it.
//===----------------------------------------------------------------------===//

#include "PoolAllocator.h"
#include "PageManager.h"
#include "Report.h"
#include "adl_splay.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/mman.h>
//#include <sys/ucontext.h>
#define DEBUG(x) 

// global variable declarations
extern unsigned PPageSize;
static unsigned globalallocID = 0;
static unsigned globalfreeID = 0;
static void * globalTemp = 0;
static PoolTy dummyPool;
static unsigned dummyInitialized = 0;
unsigned poolmemusage = 0;

// Invalid address range
#if !defined(__linux__)
unsigned InvalidUpper = 0x00000000;
unsigned InvalidLower = 0x00000003;
#endif

// Splay tree of external objects
extern void * ExternalObjects;

/* Set to 1 to log object registrations */
static /*const*/ unsigned logregs = 0;

// signal handler
static void bus_error_handler(int, siginfo_t *, void *);

// creates a new PtrMetaData structure to record pointer information
static inline void updatePtrMetaData(PDebugMetaData, unsigned, void *);
static PDebugMetaData createPtrMetaData (unsigned,
                                         unsigned,
                                         void *,
                                         void *,
                                         void *);

//===----------------------------------------------------------------------===//
//
//  PoolSlab implementation
//
//===----------------------------------------------------------------------===//

// PoolSlab Structure - Hold multiple objects of the current node type.
// Invariants: FirstUnused <= UsedEnd
//
struct PoolSlab {
  PoolSlab **PrevPtr, *Next;
  bool isSingleArray;   // If this slab is used for exactly one array
  unsigned allocated; // Number of bytes allocated
  PoolSlab * Canonical; // For stack slabs, the canonical page

private:
  // FirstUnused - First empty node in slab
  unsigned short FirstUnused;

  // UsedBegin - The first node in the slab that is used.
  unsigned short UsedBegin;

  // UsedEnd - 1 past the last allocated node in slab. 0 if slab is empty
  unsigned short UsedEnd;

  // NumNodesInSlab - This contains the number of nodes in this slab, which
  // effects the size of the NodeFlags vector, and indicates the number of nodes
  // which are in the slab.
  unsigned int NumNodesInSlab;

  // Size of Slab - For single array slabs, specifies the size of the slab in
  //                bytes from beginning to end (including slab header).
  //
public:
  unsigned int SizeOfSlab;

private:
  // NodeFlagsVector - This array contains two bits for each node in this pool
  // slab.  The first (low address) bit indicates whether this node has been
  // allocated, and the second (next higher) bit indicates whether this is the
  // start of an allocation.
  //
  // This is a variable sized array, which has 2*NumNodesInSlab bits (rounded up
  // to 4 bytes).
  unsigned NodeFlagsVector[1];
  
  bool isNodeAllocated(unsigned NodeNum) {
    return NodeFlagsVector[NodeNum/16] & (1 << (NodeNum & 15));
  }

  void markNodeAllocated(unsigned NodeNum) {
    NodeFlagsVector[NodeNum/16] |= 1 << (NodeNum & 15);
  }

  void markNodeFree(unsigned NodeNum) {
    NodeFlagsVector[NodeNum/16] &= ~(1 << (NodeNum & 15));
  }

  void setStartBit(unsigned NodeNum) {
    NodeFlagsVector[NodeNum/16] |= 1 << ((NodeNum & 15)+16);
  }

  bool isStartOfAllocation(unsigned NodeNum) {
    return NodeFlagsVector[NodeNum/16] & (1 << ((NodeNum & 15)+16));
  }
  
  void clearStartBit(unsigned NodeNum) {
    NodeFlagsVector[NodeNum/16] &= ~(1 << ((NodeNum & 15)+16));
  }

  void assertOkay (void) {
    assert (FirstUnused <= UsedEnd);
    assert ((UsedEnd == getSlabSize()) || (!isNodeAllocated(UsedEnd)));
    assert ((FirstUnused == getSlabSize()) || (!isNodeAllocated(FirstUnused)));
  }
public:
  // create - Create a new (empty) slab and add it to the end of the Pools list.
  static PoolSlab *create(PoolTy *Pool);

  // createSingleArray - Create a slab for a large singlearray with NumNodes
  // entries in it, returning the pointer into the pool directly.
  static void *createSingleArray(PoolTy *Pool, unsigned NumNodes);

  // getSlabSize - Return the number of nodes that each slab should contain.
  static unsigned getSlabSize(PoolTy *Pool) {
    // We need space for the header...
    unsigned NumNodes = PageSize-sizeof(PoolSlab);
    
    // We need space for the NodeFlags...
    // FIXME:
    //  We unconditionally round up a byte.  We should only do that if
    //  necessary.
    unsigned NodeFlagsBytes = (NumNodes/Pool->NodeSize * 2 / 8) + 1;
    NumNodes -= (NodeFlagsBytes+3) & ~3;  // Round up to int boundaries.

    // Divide the remainder among the nodes!
    return NumNodes / Pool->NodeSize;
  }

  void addToList(PoolSlab **PrevPtrPtr) {
    PoolSlab *InsertBefore = *PrevPtrPtr;
    *PrevPtrPtr = this;
    PrevPtr = PrevPtrPtr;
    Next = InsertBefore;
    if (InsertBefore) InsertBefore->PrevPtr = &Next;
  }

  void unlinkFromList() {
    *PrevPtr = Next;
    if (Next) Next->PrevPtr = PrevPtr;
  }

  unsigned getSlabSize() const {
    return NumNodesInSlab;
  }

  // destroy - Release the memory for the current object.
  void destroy();

  // isEmpty - This is a quick check to see if this slab is completely empty or
  // not.
  bool isEmpty() const { return UsedEnd == 0; }

  // isFull - This is a quick check to see if the slab is completely allocated.
  //
  bool isFull() const { return isSingleArray || (FirstUnused == getSlabSize()); }

  // allocateSingle - Allocate a single element from this pool, returning -1 if
  // there is no space.
  int allocateSingle();

  // allocateMultiple - Allocate multiple contiguous elements from this pool,
  // returning -1 if there is no space.
  int allocateMultiple(unsigned Num);

  // getElementAddress - Return the address of the specified element.
  void *getElementAddress(unsigned ElementNum, unsigned ElementSize) {
    char *Data = (char*)&NodeFlagsVector[((unsigned)NumNodesInSlab+15)/16];
    return &Data[ElementNum*ElementSize];
  }
  
  const void *getElementAddress(unsigned ElementNum, unsigned ElementSize)const{
    const char *Data =
      (const char *)&NodeFlagsVector[(unsigned)(NumNodesInSlab+15)/16];
    return &Data[ElementNum*ElementSize];
  }

  // containsElement - Return the element number of the specified address in
  // this slab.  If the address is not in slab, return -1.
  int containsElement(void *Ptr, unsigned ElementSize) const;

  // freeElement - Free the single node, small array, or entire array indicated.
  void freeElement(unsigned short ElementIdx);
  
  // getSize --- size of an allocation
  unsigned getSize(void *Node, unsigned ElementSize);
  
  // lastNodeAllocated - Return one past the last node in the pool which is
  // before ScanIdx, that is allocated.  If there are no allocated nodes in this
  // slab before ScanIdx, return 0.
  unsigned lastNodeAllocated(unsigned ScanIdx);
};

// create - Create a new (empty) slab and add it to the end of the Pools list.
PoolSlab *
PoolSlab::create(PoolTy *Pool) {
  unsigned NodesPerSlab = getSlabSize(Pool);

  unsigned Size = sizeof(PoolSlab) + 4*((NodesPerSlab+15)/16) +
    Pool->NodeSize*getSlabSize(Pool);
  assert(Size <= PageSize && "Trying to allocate a slab larger than a page!");
  PoolSlab *PS = (PoolSlab*)AllocatePage();

  PS->NumNodesInSlab = NodesPerSlab;
  PS->isSingleArray = 0;  // Not a single array!
  PS->FirstUnused = 0;    // Nothing allocated.
  PS->UsedBegin   = 0;    // Nothing allocated.
  PS->UsedEnd     = 0;    // Nothing allocated.
  PS->allocated   = 0;    // No bytes allocated.

  for (unsigned i = 0; i < PS->getSlabSize(); ++i)
  {
    PS->markNodeFree(i);
    PS->clearStartBit(i);
  }

  // Add the slab to the list...
  PS->addToList((PoolSlab**)&Pool->Ptr1);
  //  printf(" creating a slab %x\n", PS);
  return PS;
}

void *
PoolSlab::createSingleArray(PoolTy *Pool, unsigned NumNodes) {
  // FIXME: This wastes memory by allocating space for the NodeFlagsVector
  unsigned NodesPerSlab = getSlabSize(Pool);
  assert(NumNodes > NodesPerSlab && "No need to create a single array!");

  unsigned NumPages = (NumNodes+NodesPerSlab-1)/NodesPerSlab;
  PoolSlab *PS = (PoolSlab*)AllocateNPages(NumPages);

  assert(PS && "poolalloc: Could not allocate memory!");

  if (Pool->NumSlabs > AddrArrSize)
    Pool->Slabs->insert((void*)PS);
  else if (Pool->NumSlabs == AddrArrSize) {
    // Create the hash_set
    Pool->Slabs = new hash_set<void *>;
    Pool->Slabs->insert((void *)PS);
    for (unsigned i = 0; i < AddrArrSize; ++i)
      Pool->Slabs->insert((void *) Pool->SlabAddressArray[i]);
  } else {
    // Insert it in the array
    Pool->SlabAddressArray[Pool->NumSlabs] = (unsigned) PS;
  }
  Pool->NumSlabs++;
  
  PS->addToList((PoolSlab**)&Pool->LargeArrays);

  PS->allocated   = 0xffffffff;    // No bytes allocated.
  PS->isSingleArray = 1;
  PS->NumNodesInSlab = NodesPerSlab;
  PS->SizeOfSlab     = (NumPages * PageSize);
  *(unsigned*)&PS->FirstUnused = NumPages;
  return PS->getElementAddress(0, 0);
}

void
PoolSlab::destroy() {
  if (isSingleArray)
    for (unsigned NumPages = *(unsigned*)&FirstUnused; NumPages != 1;--NumPages)
      FreePage((char*)this + (NumPages-1)*PageSize);

  FreePage(this);
}

// allocateSingle - Allocate a single element from this pool, returning -1 if
// there is no space.
int
PoolSlab::allocateSingle() {
  // If the slab is a single array, go on to the next slab.  Don't allocate
  // single nodes in a SingleArray slab.
  if (isSingleArray) return -1;

  unsigned SlabSize = getSlabSize();

  // Check to see if there are empty entries at the end of the slab...
  if (UsedEnd < SlabSize) {
    // Mark the returned entry used
    unsigned short UE = UsedEnd;
    markNodeAllocated(UE);
    setStartBit(UE);
    
    // If we are allocating out the first unused field, bump its index also
    if (FirstUnused == UE) {
      FirstUnused++;
    }
    
    // Updated the UsedBegin field if necessary
    if (UsedBegin > UE) UsedBegin = UE;

    // Return the entry, increment UsedEnd field.
    ++UsedEnd;
    assertOkay();
    allocated += 1;
    return UE;
  }
  
  // If not, check to see if this node has a declared "FirstUnused" value that
  // is less than the number of nodes allocated...
  //
  if (FirstUnused < SlabSize) {
    // Successfully allocate out the first unused node
    unsigned Idx = FirstUnused;
    markNodeAllocated(Idx);
    setStartBit(Idx);
    
    // Increment FirstUnused to point to the new first unused value...
    // FIXME: this should be optimized
    unsigned short FU = FirstUnused;
    do {
      ++FU;
    } while ((FU != SlabSize) && (isNodeAllocated(FU)));
    FirstUnused = FU;

    // Updated the UsedBegin field if necessary
    if (UsedBegin > Idx) UsedBegin = Idx;

    assertOkay();
    allocated += 1;
    return Idx;
  }
  
  assertOkay();
  return -1;
}

// allocateMultiple - Allocate multiple contiguous elements from this pool,
// returning -1 if there is no space.
int
PoolSlab::allocateMultiple(unsigned Size) {
  // Do not allocate small arrays in SingleArray slabs
  if (isSingleArray) return -1;

  // For small array allocation, check to see if there are empty entries at the
  // end of the slab...
  if (UsedEnd+Size <= getSlabSize()) {
    // Mark the returned entry used and set the start bit
    unsigned UE = UsedEnd;
    setStartBit(UE);
    for (unsigned i = UE; i != UE+Size; ++i)
      markNodeAllocated(i);
    
    // If we are allocating out the first unused field, bump its index also
    if (FirstUnused == UE)
      FirstUnused += Size;

    // Updated the UsedBegin field if necessary
    if (UsedBegin > UE) UsedBegin = UE;

    // Increment UsedEnd
    UsedEnd += Size;

    // Return the entry
    assertOkay();
    allocated += Size;
    return UE;
  }

  // If not, check to see if this node has a declared "FirstUnused" value
  // starting which Size nodes can be allocated
  //
  unsigned Idx = FirstUnused;
  while (Idx+Size <= getSlabSize()) {
    assert(!isNodeAllocated(Idx) && "FirstUsed is not accurate!");

    // Check if there is a continuous array of Size nodes starting FirstUnused
    unsigned LastUnused = Idx+1;
    for (; (LastUnused != Idx+Size) && (!isNodeAllocated(LastUnused)); ++LastUnused)
      /*empty*/;

    // If we found an unused section of this pool which is large enough, USE IT!
    if (LastUnused == Idx+Size) {
      setStartBit(Idx);
      // FIXME: this loop can be made more efficient!
      for (unsigned i = Idx; i != Idx + Size; ++i)
        markNodeAllocated(i);

      // This should not be allocating on the end of the pool, so we don't need
      // to bump the UsedEnd pointer.
      assert(Idx != UsedEnd && "Shouldn't allocate at end of pool!");

      // If we are allocating out the first unused field, bump its index also.
      if (Idx == FirstUnused) {
        unsigned SlabSize = getSlabSize();
        unsigned i;
        for (i = FirstUnused+Size; i < UsedEnd; ++i) {
          if (!isNodeAllocated(i)) {
            break;
          }
        }
        FirstUnused = i;
        if (isNodeAllocated(i))
          FirstUnused = SlabSize;
      }
      
      // Updated the UsedBegin field if necessary
      if (UsedBegin > Idx) UsedBegin = Idx;

      // Return the entry
      assertOkay();
      allocated += Size;
      return Idx;
    }

    // Otherwise, try later in the pool.  Find the next unused entry.
    Idx = LastUnused;
    while (Idx+Size <= getSlabSize() && isNodeAllocated(Idx))
      ++Idx;
  }

  assertOkay();
  return -1;
}

// getSize
unsigned PoolSlab::getSize(void *Ptr, unsigned ElementSize) {
  if (isSingleArray) abort();
  const void *FirstElement = getElementAddress(0, 0);
  if (FirstElement <= Ptr) {
    unsigned Delta = (char*)Ptr-(char*)FirstElement;
    unsigned Index = Delta/ElementSize;
    
    if (Index < getSlabSize()) {
      //we have the index now do something like free
      assert(isStartOfAllocation(Index) &&
        "poolrealloc: Attempt to realloc from the middle of allocated array\n");
      unsigned short ElementEndIdx = Index + 1;
      
      // FIXME: This should use manual strength reduction to produce decent code.
      unsigned short UE = UsedEnd;
      while (ElementEndIdx != UE &&
          !isStartOfAllocation(ElementEndIdx) && 
          isNodeAllocated(ElementEndIdx)) {
        ++ElementEndIdx;
      }
      return (ElementEndIdx - Index);
    }
  }
  if (logregs)
  {
    fprintf(stderr, "PoolSlab::getSize failed!\n");
    fflush(stderr);
  }
  abort();
}


// containsElement - Return the element number of the specified address in
// this slab.  If the address is not in slab, return -1.
int
PoolSlab::containsElement(void *Ptr, unsigned ElementSize) const {
  const void *FirstElement = getElementAddress(0, 0);
  if (FirstElement <= Ptr) {
    unsigned Delta = (char*)Ptr-(char*)FirstElement;
    if (isSingleArray) {
      if (Delta < SizeOfSlab) return Delta/ElementSize;
    }
    unsigned Index = Delta/ElementSize;
    if (Index < getSlabSize()) {
      if (Delta % ElementSize != 0) {
        fprintf(stderr, "Freeing pointer into the middle of an element!\n");
        fflush(stderr);
    abort();
      }
      
      return Index;
    }
  }
  return -1;
}


// freeElement - Free the single node, small array, or entire array indicated.
void
PoolSlab::freeElement(unsigned short ElementIdx) {
  if (!isNodeAllocated(ElementIdx)) return;
  //  assert(isNodeAllocated(ElementIdx) &&
  //         "poolfree: Attempt to free node that is already freed\n");
#if 0
  assert(!isSingleArray && "Cannot free an element from a single array!");
#else
#if 0
  if (isSingleArray) {
    this->addToList((PoolSlab**)&Pool->FreeLargeArrays);
    return;
  }
#endif
#endif

  // Mark this element as being free!
  markNodeFree(ElementIdx);
  --allocated;

  // If this slab is not a SingleArray
  assert(isStartOfAllocation(ElementIdx) &&
         "poolfree: Attempt to free middle of allocated array\n");
  
  // Free the first cell
  clearStartBit(ElementIdx);
  markNodeFree(ElementIdx);
  
  // Free all nodes if this was a small array allocation.
  unsigned short ElementEndIdx = ElementIdx + 1;

  // FIXME: This should use manual strength reduction to produce decent code.
  unsigned short UE = UsedEnd;
  while (ElementEndIdx != UE &&
         !isStartOfAllocation(ElementEndIdx) && 
         isNodeAllocated(ElementEndIdx)) {
    markNodeFree(ElementEndIdx);
    --allocated;
    ++ElementEndIdx;
  }
  
  // Update the first free field if this node is below the free node line
  if (ElementIdx < FirstUnused) FirstUnused = ElementIdx;

  // Update the first used field if this node was the first used.
  if (ElementIdx == UsedBegin) UsedBegin = ElementEndIdx;
  
  // If we are freeing the last element in a slab, shrink the UsedEnd marker
  // down to the last used node.
  if (ElementEndIdx == UE) {
#if 0
      printf("FU: %d, UB: %d, UE: %d  FREED: [%d-%d)",
           FirstUnused, UsedBegin, UsedEnd, ElementIdx, ElementEndIdx);
#endif

    // If the user is freeing the slab entirely in-order, it's quite possible
    // that all nodes are free in the slab.  If this is the case, simply reset
    // our pointers.
    if (UsedBegin == UE) {
      FirstUnused = 0;
      UsedBegin = 0;
      UsedEnd = 0;
      assertOkay();
    } else if (FirstUnused == ElementIdx) {
      // Freed the last node(s) in this slab.
      FirstUnused = ElementIdx;
      UsedEnd = ElementIdx;
      assertOkay();
    } else {
      UsedEnd = lastNodeAllocated(ElementIdx);
      if (FirstUnused > UsedEnd) FirstUnused = UsedEnd;
      assertOkay();
      assert(FirstUnused <= UsedEnd+1 &&
             "FirstUnused field was out of date!");
    }
  }
  assertOkay();
}

unsigned
PoolSlab::lastNodeAllocated(unsigned ScanIdx) {
  // Check the last few nodes in the current word of flags...
  unsigned CurWord = ScanIdx/16;
  unsigned short Flags = NodeFlagsVector[CurWord] & 0xFFFF;
  if (Flags) {
    // Mask off nodes above this one
    Flags &= (1 << ((ScanIdx & 15)+1))-1;
    if (Flags) {
      // If there is still something in the flags vector, then there is a node
      // allocated in this part.  The goto is a hack to get the uncommonly
      // executed code away from the common code path.
      //printf("A: ");
      goto ContainsAllocatedNode;
    }
  }

  // Ok, the top word doesn't contain anything, scan the whole flag words now.
  --CurWord;
  while (CurWord != ~0U) {
    Flags = NodeFlagsVector[CurWord] & 0xFFFF;
    if (Flags) {
      // There must be a node allocated in this word!
      //printf("B: ");
      goto ContainsAllocatedNode;
    }
    CurWord--;
  }
  return 0;

ContainsAllocatedNode:
  // Figure out exactly which node is allocated in this word now.  The node
  // allocated is the one with the highest bit set in 'Flags'.
  //
  // This should use __builtin_clz to get the value, but this builtin is only
  // available with GCC 3.4 and above.  :(
  assert(Flags && "Should have allocated node!");
  
  unsigned short MSB;
#if GCC3_4_EVENTUALLY
  MSB = 16 - ::__builtin_clz(Flags);
#else
  for (MSB = 15; (Flags & (1U << MSB)) == 0; --MSB)
    /*empty*/;
#endif

  assert((1U << MSB) & Flags);   // The bit should be set
  assert((~(1U << MSB) & Flags) < Flags);// Removing it should make flag smaller
  ScanIdx = CurWord*16 + MSB;
  assert(isNodeAllocated(ScanIdx));
  return (ScanIdx+1);
}


//===----------------------------------------------------------------------===//
//
//  StackSlab implementation
//
//===----------------------------------------------------------------------===//

//
// Structure: StackSlab
//
// Description:
//  A stack slab is similar to a pool slab but simple and smaller.  It is used
//  for stack allocations that have been promoted to the heap.
struct StackSlab {
  public:
    // Pointer to canonical address of stack slab
    StackSlab * Canonical;

    // Pointers for linking in the stack slab
    StackSlab **PrevPtr, *Next;

    // Top of stack
    unsigned int * tos;

    // Data for the stack
    unsigned int data[1020];

    static StackSlab *create (void * p) {
      StackSlab *SS = (StackSlab*) p;
      SS->tos = &(SS->data[0]);
      return SS;
    }

    unsigned char * allocate (unsigned int size) {
      //
      // We will return a pointer to the current top of stack.
      //
      unsigned char * retvalue = (unsigned char *) (tos);

      //
      // Adjust the top of stack down to the next free object.
      //
      size = (size + 3) & (~3u);
      unsigned int NumberOfInts = size / sizeof (unsigned int);
      tos += NumberOfInts;
      assert (tos < &(data[1020]));
      return retvalue;
    }

    void clear (void) {
      tos = data;
    }

    void addToList(StackSlab **PrevPtrPtr) {
      StackSlab *InsertBefore = *PrevPtrPtr;
      *PrevPtrPtr = this;
      PrevPtr = PrevPtrPtr;
      Next = InsertBefore;
      if (InsertBefore) InsertBefore->PrevPtr = &Next;
    }

    void unlinkFromList() {
      *PrevPtr = Next;
      if (Next) Next->PrevPtr = PrevPtr;
    }
};

//===----------------------------------------------------------------------===//
//
//  Pool allocator library implementation
//
//===----------------------------------------------------------------------===//

void
pool_init_runtime (unsigned Dangling) {
  //
  // Configure the allocator.
  //
  extern ConfigData ConfigData;
  ConfigData.RemapObjects = Dangling;

  //
  // Allocate a range of memory for rewrite pointers.
  //
#if !defined(__linux__)
  const unsigned invalidsize = 1 * 1024 * 1024 * 1024;
  void * Addr = mmap (0, invalidsize, 0, MAP_SHARED | MAP_ANON, -1, 0);
  if (Addr == MAP_FAILED) {
     perror ("mmap:");
     fflush (stdout);
     fflush (stderr);
     assert(0 && "valloc failed\n");
  }
  madvise (Addr, invalidsize, MADV_FREE);
  InvalidLower = (unsigned int) Addr;
  InvalidUpper = (unsigned int) Addr + invalidsize;
#endif

  //
  // Install hooks for catching allocations outside the scope of SAFECode
  //
#if 0
  extern void installAllocHooks(void);
  installAllocHooks();
#endif
  return;
}

// poolinit - Initialize a pool descriptor to empty
//
void
poolinit(PoolTy *Pool, unsigned NodeSize) {
  assert(Pool && "Null pool pointer passed into poolinit!\n");
  DEBUG(printf("pool init %x, %d\n", Pool, NodeSize);)

  // Ensure the page manager is initialized
  InitializePageManager();

  // We must alway return unique pointers, even if they asked for 0 bytes
  Pool->NodeSize = NodeSize ? NodeSize : 1;
  // Initialize the splay tree
  Pool->Objects = Pool->OOB = Pool->DPTree = 0;
  Pool->DPTree = 0;
  Pool->Ptr1 = Pool->Ptr2 = 0;
  Pool->LargeArrays = 0;
  Pool->StackSlabs = Pool->FreeStackSlabs = 0;
  // For SAFECode, we set FreeablePool to 0 always
  //  Pool->FreeablePool = 0;
  Pool->AllocadPool = -1;
  Pool->allocaptr = 0;
  Pool->lastUsed = 0;
  Pool->prevPage[0] = 0;
  Pool->prevPage[1] = 0;
  // Initialize the SlabAddressArray to zero
  for (int i = 0; i < AddrArrSize; ++i) {
    Pool->SlabAddressArray[i] = 0;
  }
  Pool->NumSlabs = 0;
#if 0
  Pool->RegNodes = new std::map<void*,unsigned>;
#endif
  
  if (dummyInitialized == 1)
    return;
  
  dummyPool.NodeSize = NodeSize ? NodeSize : 1;
  // Initialize the splay tree
  dummyPool.Objects = dummyPool.OOB = dummyPool.DPTree = 0;
  dummyPool.Ptr1 = dummyPool.Ptr2 = 0;
  dummyPool.LargeArrays = 0;
  // For SAFECode, we set FreeablePool to 0 always
  //  Pool->FreeablePool = 0;
  dummyPool.AllocadPool = -1;
  dummyPool.allocaptr = 0;
  dummyPool.lastUsed = 0;
  dummyPool.prevPage[0] = 0;
  dummyPool.prevPage[1] = 0;
  // Initialize the SlabAddressArray to zero
  for (int i = 0; i < AddrArrSize; ++i) {
    dummyPool.SlabAddressArray[i] = 0;
  }
  dummyPool.NumSlabs = 0;
#if 0
  dummyPool.RegNodes = new std::map<void*,unsigned>;
#endif
  dummyInitialized = 1;
}

void
poolmakeunfreeable(PoolTy *Pool) {
  assert(Pool && "Null pool pointer passed in to poolmakeunfreeable!\n");
  //  Pool->FreeablePool = 0;
}

// pooldestroy - Release all memory allocated for a pool
//
// FIXME: determine how to adjust debug logs when 
//        pooldestroy is called
void
pooldestroy(PoolTy *Pool) {
  assert(Pool && "Null pool pointer passed in to pooldestroy!\n");
  adl_splay_delete_tag(&Pool->Objects, Pool);
  //adl_splay_delete_tag(&Pool->DPTree, Pool);
  if (Pool->AllocadPool) return;

  // Remove all registered pools
#if 0
  delete Pool->RegNodes;
#endif

  if (Pool->NumSlabs > AddrArrSize) {
    Pool->Slabs->clear();
    delete Pool->Slabs;
  }

  // Free any partially allocated slabs
  PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
  while (PS) {
    PoolSlab *Next = PS->Next;
    PS->destroy();
    PS = Next;
  }

  // Free the completely allocated slabs
  PS = (PoolSlab*)Pool->Ptr2;
  while (PS) {
    PoolSlab *Next = PS->Next;
    PS->destroy();
    PS = Next;
  }

  // Free the large arrays
  PS = (PoolSlab*)Pool->LargeArrays;
  while (PS) {
    PoolSlab *Next = PS->Next;
    PS->destroy();
    PS = Next;
  }

}


// Function: poolallocarray()
//
// Description:
//  This is a helper function used to implement poolalloc() when the number of
//  nodes to allocate is not 1.
//
// Inputs:
//  Pool - A pointer to the pool from which to allocate.
//  Size - The number of nodes to allocate.
//
// FIXME: look into globalTemp, make it a pass by reference arg instead of
//          a global variable.
// FIXME: determine whether Size is bytes or number of nodes.
static void *
poolallocarray(PoolTy* Pool, unsigned Size) {
  assert(Pool && "Null pool pointer passed into poolallocarray!\n");
  
  // check to see if we need to allocate a single large array
  if (Size > PoolSlab::getSlabSize(Pool)) {
    if (logregs) {
      fprintf(stderr, " poolallocarray:694: Size = %d, SlabSize = %d\n", Size, PoolSlab::getSlabSize(Pool));
      fflush(stderr);
    }
    globalTemp = (PoolSlab*) PoolSlab::createSingleArray(Pool, Size);
    unsigned offset = (unsigned)globalTemp & (PPageSize - 1);
    void * retAddress = (void *)((unsigned)(globalTemp) & ~(PPageSize - 1));

    if (logregs) {
      fprintf(stderr, " poolallocarray:704: globalTemp = 0x%08x, offset = 0x%08x, retAddress = 0x%08x\n",
          (unsigned)globalTemp, offset, (unsigned)retAddress);
      fflush(stderr);
    }
    return (void*) ((unsigned)retAddress + offset);
  }
 
  PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
  unsigned offset;

  // Loop through all of the slabs looking for one with an opening
  for (; PS; PS = PS->Next) {
    int Element = PS->allocateMultiple(Size);
    if (Element != -1) {
    // We allocated an element.  Check to see if this slab has been completely
    // filled up.  If so, move it to the Ptr2 list.
      if (PS->isFull()) {
        PS->unlinkFromList();
        PS->addToList((PoolSlab**)&Pool->Ptr2);
      }
      
      // insert info into adl splay tree for poolcheck runtime
      //unsigned NodeSize = Pool->NodeSize;
      globalTemp = PS->getElementAddress(Element, Pool->NodeSize);
      offset = (unsigned)globalTemp & (PPageSize - 1); 
      //adl_splay_insert(&(Pool->Objects), globalTemp, 
      //          (unsigned)((Size*NodeSize) - NodeSize + 1), (Pool));
      if(logregs) {fprintf(stderr, " poolallocarray:731:before RemapObject\n");}
      //  remap the page to get a shadow page (dangling pointer detection library)
      PS = (PoolSlab *) RemapObject(globalTemp, Size*Pool->NodeSize);
      if (logregs) {
        fprintf(stderr, " poolallocarray:735: globalTemp = 0x%x\n", (unsigned)globalTemp);
        fprintf(stderr ," poolallocarray:736: PS = 0x%08x, offset = 0x%08x, retAddress = 0x%08x\n",
              (unsigned)PS, offset, (unsigned)PS + offset);
      }
      return (void*) ((unsigned)PS + offset);
    }
  }
  
  PoolSlab *New = PoolSlab::create(Pool);
  //  printf("new slab created %x \n", New);
  if (Pool->NumSlabs > AddrArrSize)
    Pool->Slabs->insert((void *)New);
  else if (Pool->NumSlabs == AddrArrSize) {
    // Create the hash_set
    Pool->Slabs = new hash_set<void *>;
    Pool->Slabs->insert((void *)New);
    for (unsigned i = 0; i < AddrArrSize; ++i)
      Pool->Slabs->insert((void *)Pool->SlabAddressArray[i]);
  }
  else {
    // Insert it in the array
    Pool->SlabAddressArray[Pool->NumSlabs] = (unsigned) New;
  }
  
  Pool->NumSlabs++;
  
  int Idx = New->allocateMultiple(Size);
  assert(Idx == 0 && "New allocation didn't return zero'th node?");
  
  // insert info into adl splay tree for poolcheck runtime
  //unsigned NodeSize = Pool->NodeSize;
  globalTemp = New->getElementAddress(0, 0);
  //adl_splay_insert(&(Pool->Objects), globalTemp, 
  //          (unsigned)((Size*NodeSize) - NodeSize + 1), (Pool));
  
  // remap page to get a shadow page (dangling pointer detection library)
  New = (PoolSlab *) RemapObject(globalTemp, Size*Pool->NodeSize);
  offset = (unsigned)globalTemp & (PPageSize - 1);
  if (logregs) {
    fprintf(stderr, " poolallocarray:774: globalTemp = 0x%x\n, offset = 0x%x\n", (unsigned)globalTemp, offset);
    fprintf(stderr, " poolallocarray:775: New = 0x%08x, Size = %d, retAddress = 0x%08x\n",
        (unsigned)New, Size, (unsigned)New + offset);
  }
  return (void*) ((unsigned)New + offset);
}

void
poolregister(PoolTy *Pool, void * allocaptr, unsigned NumBytes) {
  // If the pool is NULL, don't do anything.
  if (!Pool) return;

#if 0
  if (Pool->AllocadPool != -1) {
    if (Pool->AllocadPool == 0) {
      printf(" Handle this case later\n");
      exit(-1);
    } else {
      printf(" An allocad pool, you can only allocate once \n");
      exit(-1);
    }
  } else {
    Pool->AllocadPool = NumBytes;
    Pool->allocaptr = allocaptr;
  }
#else
#if 0
  Pool->RegNodes->insert (std::make_pair(allocaptr,NumBytes));
#endif
  adl_splay_insert(&(Pool->Objects), allocaptr, NumBytes, 0);
  if (logregs) {
    fprintf (stderr, "poolregister: %x %d\n", (unsigned)allocaptr, NumBytes);
  }
#endif
}

void
poolunregister(PoolTy *Pool, void * allocaptr) {
  if (!Pool) return;
  adl_splay_delete(&Pool->Objects, allocaptr);
  if (logregs) {
    fprintf (stderr, "pooluregister: %x\n", allocaptr);
  }
}

extern "C" void frag(PoolTy * Pool);
void
frag(PoolTy * Pool) {
  unsigned long totalalloc=0;
  unsigned long total=0;
  for (PoolSlab *PS = (PoolSlab*)Pool->Ptr1; PS; PS = PS->Next) {
    total += PS->getSlabSize();
    totalalloc += PS->allocated;
    fprintf (stderr, "%2f\n", (double) PS->allocated * 100 / (double) PS->getSlabSize());
  }
  fprintf (stderr, "%d %d %2f\n", totalalloc, total, (double) totalalloc * 100 / (double) total);
  fflush (stderr);
}

//Pool->AllocadPool -1 : unused so far
//Pool->AllocadPool 0 : used only for mallocs
//Pool->AllocadPool >0 : used for only allocas indicating the size 
void *
poolalloc(PoolTy *Pool, unsigned NumBytes) {
  void *retAddress = NULL;
  assert(Pool && "Null pool pointer passed into poolalloc!\n");

#if 0
  // Ensure that stack objects and heap objects d not belong to the same pool.
  if (Pool->AllocadPool != -1) {
    if (Pool->AllocadPool != 0) {
    printf(" Did not Handle this case, an alloa and malloc point to");
    printf("same DSNode, Will happen in stack safety \n");
    exit(-1);
    }
  }
  else {
    Pool->AllocadPool = 0;
  }
#endif
   
  // Ensure that we're always allocating at least 1 byte.
  if (NumBytes == 0)
    NumBytes = 1;

  unsigned NodeSize = Pool->NodeSize;
  unsigned NodesToAllocate = (NumBytes + NodeSize - 1)/NodeSize;
  unsigned offset = 0;
  PDebugMetaData debugmetadataPtr;
  
  // Call a helper function if we need to allocate more than 1 node.
  if (NodesToAllocate > 1) {
    if (logregs) {
      fprintf(stderr, " poolalloc:848: Allocating more than 1 node for %d bytes\n", NumBytes); fflush(stderr);
    }
    retAddress = poolallocarray(Pool, NodesToAllocate);

    //
    // Record information about this allocation in the global debugging
    // structure.
    globalallocID++;
    debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID, __builtin_return_address(0), 0, globalTemp);
    adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, (void *) debugmetadataPtr);
    if (logregs) {
      fprintf(stderr, " poolalloc:856: after inserting to dummyPool\n");
      fflush (stderr);
    }

    // Register the object in the splay tree.  Keep track of its debugging data
    // with the splay node tag so that we can quickly map shadow address back
    // to the canonical address.
    //
    // globalTemp is the canonical page address
    adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr);
    
    //if ((unsigned)retAddress > 0x2f000000 && logregs == 0)
    //  logregs = 1;
    
    if (logregs) {
      fprintf(stderr, " poolalloc:863: retAddress = 0x%08x NumBytes = %d globalTemp = 0x%08x\n",
          (unsigned)retAddress, NumBytes, (unsigned)globalTemp); fflush(stderr);
    }
    assert (retAddress && "poolalloc(1): Returning NULL!\n");
    return retAddress;
  }
  // Special case the most common situation, where a single node is being
  // allocated.
  PoolSlab *PS = (PoolSlab*)Pool->Ptr1;

  if (__builtin_expect(PS != 0, 1)) {
    int Element = PS->allocateSingle();
    if (__builtin_expect(Element != -1, 1)) {
      // We allocated an element.  Check to see if this slab has been
      // completely filled up.  If so, move it to the Ptr2 list.
      if (__builtin_expect(PS->isFull(), false)) {
        PS->unlinkFromList();
        PS->addToList((PoolSlab**)&Pool->Ptr2);
      }
      
      globalTemp = PS->getElementAddress(Element, NodeSize);
      offset = (unsigned)globalTemp & (PPageSize - 1);
      if (logregs) {
        fprintf(stderr, " poolalloc:885: canonical page = 0x%08x offset = 0x%08x\n", (unsigned)globalTemp, offset);
      }
      //adl_splay_insert(&(Pool->Objects), globalTemp, NumBytes, (Pool));
      
      // remap page to get a shadow page for dangling pointer library
      PS = (PoolSlab *) RemapObject(globalTemp, NumBytes);
      retAddress = (void*) ((unsigned)PS + offset);
      // for the use of dangling pointer runtime
      globalallocID++;
      debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID,
                          __builtin_return_address(0), 0, globalTemp);
      adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, debugmetadataPtr);
      
      adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr);
      if (logregs) {
        fprintf(stderr, " poolalloc:900: retAddress = 0x%08x, NumBytes = %d\n", (unsigned)retAddress, NumBytes);
      }
      assert (retAddress && "poolalloc(2): Returning NULL!\n");
      return retAddress;
    }

    // Loop through all of the slabs looking for one with an opening
    for (PS = PS->Next; PS; PS = PS->Next) {
      int Element = PS->allocateSingle();
      if (Element != -1) {
        // We allocated an element.  Check to see if this slab has been
        // completely filled up.  If so, move it to the Ptr2 list.
        if (PS->isFull()) {
          PS->unlinkFromList();
          PS->addToList((PoolSlab**)&Pool->Ptr2);
        }
        
        globalTemp = PS->getElementAddress(Element, NodeSize);
        offset = (unsigned)globalTemp & (PPageSize - 1);
        //adl_splay_insert(&(Pool->Objects), globalTemp, NumBytes, (Pool));
      
        // remap page to get a shadow page for dangling pointer library
        PS = (PoolSlab *) RemapObject(globalTemp, NumBytes);
        retAddress = (void*) ((unsigned)PS + offset);
        //printf(" returning the address %x",retAddress);
        // for the use of dangling pointer runtime
        globalallocID++;
        debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID,
                            __builtin_return_address(0), 0, globalTemp);
        adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, debugmetadataPtr);
        
        adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr);
        if (logregs) {
          fprintf (stderr, " poolalloc:932: PS = 0x%08x, retAddress = 0x%08x, NumBytes = %d, offset = 0x%08x\n",
                (unsigned)PS, (unsigned)retAddress, NumBytes, offset);
        }
        assert (retAddress && "poolalloc(3): Returning NULL!\n");
        return retAddress;
      }
    }
  }

  // Otherwise we must allocate a new slab and add it to the list
  PoolSlab *New = PoolSlab::create(Pool);
  //
  // Ensure that we're always allocating at least 1 byte.
  //
  if (NumBytes == 0)
    NumBytes = 1;
  
  if (Pool->NumSlabs > AddrArrSize)
    Pool->Slabs->insert((void *)New);
  else if (Pool->NumSlabs == AddrArrSize) {
    // Create the hash_set
    Pool->Slabs = new hash_set<void *>;
    Pool->Slabs->insert((void *)New);
    for (unsigned i = 0; i < AddrArrSize; ++i)
      Pool->Slabs->insert((void *)Pool->SlabAddressArray[i]);
  }
  else {
    // Insert it in the array
    Pool->SlabAddressArray[Pool->NumSlabs] = (unsigned) New;
  }
  Pool->NumSlabs++;


  int Idx = New->allocateSingle();
  assert(Idx == 0 && "New allocation didn't return zero'th node?");
  if (logregs) {
    fprintf(stderr, " poolalloc:967: canonical page at 0x%08x from underlying allocator\n", (unsigned)New);
  }
  globalTemp = New->getElementAddress(0, 0);
  offset = (unsigned)globalTemp & (PPageSize - 1);
  
  if (logregs) {
    fprintf(stderr, " poolalloc:973: element at 0x%08x, offset=0x%08x\n", (unsigned)globalTemp, offset);
  }
  //adl_splay_insert(&(Pool->Objects), globalTemp, NumBytes, (Pool));
  
  // remap  page to get a shadow page for dangling pointer library
  New = (PoolSlab *) RemapObject(globalTemp, NumBytes);
  offset = (unsigned)globalTemp & (PPageSize - 1);
  //printf(" shadow page at 0x%x through remapping\n", (unsigned)New);
  retAddress = (void*) ((unsigned)New + offset);
  //printf(" returning the address 0x%x\n", (unsigned)retAddress);
  // for the use of dangling pointer runtime
  globalallocID++;
  debugmetadataPtr = createPtrMetaData(globalallocID, globalfreeID, __builtin_return_address(0), 0, globalTemp);
  adl_splay_insert(&(dummyPool.DPTree), retAddress, NumBytes, (void *) debugmetadataPtr);
  
  adl_splay_insert(&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr);
  if (logregs) {
    fprintf (stderr, " poolalloc:990: New = 0x%08x, retAddress = 0x%08x, NumBytes = %d, offset = 0x%08x\n",
          (unsigned)New, (unsigned)retAddress, NumBytes, offset);
  }
  assert (retAddress && "poolalloc(4): Returning NULL!\n");
  return retAddress;
}

void *
poolrealloc(PoolTy *Pool, void *Node, unsigned NumBytes) {
  if (Node == 0) return poolalloc(Pool, NumBytes);
  if (NumBytes == 0) {
    poolfree(Pool, Node);
    return 0;
  }

  void *New = poolalloc(Pool, NumBytes);
  //    unsigned Size =
  //FIXME the following may not work in all cases  
  memcpy(New, Node, NumBytes);
  poolfree(Pool, Node);
  return New;
}

void *
poolcalloc (PoolTy *Pool, unsigned Number, unsigned NumBytes) {
  void * New = poolalloc (Pool, Number * NumBytes);
  if (New) bzero (New, Number * NumBytes);
  return New;
}

void *
poolstrdup(PoolTy *Pool, char *Node) {
  if (Node == 0) return 0;

  unsigned int NumBytes = strlen(Node) + 1;
  void *New = poolalloc(Pool, NumBytes);
  if (New) {
    memcpy(New, Node, NumBytes+1);
  }
  return New;
}

//
// Function: pool_newstack()
//
// Description:
//  Create a new pool slab for the given function invocation.
//
void
pool_newstack (PoolTy * Pool) {
  // Pointer to the new pool slab
  StackSlab * PS;

  //
  // Get a new stack slab.  Either reuse an old one or create a new one.
  //
  assert ((sizeof (StackSlab) <= 4096) && "StackSlab too big!\n");
  if (Pool->FreeStackSlabs) {
    PS = (StackSlab *)(Pool->FreeStackSlabs);
    PS->unlinkFromList();
  } else {
    PS = (StackSlab*) valloc (sizeof (StackSlab));
  }

  //
  // Ensure we have a pool slab.
  //
  assert (PS && "pool_newstack: Can't create new slab\n");

  //
  // Remap the stack slab into a new virtual address space.
  //
  PS->Canonical = PS;
  PS = (StackSlab *) RemapObject (PS, sizeof (StackSlab));

  //
  // Initialize it.
  //
  PS = StackSlab::create (PS);

  //
  // Link the shadow slab into the set of stack slabs.
  //
  PS->addToList((StackSlab**)&Pool->StackSlabs);
#if 1
fprintf (stderr, "\nnewstack: %x %x\n", PS, PS->Canonical);
fflush (stderr);
#endif
  return;
}

void *
pool_alloca (PoolTy * Pool, unsigned int NumBytes) {
  // The address of the allocated object
  void * retAddress;

  // Ensure that we're always allocating at least 1 byte.
  if (NumBytes == 0)
    NumBytes = 1;

  // Allocate memory from the function's single slab.
  assert (Pool->StackSlabs && "pool_alloca: No call to newstack!\n");
  globalTemp = ((StackSlab *)(Pool->StackSlabs))->allocate (NumBytes);
fprintf (stderr, "alloca: %x %x\n", globalTemp, NumBytes);
fflush (stderr);

  //
  // Allocate and remap the object.
  //
  retAddress = globalTemp;

  //
  // Record information about this allocation in the global debugging
  // structure.
  // FIXME: Need to ensure MetaData is correct for debugging
  //
  globalallocID++;
  PDebugMetaData debugmetadataPtr;
  debugmetadataPtr = createPtrMetaData (globalallocID,
                                        globalfreeID,
                                        __builtin_return_address(0),
                                        0,
                                        globalTemp);

  adl_splay_insert (&(dummyPool.DPTree),
                    retAddress,
                    NumBytes,
                    (void *) debugmetadataPtr);

  // Register the object in the splay tree.  Keep track of its debugging data
  // with the splay node tag so that we can quickly map shadow address back
  // to the canonical address.
  //
  // globalTemp is the canonical page address
  adl_splay_insert (&(Pool->Objects), retAddress, NumBytes, debugmetadataPtr);
    
  assert (retAddress && "pool_alloca(1): Returning NULL!\n");
  return retAddress;
}

void
pool_delstack (PoolTy * Pool) {
  StackSlab * PS = (StackSlab *)(Pool->StackSlabs);

  //
  // Get the canonical page corresponding to this slab.
  //
#if 1
fprintf (stderr, "delstack: %x\n", PS);
fflush (stderr);
#endif

  //
  // Remove the slab from the list.
  //
  PS->unlinkFromList();

  //
  // Deallocate all elements and add the slab into the set of free slabs.
  //
  PS->Canonical->addToList((StackSlab**)&Pool->FreeStackSlabs);

#if 1
  //
  // Make the stack page inaccessible.
  //
  ProtectShadowPage (PS, 1);
#endif

  return;
}

// SearchForContainingSlab - Do a brute force search through the list of
// allocated slabs for the node in question.
//
static PoolSlab *
SearchForContainingSlab(PoolTy *Pool, void *Node, unsigned &TheIndex) {
  PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
  unsigned NodeSize = Pool->NodeSize;

  // Search the partially allocated slab list for the slab that contains this
  // node.
  int Idx = -1;
  if (PS) {               // Pool->Ptr1 could be null if Ptr2 isn't
    for (; PS; PS = PS->Next) {
      Idx = PS->containsElement(Node, NodeSize);
      if (Idx != -1) break;
    }
  }

  // If the partially allocated slab list doesn't contain it, maybe the
  // completely allocated list does.
  if (PS == 0) {
    PS = (PoolSlab*)Pool->Ptr2;
    assert(Idx == -1 && "Found node but don't have PS?");
    
    while (PS) {
      assert(PS && "poolfree: node being free'd not found in allocation "
             " pool specified!\n");
      Idx = PS->containsElement(Node, NodeSize);
      if (Idx != -1) break;
      PS = PS->Next;
    }
  }
  
  // Otherwise, maybe its a block within LargeArrays
  if(PS == 0) {
    PS = (PoolSlab*)Pool->LargeArrays;
    assert(Idx == -1  && "Found node but don't have PS?");
    
    while (PS) {
      assert(PS && "poolfree: node being free'd not found in allocation "
             " pool specified!\n");
      Idx = PS->containsElement(Node, NodeSize);
      if (Idx != -1) break;
      PS = PS->Next;
    }
  }

  TheIndex = Idx;
  return PS;
}

void
poolcheck(PoolTy *Pool, void *Node) {
  void* S = Node;
  unsigned len = 0;
  if (!Pool) return;
  int fs = adl_splay_retrieve(&(Pool->Objects), &S, &len, 0);
  if ((fs) && (S <= Node) && (((char*)S + len) > (char*)Node)) {
    return;
  }

  /*
   * The node is not found or is not within bounds; fail!
   */
  fprintf (stderr, "Poolcheck failed(%x:%x): %x %x from %x\n", 
      (unsigned)Pool, fs, (unsigned)Node, len, (unsigned)__builtin_return_address(0));
  fflush (stderr);
  abort ();
  return;
}

void
poolcheckui (PoolTy *Pool, void *Node) {
  void* S = Node;
  unsigned len = 0;
  if (!Pool) return;

  /*
   * Look for the object within the pool's splay tree.
   */
  int fs = adl_splay_retrieve(&(Pool->Objects), &S, &len, 0);
  if ((fs) && (S <= Node) && (((char*)S + len) > (char*)Node)) {
    return;
  }

  /*
   * Look for the object within the splay tree of external objects.
   */
  S = Node;
  len = 0;
  fs = adl_splay_retrieve (&(ExternalObjects), &S, &len, 0);
  if ((fs) && (S <= Node) && (((char*)S + len) > (char*)Node)) {
    return;
  }

  /*
   * The node is not found or is not within bounds.  Report a warning but keep
   * going.
   */
  fprintf (stderr, "PoolcheckUI failed(%x:%x): %x %x from %x\n", 
      (unsigned)Pool, fs, (unsigned)Node, len, (unsigned)__builtin_return_address(0));
  fflush (stderr);
  return;
}

/*
 * Function: boundscheck()
 *
 * Description:
 *  Perform a precise bounds check.  Ensure that Source is within a valid
 *  object within the pool and that Dest is within the bounds of the same
 *  object.
 */
static unsigned char * invalidptr = 0;

void *
boundscheck (PoolTy * Pool, void * Source, void * Dest) {
  void* S = Source;
  unsigned len = 0;
  int fs = adl_splay_retrieve(&(Pool->Objects), &S, &len, 0);
  if ((fs) && (S <= Dest) && (((char*)S + len) > (char*)Dest)) {
    return Dest;
  }

  /*
   * Handle the case where a pointer is allowed to move just beyond the end of
   * the allocated space.
   */
  if ((fs) && (((char *) Dest) == ((char*)S + len))) {
    if (logregs)
      fprintf (stderr, "boundscheck  : rewrite: %x %x %x %x, pc=%x\n",
               S, Source, Dest, len, (void*)__builtin_return_address(0));
    if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower;
    ++invalidptr;
    void* P = invalidptr;
    if ((unsigned)P & ~(InvalidUpper - 1)) {
      fprintf (stderr, "boundscheck: out of rewrite ptrs: %x %x: %x %x, pc=%x\n",
               Source, Dest, InvalidLower, invalidptr, (void*)__builtin_return_address(0));
      fflush (stderr);
      return Dest;
    }

    adl_splay_insert (&(Pool->OOB), P, 1, Dest);
    return invalidptr;
  }

  /*
   * Allow pointers to the first page in memory provided that they remain
   * within that page.  Loads and stores using such pointers will fault.  This
   * allows indexing of NULL pointers without error.
   */
  if (Source < (unsigned char *)(4096)) {
    if (Dest < (unsigned char *)(4096)) {
      return Dest;
    } else {
      if (logregs)
        fprintf (stderr, "boundscheck  : rewrite: %x %x %x %x, pc=%x\n",
                 S, Source, Dest, len, (void*)__builtin_return_address(0));
      if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower;
      ++invalidptr;
      void* P = invalidptr;
      if ((unsigned)P & ~(InvalidUpper - 1)) {
        fprintf (stderr, "boundscheck: out of rewrite ptrs: %x %x: %x %x, pc=%x\n",
                 Source, Dest, InvalidLower, invalidptr, (void*)__builtin_return_address(0));
        fflush (stderr);
        return Dest;
      }

      adl_splay_insert (&(Pool->OOB), P, 1, Dest);
      return invalidptr;
    }
  }

  /*
   * The node is not found or is not within bounds; fail!
   */
  if (fs) {
    ReportBoundsCheck ((unsigned)Source,
                       (unsigned)Dest,
                       (unsigned)__builtin_return_address(0),
                       (unsigned)S,
                       (unsigned)len);
  } else {
    ReportBoundsCheck ((unsigned)Source,
                       (unsigned)Dest,
                       (unsigned)__builtin_return_address(0),
                       (unsigned)0,
                       (unsigned)0);
  }
  fflush (stderr);
  abort ();
  return Dest;
}

int
boundscheckui_lookup (PoolTy * Pool, void * Source ) {
  //search for object for Source in splay tree, return length 
  return adl_splay_lookup (&(Pool->Objects), &Source);
}

void *
boundscheckui_check (int len, PoolTy * Pool, void * Source, void * Dest) {
  /*
   * First, attempt to find the pointer within a valid object.  If the source
   * pointer is within a valid object but the destination pointer is not, then
   * rewrite the pointer.
   */
  void* S = Source;
  //unsigned len = 0;

  if (len) {
    if ((S <= Dest) && (((char*)S + len) > (char*)Dest)) {
      return Dest;
    } else {
      if (logregs)
        fprintf (stderr, "boundscheckui: rewrite: %x %x %x %x, pc=%x\n",
                 S, Source, Dest, len, (void*)__builtin_return_address(0));
      if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower;
      ++invalidptr;
      void* P = invalidptr;
      //if ((unsigned)P & ~(InvalidUpper - 1)) {
      if ((unsigned) P == InvalidUpper) {
        fprintf (stderr, "boundscheckui: out of rewrite ptrs: %x %x, pc=%x\n",
                 InvalidLower, InvalidUpper, invalidptr);
                 //Source, Dest, (void*)__builtin_return_address(0));
        fflush (stderr);
        abort();
      }
      adl_splay_insert (&(Pool->OOB), P, 1, Dest);
      return invalidptr;
    }
  }


  /*
   * Allow pointers to the first page in memory provided that they remain
   * within that page.  Loads and stores using such pointers will fault.  This
   * allows indexing of NULL pointers without error.
   */
  if (Source < (unsigned char *)(4096)) {
    if (Dest < (unsigned char *)(4096)) {
      return Dest;
    } else {
      if (logregs)
        fprintf (stderr, "boundscheckui: rewrite: %x %x %x %x, pc=%x\n",
                 S, Source, Dest, len, (void*)__builtin_return_address(0));
      if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower;
      ++invalidptr;
      void* P = invalidptr;
      //if ((unsigned)P & ~(InvalidUpper - 1)) {
      if ((unsigned) P == InvalidUpper) {
        fprintf (stderr, "boundscheckui: out of rewrite ptrs: %x %x, pc=%x\n",
                 InvalidLower, InvalidUpper, invalidptr);
                 //Source, Dest, (void*)__builtin_return_address(0));
        fflush (stderr);
        abort();
      }
      adl_splay_insert (&(Pool->OOB), P, 1, Dest);
      return invalidptr;
    }
  }

  /*
   * Attempt to look for the object in the external object splay tree.
   */
  S = Source;
  unsigned len_new = 0;
  int fs = adl_splay_retrieve (&(ExternalObjects), &S, &len_new, 0);
  if (fs) {
    if ((S <= Dest) && (((char*)S + len_new) > (char*)Dest)) {
      return Dest;
    } else {
      ReportBoundsCheck ((unsigned)Source,
                         (unsigned)Dest,
                         (unsigned)__builtin_return_address(0),
                         (unsigned)S,
                         (unsigned)len);
    }
  }

  /*
   * We cannot find the object.  Print a warning and continue execution.
   */
  
 return Dest;
}

void *
boundscheckui (PoolTy * Pool, void * Source, void * Dest) {
  // This code is inlined at all boundscheckui calls

  // Search the splay for Source and return the bounds of the object
  int len = boundscheckui_lookup (Pool, Source); 
  
  // Check if destination lies in the same object
  if (__builtin_expect (len &&
                        ((Source <= Dest) &&
                        ((char*)Source + len) > (char*)Dest), 1)) {
    return Dest;
  } else {
    //
    // Valid object not found in splay tree or Dest is not within the valid
    // object
    //
    return boundscheckui_check( len, Pool, Source, Dest );  
  }
}

void *
rewrite_ptr (void * p) {
  static void * OOBTree;

  if (invalidptr == 0) invalidptr = (unsigned char*)InvalidLower;
  ++invalidptr;
  void* P = invalidptr;
  //if ((unsigned)P & ~(InvalidUpper - 1)) {
  if ((unsigned) P == InvalidUpper) {
    fprintf (stderr, "rewrite: out of rewrite ptrs: %x %x, pc=%x\n",
             InvalidLower, InvalidUpper, invalidptr);
             //Source, Dest, (void*)__builtin_return_address(0));
    fflush (stderr);
    abort();
  }

  adl_splay_insert (&(OOBTree), P, 1, p);
  return invalidptr;
}

/*
 * Function: getActualValue()
 *
 * Description:
 *  If src is an out of object pointer, get the original value.
 */
void *
pchk_getActualValue (PoolTy * Pool, void * src) {
  if ((unsigned)src <= InvalidLower) return src;

  void* tag = 0;

  /* outside rewrite zone */
  if ((unsigned)src & ~(InvalidUpper - 1)) return src;
  if (adl_splay_retrieve(&(Pool->OOB), &src, 0, &tag)) {
    return tag;
  }

  /* Lookup has failed */
  fprintf (stderr, "GetActualValue failure: src = %x, pc = %x", (unsigned) src,
           (unsigned) __builtin_return_address(0));
  fflush (stderr);
  abort ();
  return tag;
}

// Check that Node falls within the pool and within start and (including)
// end offset
void
poolcheckalign (PoolTy *Pool, void *Node, unsigned StartOffset, 
                unsigned EndOffset) {
  PoolSlab *PS;
  if (StartOffset >= Pool->NodeSize || EndOffset >= Pool->NodeSize) {
    printf("Error: Offset specified exceeded node size");
    exit(-1);
  }

  if (Pool->AllocadPool > 0) {
    if (Pool->allocaptr <= Node) {
     unsigned diffPtr = (unsigned)Node - (unsigned)Pool->allocaptr;
     unsigned offset = diffPtr % Pool->NodeSize;
     if ((diffPtr  < (unsigned)Pool->AllocadPool ) && (offset >= StartOffset) &&
         (offset <= EndOffset))
       return;
    }
    assert(0 && "poolcheckalign failure FAILING \n");
    exit(-1);    
  }
  
  PS = (PoolSlab*)((long)Node & ~(PageSize-1));

  if (Pool->NumSlabs > AddrArrSize) {
    hash_set<void*> &theSlabs = *Pool->Slabs;
    if (theSlabs.find((void*)PS) == theSlabs.end()) {
      // Check the LargeArrays
      if (Pool->LargeArrays) {
        PoolSlab *PSlab = (PoolSlab*) Pool->LargeArrays;
        int Idx = -1;
        while (PSlab) {
          assert(PSlab && "poolcheck: node being free'd not found in "
                          "allocation pool specified!\n");
          Idx = PSlab->containsElement(Node, Pool->NodeSize);
          if (Idx != -1) {
            Pool->prevPage[Pool->lastUsed] = PS;
            Pool->lastUsed = (Pool->lastUsed + 1) % 4;
            break;
          }
          PSlab = PSlab->Next;
        }

        if (Idx == -1) {
          fprintf(stderr, "poolcheck1: node being checked not found in pool with right"
           " alignment\n");
          fflush(stderr);
      abort();
          exit(-1);
        } else {
          //exit(-1);
        }
      } else {
        fprintf(stderr, "poolcheck2: node being checked not found in pool with right"
               " alignment\n");
        fflush(stderr);
    abort();
        exit(-1);
      }
    } else {
      unsigned long startaddr = (unsigned long)PS->getElementAddress(0,0);
      if (startaddr > (unsigned long) Node) {
        fprintf(stderr, "poolcheck: node being checked points to meta-data \n");
        fflush(stderr);
    abort();
        exit(-1);
      }
      unsigned long offset = ((unsigned long) Node - (unsigned long) startaddr) % Pool->NodeSize;
      if ((offset < StartOffset) || (offset > EndOffset)) {
        fprintf(stderr, "poolcheck3: node being checked does not have right alignment\n");
        fflush(stderr);
    abort();
        exit(-1);
      }
      Pool->prevPage[Pool->lastUsed] = PS;
      Pool->lastUsed = (Pool->lastUsed + 1) % 4;
    }
  } else {
    bool found = false;
    for (unsigned i = 0; i < AddrArrSize && !found; ++i) {
      if ((unsigned)Pool->SlabAddressArray[i] == (unsigned) PS) {
        found = true;
        Pool->prevPage[Pool->lastUsed] = PS;
        Pool->lastUsed = (Pool->lastUsed + 1) % 4;
      }
    } 

    if (found) {
      // Check that Node does not point to PoolSlab meta-data
      unsigned long startaddr = (unsigned long)PS->getElementAddress(0,0);
      if (startaddr > (unsigned long) Node) {
        printf("poolcheck: node being checked points to meta-data \n");
        exit(-1);
      }
      unsigned long offset = ((unsigned long) Node - (unsigned long) startaddr) % Pool->NodeSize;
      if ((offset < StartOffset) || (offset > EndOffset)) {
        fprintf(stderr, "poolcheck4: node being checked does not have right alignment\n");
        fflush(stderr);
    abort();
        exit(-1);
      }
    } else {
      // Check the LargeArrays
      if (Pool->LargeArrays) {
        PoolSlab *PSlab = (PoolSlab*) Pool->LargeArrays;
        int Idx = -1;
        while (PSlab) {
          assert(PSlab && "poolcheck: node being free'd not found in "
           "allocation pool specified!\n");
          Idx = PSlab->containsElement(Node, Pool->NodeSize);
          if (Idx != -1) {
            Pool->prevPage[Pool->lastUsed] = PS;
            Pool->lastUsed = (Pool->lastUsed + 1) % 4;
            break;
          }
          PSlab = PSlab->Next;
        }
        if (Idx == -1) {
          fprintf(stderr, "poolcheck6: node being checked not found in pool with right"
           " alignment\n");
          fflush(stderr);
      abort();
          exit(-1);
        }
      } else {
        fprintf(stderr, "poolcheck5: node being checked not found in pool with right"
               " alignment %x %x\n", (unsigned)Pool, (unsigned)Node);
        fflush(stderr);
    abort();
      }
    }
  }
}



void
poolfree(PoolTy *Pool, void *Node) {
  assert(Pool && "Null pool pointer passed in to poolfree!\n");
  DEBUG(printf("poolfree  %x %x \n",Pool,Node);)
  PoolSlab *PS;
  int Idx;
  
  
  if (logregs) {
    printf(" poolfree:1368: poolfree to addr 0x%08x\n", (unsigned)Node);
  }
  // update DebugMetaData
  globalfreeID++;

  // FIXME: figure what mykey, NumPPAge and len are for
  void * mykey;
  unsigned len = 1;
  unsigned NumPPage = 0;
  unsigned offset = (unsigned)((long)Node & (PPageSize - 1));
  PDebugMetaData debugmetadataptr;
  mykey = Node;
  
  // Retrieve the debug information about the node.  This will include a
  // pointer to the canonical page.
  adl_splay_retrieve (&(Pool->Objects), &mykey, &len, (void **) &debugmetadataptr);
  
  if (logregs) {
    printf(" poolfree:1387: mykey = 0x%08x offset = 0x%08x\n", (unsigned)mykey, offset);
    printf(" poolfree:1388: len = %d\n", len);
  }

  // figure out how many pages does this object span to
  //  protect the pages. First we sum the offset and len
  //  to get the total size we originally remapped.
  //  Then, we determine if this sum is a multiple of
  //  physical page size. If it is not, then we increment
  //  the number of pages to protect.
  //  FIXME!!!

  NumPPage = (len / PPageSize) + 1;
  if ( (len - (NumPPage-1) * PPageSize) > (PPageSize - offset) )
    NumPPage++;
  
  assert (debugmetadataptr && "poolfree: No debugmetadataptr\n");
  globalTemp = debugmetadataptr->canonAddr;
  
  if (logregs) {
    printf(" poolfree:1397: NumPPage = %d\n", NumPPage);
    printf(" poolfree:1398: canonical address is 0x%x\n", (unsigned)globalTemp);
  }
  updatePtrMetaData(debugmetadataptr, globalfreeID, __builtin_return_address(0));

  //
  // Allow the poolcheck runtime to finish the bookkeping it needs to do.
  //
  adl_splay_delete (&Pool->Objects, Node);
  
  if (1) {                  // THIS SHOULD BE SET FOR SAFECODE!
    unsigned TheIndex;
    PS = SearchForContainingSlab(Pool, globalTemp, TheIndex);
    Idx = TheIndex;
    assert (PS && "poolfree: No poolslab found for object!\n");
    PS->freeElement(Idx);
  } else {
    // Since it is undefined behavior to free a node which has not been
    // allocated, we know that the pointer coming in has to be a valid node
    // pointer in the pool.  Mask off some bits of the address to find the base
    // of the pool.
    assert((PageSize & PageSize-1) == 0 && "Page size is not a power of 2??");
    PS = (PoolSlab*)((long)Node & ~(PageSize-1));

    if (PS->isSingleArray) {
      PS->unlinkFromList();
      
      // works done to update the DebugMetaData struct for
      //  dangling pointer runtime
      globalfreeID++;
      void * mykey;
      unsigned len = 0;
      PDebugMetaData debugmetadataptr;
      mykey = Node;
      adl_splay_retrieve(&(Pool->DPTree), &mykey, &len, (void **) &debugmetadataptr);
      updatePtrMetaData(debugmetadataptr, globalfreeID, __builtin_return_address(0));      
      return;
    }

    Idx = PS->containsElement(Node, Pool->NodeSize);
    assert((int)Idx != -1 && "Node not contained in slab??");
  }
  
  //  return if PS is NULL
  if (!PS)
    return;
  assert (PS && "PS is NULL!\n");
  
  // If PS was full, it must have been in list #2.  Unlink it and move it to
  // list #1.
  if (PS->isFull()) {
    // Now that we found the node, we are about to free an element from it.
    // This will make the slab no longer completely full, so we must move it to
    // the other list!
    PS->unlinkFromList(); // Remove it from the Ptr2 list.

    //
    // Do not re-use single array slabs.
    //
    if (!(PS->isSingleArray)) {
      PoolSlab **InsertPosPtr = (PoolSlab**)&Pool->Ptr1;

      // If the partially full list has an empty node sitting at the front of
      // the list, insert right after it.
      if ((*InsertPosPtr))
        if ((*InsertPosPtr)->isEmpty())
          InsertPosPtr = &(*InsertPosPtr)->Next;

      PS->addToList(InsertPosPtr);     // Insert it now in the Ptr1 list.
    }
  }

  // Ok, if this slab is empty, we unlink it from the of slabs and either move
  // it to the head of the list, or free it, depending on whether or not there
  // is already an empty slab at the head of the list.
  if ((PS->isEmpty()) && (!(PS->isSingleArray))) {
    PS->unlinkFromList();   // Unlink from the list of slabs...
    
    // If we can free this pool, check to see if there are any empty slabs at
    // the start of this list.  If so, delete the FirstSlab!
    PoolSlab *FirstSlab = (PoolSlab*)Pool->Ptr1;
    if (0 && FirstSlab && FirstSlab->isEmpty()) {
      // Here we choose to delete FirstSlab instead of the pool we just freed
      // from because the pool we just freed from is more likely to be in the
      // processor cache.
    FirstSlab->unlinkFromList();
    FirstSlab->destroy();
    //  Pool->Slabs.erase((void *)FirstSlab);
    }
 
    // Link our slab onto the head of the list so that allocations will find it
    // efficiently.    
    PS->addToList((PoolSlab**)&Pool->Ptr1);
  }
 
  // Protect the shadow pages
  ProtectShadowPage((void *)((long)Node & ~(PPageSize - 1)), NumPPage);
  
  //
  // An object has been freed.  Set up a signal handler to catch any dangling
  // pointer references.
  //
  // FIXME:
  //  This code was placed here because it does not appear to work when placed
  //  in poolinit().
  //
  struct sigaction sa;
  bzero (&sa, sizeof (struct sigaction));
  sa.sa_sigaction = bus_error_handler;
  sa.sa_flags = SA_SIGINFO;
  if (sigaction(SIGBUS, &sa, NULL) == -1) {
    fprintf (stderr, "sigaction installer failed!");
    fflush (stderr);
  }

  return; 
}

//===----------------------------------------------------------------------===//
//
// Dangling pointer runtime functions
//
//===----------------------------------------------------------------------===//

//
// Function: createPtrMetaData()
//  Allocates memory for a DebugMetaData struct and fills up the appropriate
//  fields so to keep a record of the pointer's meta data
//
extern "C" { void * internal_malloc (unsigned int size);}
static PDebugMetaData
createPtrMetaData (unsigned paramAllocID,
                   unsigned paramFreeID,
                   void * paramAllocPC,
                   void * paramFreePC,
                   void * paramCanon) {
  // FIXME:
  //  This only works because DebugMetaData and a splay tree node are of
  //  identical size.
  PDebugMetaData ret = (PDebugMetaData) internal_malloc(sizeof(DebugMetaData));
  ret->allocID = paramAllocID;
  ret->freeID = paramFreeID;
  ret->allocPC = paramAllocPC;
  ret->freePC = paramFreePC;
  ret->canonAddr = paramCanon;

  return ret;
}

static inline void
updatePtrMetaData (PDebugMetaData debugmetadataptr,
                   unsigned globalfreeID,
                   void * paramFreePC) {
  debugmetadataptr->freeID = globalfreeID;
  debugmetadataptr->freePC = paramFreePC;
  return;
}

//
// Function: bus_error_handler()
//
// Description:
//  This is the signal handler that catches bad memory references.
//
static void
bus_error_handler (int sig, siginfo_t * info, void * context) {
  signal(SIGBUS, NULL);
  ucontext_t * mycontext = (ucontext_t *) context;

  unsigned len = 0;
  void * faultAddr = info->si_addr;
  PDebugMetaData debugmetadataptr;
  int fs = 0;
  if (0 == (fs = adl_splay_retrieve(&(dummyPool.DPTree), &faultAddr, &len, (void **) &debugmetadataptr)))
  {
    fprintf(stderr, "signal handler: retrieving debug meta data failed");
    fflush(stderr);
    abort();
  }
 
  // FIXME: Correct the semantics for calculating NumPPage 
  unsigned NumPPage;
  unsigned offset = (unsigned) ((long)info->si_addr & (PPageSize - 1) );
  NumPPage = (len / PPageSize) + 1;
  if ( (len - (NumPPage-1) * PPageSize) > (PPageSize - offset) )
    NumPPage++;
 
  // This is necessary so that the program continues execution,
  //  especially in debugging mode 
  UnprotectShadowPage((void *)((long)info->si_addr & ~(PPageSize - 1)), NumPPage);
  
  //void* S = info->si_addr;
  // printing reports
  void * address = 0;
  unsigned program_counter = 0;
  unsigned alloc_pc = 0;
  unsigned free_pc = 0;
  unsigned allocID = 0;
  unsigned freeID = 0;

#if defined(__APPLE__)
#if defined(i386) || defined(__i386__) || defined(__x86__)
  program_counter = mycontext->uc_mcontext->__ss.__eip;
#endif
  alloc_pc = ((unsigned) (debugmetadataptr->allocPC)) - 5;
  free_pc  = ((unsigned) (debugmetadataptr->freePC)) - 5;
  allocID  = debugmetadataptr->allocID;
  freeID   = debugmetadataptr->freeID;
#endif
  
  ReportDanglingPointer (address, program_counter,
                         alloc_pc, allocID,
                         free_pc, freeID);

  // reinstall the signal handler for subsequent faults
  struct sigaction sa;
  sa.sa_sigaction = bus_error_handler;
  sa.sa_flags = SA_SIGINFO;
  if (sigaction(SIGBUS, &sa, NULL) == -1)
    printf("sigaction installer failed!");
  
  return;
}

 

//
// Function: funccheck()
//
// Description:
//  Determine whether the specified function pointer is one of the functions
//  in the given list.
//
// Inputs:
//  num - The number of function targets in the DSNode.
//  f   - The function pointer that we are testing.
//  g   - The first function given in the DSNode.
//
void
funccheck (unsigned num, void *f, void *g, ...) {
  va_list ap;
  unsigned i = 0;

  // Test against the first function in the list
  if (f == g) return;
  i++;
  va_start(ap, g);
  for ( ; i != num; ++i) {
    void *h = va_arg(ap, void *);
    if (f == h) {
      return;
    }
  }
  if (logregs) {
  fprintf(stderr, "funccheck failed(num=%d): %x %x\n", num, f, g);
  fflush(stderr);
  }
  abort();
}

void
poolstats() {
  fprintf (stderr, "pool mem usage %d\n", poolmemusage);
  fflush (stderr);
}
