Browse Source

New alignment code to hopefully fix the alignment issues

rdb 8 years ago
parent
commit
2acde88695

+ 4 - 4
dtool/src/dtoolbase/deletedBufferChain.cxx

@@ -39,7 +39,7 @@ allocate(size_t size, TypeHandle type_handle) {
   assert(size <= _buffer_size);
 
   // Determine how much space to allocate.
-  const size_t alloc_size = _buffer_size + flag_reserved_bytes + MemoryHook::get_memory_alignment() - 1;
+  const size_t alloc_size = _buffer_size + flag_reserved_bytes + MEMORY_HOOK_ALIGNMENT - 1;
 
   ObjectNode *obj;
 
@@ -71,8 +71,8 @@ allocate(size_t size, TypeHandle type_handle) {
 
   // Allocate memory, and make sure the object starts at the proper alignment.
   void *mem = NeverFreeMemory::alloc(alloc_size);
-  intptr_t pad = (-(intptr_t)flag_reserved_bytes - (intptr_t)mem) % MemoryHook::get_memory_alignment();
-  obj = (ObjectNode *)((uintptr_t)mem + pad);
+  uintptr_t aligned = ((uintptr_t)mem + flag_reserved_bytes + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1);
+  obj = (ObjectNode *)(aligned - flag_reserved_bytes);
 
 #ifdef USE_DELETEDCHAINFLAG
   obj->_flag = DCF_alive;
@@ -81,7 +81,7 @@ allocate(size_t size, TypeHandle type_handle) {
   void *ptr = node_to_buffer(obj);
 
 #ifndef NDEBUG
-  assert(((uintptr_t)ptr % MemoryHook::get_memory_alignment()) == 0);
+  assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
 #endif
 
 #ifdef DO_MEMORY_USAGE

+ 60 - 85
dtool/src/dtoolbase/deletedChain.T

@@ -1,25 +1,22 @@
-// Filename: deletedChain.T
-// Created by:  drose (01Apr06)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file deletedChain.T
+ * @author drose
+ * @date 2006-04-01
+ */
 
 template<class Type>
 DeletedChain<Type> StaticDeletedChain<Type>::_chain;
 
-////////////////////////////////////////////////////////////////////
-//     Function: DeletedChain::allocate
-//       Access: Public
-//  Description: Allocates the memory for a new object of Type.
-////////////////////////////////////////////////////////////////////
+/**
+ * Allocates the memory for a new object of Type.
+ */
 template<class Type>
 INLINE Type *DeletedChain<Type>::
 allocate(size_t size, TypeHandle type_handle) {
@@ -31,14 +28,12 @@ allocate(size_t size, TypeHandle type_handle) {
   memory_hook->mark_pointer(ptr, _chain->get_buffer_size(), make_ref_ptr(ptr));
 #endif  // DO_MEMORY_USAGE
 
-  return (Type *)ptr;
+  return (Type *)ASSUME_ALIGNED(ptr, MEMORY_HOOK_ALIGNMENT);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DeletedChain::deallocate
-//       Access: Public
-//  Description: Frees the memory for an object of Type.
-////////////////////////////////////////////////////////////////////
+/**
+ * Frees the memory for an object of Type.
+ */
 template<class Type>
 INLINE void DeletedChain<Type>::
 deallocate(Type *ptr, TypeHandle type_handle) {
@@ -57,16 +52,13 @@ deallocate(Type *ptr, TypeHandle type_handle) {
   _chain->deallocate(ptr, type_handle);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DeletedChain::validate
-//       Access: Public
-//  Description: Returns true if the pointer is valid, false if it has
-//               been deleted or if it was never a valid pointer.
-//
-//               This is only meaningful in debug mode, where
-//               USE_DELETEDCHAINFLAG is defined.  If not, this
-//               trivially returns true.
-////////////////////////////////////////////////////////////////////
+/**
+ * Returns true if the pointer is valid, false if it has been deleted or if it
+ * was never a valid pointer.
+ *
+ * This is only meaningful in debug mode, where USE_DELETEDCHAINFLAG is
+ * defined.  If not, this trivially returns true.
+ */
 template<class Type>
 INLINE bool DeletedChain<Type>::
 validate(const Type *ptr) {
@@ -80,48 +72,37 @@ validate(const Type *ptr) {
 #endif  // USE_DELETEDCHAINFLAG
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DeletedChain::make_ref_ptr
-//       Access: Public, Static
-//  Description: This method has two overloads: one that accepts a
-//               void *, and one that accepts a ReferenceCount *.  We
-//               rely on the C++ compiler to select the most
-//               appropriate one for a given type to return the
-//               ReferenceCount pointer that corresponds to a
-//               particular type, or NULL if the type does not inherit
-//               from ReferenceCount.
-////////////////////////////////////////////////////////////////////
+/**
+ * This method has two overloads: one that accepts a void *, and one that
+ * accepts a ReferenceCount *.  We rely on the C++ compiler to select the most
+ * appropriate one for a given type to return the ReferenceCount pointer that
+ * corresponds to a particular type, or NULL if the type does not inherit from
+ * ReferenceCount.
+ */
 template<class Type>
 INLINE ReferenceCount *DeletedChain<Type>::
 make_ref_ptr(void *) {
   return NULL;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DeletedChain::make_ref_ptr
-//       Access: Public, Static
-//  Description: This method has two overloads: one that accepts a
-//               void *, and one that accepts a ReferenceCount *.  We
-//               rely on the C++ compiler to select the most
-//               appropriate one for a given type to return the
-//               ReferenceCount pointer that corresponds to a
-//               particular type, or NULL if the type does not inherit
-//               from ReferenceCount.
-////////////////////////////////////////////////////////////////////
+/**
+ * This method has two overloads: one that accepts a void *, and one that
+ * accepts a ReferenceCount *.  We rely on the C++ compiler to select the most
+ * appropriate one for a given type to return the ReferenceCount pointer that
+ * corresponds to a particular type, or NULL if the type does not inherit from
+ * ReferenceCount.
+ */
 template<class Type>
 INLINE ReferenceCount *DeletedChain<Type>::
 make_ref_ptr(ReferenceCount *ptr) {
   return ptr;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DeletedChain::init_deleted_chain
-//       Access: Private
-//  Description: Assigns the _chain pointer if it is not already
-//               assigned.  This can't be done by a constructor, since
-//               often the DeletedChain instance is used before its
-//               static construct has had a chance to be called.
-////////////////////////////////////////////////////////////////////
+/**
+ * Assigns the _chain pointer if it is not already assigned.  This can't be
+ * done by a constructor, since often the DeletedChain instance is used before
+ * its static construct has had a chance to be called.
+ */
 template<class Type>
 void DeletedChain<Type>::
 init_deleted_chain() {
@@ -131,38 +112,32 @@ init_deleted_chain() {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: StaticDeletedChain::allocate
-//       Access: Public, Static
-//  Description: Allocates the memory for a new object of Type.
-////////////////////////////////////////////////////////////////////
+/**
+ * Allocates the memory for a new object of Type.
+ */
 template<class Type>
 INLINE Type *StaticDeletedChain<Type>::
 allocate(size_t size, TypeHandle type_handle) {
-  return _chain.allocate(size, type_handle);
+  Type *ptr = _chain.allocate(size, type_handle);
+  return (Type *)ASSUME_ALIGNED(ptr, MEMORY_HOOK_ALIGNMENT);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: StaticDeletedChain::deallocate
-//       Access: Public
-//  Description: Frees the memory for an object of Type.
-////////////////////////////////////////////////////////////////////
+/**
+ * Frees the memory for an object of Type.
+ */
 template<class Type>
 INLINE void StaticDeletedChain<Type>::
 deallocate(Type *ptr, TypeHandle type_handle) {
   _chain.deallocate(ptr, type_handle);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: StaticDeletedChain::validate
-//       Access: Public
-//  Description: Returns true if the pointer is valid, false if it has
-//               been deleted or if it was never a valid pointer.
-//
-//               This is only meaningful in debug mode, where
-//               USE_DELETEDCHAINFLAG is defined.  If not, this
-//               trivially returns true.
-////////////////////////////////////////////////////////////////////
+/**
+ * Returns true if the pointer is valid, false if it has been deleted or if it
+ * was never a valid pointer.
+ *
+ * This is only meaningful in debug mode, where USE_DELETEDCHAINFLAG is
+ * defined.  If not, this trivially returns true.
+ */
 template<class Type>
 INLINE bool StaticDeletedChain<Type>::
 validate(const Type *ptr) {

+ 6 - 0
dtool/src/dtoolbase/dtoolbase.h

@@ -89,6 +89,12 @@
 #define NODEFAULT
 #endif
 
+// Use this to hint the compiler that a memory address is aligned.
+#if __has_builtin(__builtin_assume_aligned) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+#define ASSUME_ALIGNED(x, y) (__builtin_assume_aligned(x, y))
+#else
+#define ASSUME_ALIGNED(x, y) (x)
+#endif
 
 /*
   include win32 defns for everything up to WinServer2003, and assume

+ 3 - 3
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -290,10 +290,10 @@ EXPCL_DTOOL void init_memory_hook();
 
 // Now redefine some handy macros to hook into the above MemoryHook object.
 #ifndef USE_MEMORY_NOWRAPPERS
-#define PANDA_MALLOC_SINGLE(size) (memory_hook->heap_alloc_single(size))
+#define PANDA_MALLOC_SINGLE(size) (ASSUME_ALIGNED(memory_hook->heap_alloc_single(size), MEMORY_HOOK_ALIGNMENT))
 #define PANDA_FREE_SINGLE(ptr) memory_hook->heap_free_single(ptr)
-#define PANDA_MALLOC_ARRAY(size) (memory_hook->heap_alloc_array(size))
-#define PANDA_REALLOC_ARRAY(ptr, size) (memory_hook->heap_realloc_array(ptr, size))
+#define PANDA_MALLOC_ARRAY(size) (ASSUME_ALIGNED(memory_hook->heap_alloc_array(size), MEMORY_HOOK_ALIGNMENT))
+#define PANDA_REALLOC_ARRAY(ptr, size) (ASSUME_ALIGNED(memory_hook->heap_realloc_array(ptr, size), MEMORY_HOOK_ALIGNMENT))
 #define PANDA_FREE_ARRAY(ptr) memory_hook->heap_free_array(ptr)
 #else
 #define PANDA_MALLOC_SINGLE(size) ::malloc(size)

+ 36 - 67
dtool/src/dtoolbase/memoryHook.I

@@ -38,57 +38,9 @@ dec_heap(size_t size) {
  * Returns the global memory alignment.  This is the number of bytes at which
  * each allocated memory pointer will be aligned.
  */
-INLINE size_t MemoryHook::
+CONSTEXPR size_t MemoryHook::
 get_memory_alignment() {
-#ifdef LINMATH_ALIGN
-  // We require 16-byte alignment of certain structures, to support SSE2.  We
-  // don't strictly have to align *everything*, but it's just easier to do so.
-#ifdef __AVX__
-  // Eigen requires 32-byte alignment when using AVX instructions.
-  const size_t alignment_size = 32;
-#else
-  const size_t alignment_size = 16;
-#endif
-#else
-  // Otherwise, align to two words.  This seems to be pretty standard to the
-  // point where some code may rely on this being the case.
-  const size_t alignment_size = sizeof(void *) * 2;
-#endif
-  return alignment_size;
-}
-
-/**
- * Returns the number of additional bytes that are reserved at the beginning
- * of every allocated block to store a size_t.
- */
-INLINE size_t MemoryHook::
-get_header_reserved_bytes() {
-  // We need to figure out the minimum amount of additional space we need in
-  // order to place a single word at the start of each allocated block, to
-  // store the size of the block.
-
-#ifdef LINMATH_ALIGN
-  // If we're doing SSE2 alignment, we must reserve a full 16-byte block,
-  // since anything less than that will spoil the alignment.
-#ifdef __AVX__
-  // Eigen requires 32-byte alignment when using AVX instructions.
-  static const size_t header_reserved_bytes = 32;
-#else
-  static const size_t header_reserved_bytes = 16;
-#endif
-
-#elif defined(MEMORY_HOOK_DO_ALIGN)
-  // If we're just aligning to words, we reserve a block as big as two words,
-  // to allow us wiggle room to align the word precisely within that block.
-  static const size_t header_reserved_bytes = sizeof(size_t) + sizeof(size_t);
-
-#else
-  // Virtually all allocators align to two words, so we make sure we preserve
-  // that alignment for the benefit of anyone who relies upon that.
-  static const size_t header_reserved_bytes = sizeof(void *) * 2;
-#endif
-
-  return header_reserved_bytes;
+  return MEMORY_HOOK_ALIGNMENT;
 }
 
 /**
@@ -109,6 +61,24 @@ round_up_to_page_size(size_t size) const {
   return  ((size + _page_size - 1) / _page_size) * _page_size;
 }
 
+/**
+ * Given a pointer that was returned by a MemoryHook allocation, returns the
+ * number of bytes that were allocated for it.  Returns 0 if not compiling
+ * with DO_MEMORY_USAGE.
+ */
+INLINE size_t MemoryHook::
+get_ptr_size(void *ptr) {
+#if defined(MEMORY_HOOK_DO_ALIGN)
+  uintptr_t *root = (uintptr_t *)ptr;
+  return (size_t)root[-2];
+#elif defined(DO_MEMORY_USAGE)
+  size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
+  return *root;
+#else
+  return 0;
+#endif  // DO_MEMORY_USAGE
+}
+
 /**
  * Increments the amount of requested size as necessary to accommodate the
  * extra data we might piggyback on each allocated block.
@@ -118,12 +88,13 @@ inflate_size(size_t size) {
 #if defined(MEMORY_HOOK_DO_ALIGN)
   // If we're aligning, we need to request the header size, plus extra bytes
   // to give us wiggle room to adjust the pointer.
-  return size + get_header_reserved_bytes() + get_memory_alignment() - 1;
+  return size + sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1;
 #elif defined(DO_MEMORY_USAGE)
   // If we're not aligning, but we're tracking memory allocations, we just
   // need the header size extra (this gives us a place to store the size of
-  // the allocated block).
-  return size + get_header_reserved_bytes();
+  // the allocated block).  However, we do need to make sure that any
+  // alignment guarantee is kept.
+  return size + MEMORY_HOOK_ALIGNMENT;
 #else
   // If we're not doing any of that, we can just allocate the precise
   // requested amount.
@@ -138,17 +109,17 @@ inflate_size(size_t size) {
 INLINE void *MemoryHook::
 alloc_to_ptr(void *alloc, size_t size) {
 #if defined(MEMORY_HOOK_DO_ALIGN)
-  size_t alignment = get_memory_alignment();
-  // Move the allocated pointer up to the next even alignment.
-  size_t *root = (size_t *)((((size_t)alloc + alignment - 1) / alignment) * alignment);
-  assert(alloc <= root && (size_t)((char *)root - (char *)alloc) < alignment);
-  root[0] = size;
-  root[1] = (size_t)alloc;  // Save the pointer we originally allocated.
-  return (void *)((char *)root + get_header_reserved_bytes());
+  // Add room for two uintptr_t values.
+  uintptr_t *root = (uintptr_t *)((char *)alloc + sizeof(uintptr_t) * 2);
+  // Align this to the requested boundary.
+  root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
+  root[-2] = size;
+  root[-1] = (uintptr_t)alloc;  // Save the pointer we originally allocated.
+  return (void *)root;
 #elif defined(DO_MEMORY_USAGE)
   size_t *root = (size_t *)alloc;
   root[0] = size;
-  return (void *)((char *)root + get_header_reserved_bytes());
+  return (void *)((char *)root + MEMORY_HOOK_ALIGNMENT);
 #else
   return alloc;
 #endif  // DO_MEMORY_USAGE
@@ -161,13 +132,11 @@ alloc_to_ptr(void *alloc, size_t size) {
 INLINE void *MemoryHook::
 ptr_to_alloc(void *ptr, size_t &size) {
 #if defined(MEMORY_HOOK_DO_ALIGN)
-  size_t *root = (size_t *)((char *)ptr - get_header_reserved_bytes());
-  size = root[0];
-  void *alloc = (void *)root[1]; // Get the pointer we originally allocated.
-  assert(alloc <= root && (size_t)((char *)root - (char *)alloc) < get_memory_alignment());
-  return alloc;
+  uintptr_t *root = (uintptr_t *)ptr;
+  size = root[-2];
+  return (void *)root[-1]; // Get the pointer we originally allocated.
 #elif defined(DO_MEMORY_USAGE)
-  size_t *root = (size_t *)((char *)ptr - get_header_reserved_bytes());
+  size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
   size = root[0];
   return (void *)root;
 #else

+ 29 - 17
dtool/src/dtoolbase/memoryHook.cxx

@@ -36,6 +36,15 @@
 
 #endif  // WIN32
 
+// Ensure we made the right decisions about the alignment size.
+static_assert(MEMORY_HOOK_ALIGNMENT >= sizeof(size_t),
+              "MEMORY_HOOK_ALIGNMENT should at least be sizeof(size_t)");
+static_assert(MEMORY_HOOK_ALIGNMENT >= sizeof(void *),
+              "MEMORY_HOOK_ALIGNMENT should at least be sizeof(void *)");
+static_assert(MEMORY_HOOK_ALIGNMENT * 8 >= NATIVE_WORDSIZE,
+              "MEMORY_HOOK_ALIGNMENT * 8 should at least be NATIVE_WORDSIZE");
+static_assert((MEMORY_HOOK_ALIGNMENT & (MEMORY_HOOK_ALIGNMENT - 1)) == 0,
+              "MEMORY_HOOK_ALIGNMENT should be a power of two");
 
 #if defined(USE_MEMORY_DLMALLOC)
 
@@ -49,17 +58,8 @@
 #ifdef _DEBUG
   #define DEBUG 1
 #endif
-#ifdef LINMATH_ALIGN
-// drose: We require 16-byte alignment of certain structures, to
-// support SSE2.  We don't strictly have to align *everything*, but
-// it's just easier to do so.
-#ifdef __AVX__
-// Eigen requires 32-byte alignment when using AVX instructions.
-#define MALLOC_ALIGNMENT ((size_t)32U)
-#else
-#define MALLOC_ALIGNMENT ((size_t)16U)
-#endif
-#endif
+// dlmalloc can do the alignment we ask for.
+#define MALLOC_ALIGNMENT MEMORY_HOOK_ALIGNMENT
 
 #include "dlmalloc_src.cxx"
 
@@ -204,6 +204,7 @@ heap_alloc_single(size_t size) {
 #endif  // DO_MEMORY_USAGE
 
   void *ptr = alloc_to_ptr(alloc, size);
+  assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
   return ptr;
 }
@@ -273,6 +274,7 @@ heap_alloc_array(size_t size) {
 #endif  // DO_MEMORY_USAGE
 
   void *ptr = alloc_to_ptr(alloc, size);
+  assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
   return ptr;
 }
@@ -316,17 +318,27 @@ heap_realloc_array(void *ptr, size_t size) {
 #endif
   }
 
-  void *ptr1 = alloc_to_ptr(alloc1, size);
-  assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
-#if defined(MEMORY_HOOK_DO_ALIGN)
-  // We might have to shift the memory to account for the new offset due to
-  // the alignment.
+  // Align this to the requested boundary.
+#ifdef MEMORY_HOOK_DO_ALIGN
+  // This copies the code from alloc_to_ptr, since we can't write the size and
+  // pointer until after we have done the memmove.
+  uintptr_t *root = (uintptr_t *)((char *)alloc1 + sizeof(uintptr_t) * 2);
+  root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
+  void *ptr1 = (void *)root;
+
   size_t orig_delta = (char *)ptr - (char *)alloc;
   size_t new_delta = (char *)ptr1 - (char *)alloc1;
   if (orig_delta != new_delta) {
     memmove((char *)alloc1 + new_delta, (char *)alloc1 + orig_delta, min(size, orig_size));
   }
-#endif  // MEMORY_HOOK_DO_ALIGN
+
+  root[-2] = size;
+  root[-1] = (uintptr_t)alloc1;  // Save the pointer we originally allocated.
+#else
+  void *ptr1 = alloc_to_ptr(alloc1, size);
+#endif
+  assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
+  assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0);
   return ptr1;
 }
 

+ 19 - 2
dtool/src/dtoolbase/memoryHook.h

@@ -20,6 +20,22 @@
 #include "mutexImpl.h"
 #include <map>
 
+#ifdef LINMATH_ALIGN
+// We require 16-byte alignment of certain structures, to support SSE2.  We
+// don't strictly have to align *everything*, but it's just easier to do so.
+#ifdef __AVX__
+#define MEMORY_HOOK_ALIGNMENT 32
+#else
+#define MEMORY_HOOK_ALIGNMENT 16
+#endif
+// Otherwise, align to two words.  This seems to be pretty standard to the
+// point where some code may rely on this being the case.
+#elif defined(IS_OSX) || NATIVE_WORDSIZE >= 64
+#define MEMORY_HOOK_ALIGNMENT 16
+#else
+#define MEMORY_HOOK_ALIGNMENT 8
+#endif
+
 class DeletedBufferChain;
 
 /**
@@ -52,8 +68,7 @@ public:
 
   bool heap_trim(size_t pad);
 
-  INLINE static size_t get_memory_alignment();
-  INLINE static size_t get_header_reserved_bytes();
+  CONSTEXPR static size_t get_memory_alignment();
 
   virtual void *mmap_alloc(size_t size, bool allow_exec);
   virtual void mmap_free(void *ptr, size_t size);
@@ -66,6 +81,8 @@ public:
 
   virtual void alloc_fail(size_t attempted_size);
 
+  INLINE static size_t get_ptr_size(void *ptr);
+
 private:
   INLINE static size_t inflate_size(size_t size);
   INLINE static void *alloc_to_ptr(void *alloc, size_t size);

+ 23 - 24
dtool/src/dtoolbase/pallocator.T

@@ -1,16 +1,15 @@
-// Filename: pallocator.T
-// Created by:  drose (05Jun01)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file pallocator.T
+ * @author drose
+ * @date 2001-06-05
+ */
 
 template<class Type>
 INLINE pallocator_single<Type>::
@@ -25,7 +24,8 @@ allocate(TYPENAME pallocator_single<Type>::size_type n, TYPENAME allocator<void>
   TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
   // This doesn't support allocating arrays.
   assert(n == 1);
-  return StaticDeletedChain<Type>::allocate(sizeof(Type), _type_handle);
+  return (Type *)ASSUME_ALIGNED(StaticDeletedChain<Type>::allocate(sizeof(Type), _type_handle),
+                                MEMORY_HOOK_ALIGNMENT);
 }
 
 template<class Type>
@@ -47,14 +47,13 @@ INLINE TYPENAME pallocator_array<Type>::pointer pallocator_array<Type>::
 allocate(TYPENAME pallocator_array<Type>::size_type n, TYPENAME allocator<void>::const_pointer) {
   TAU_PROFILE("pallocator_array:allocate()", " ", TAU_USER);
 #ifdef DO_MEMORY_USAGE
-  const size_t header_reserved_bytes = MemoryHook::get_header_reserved_bytes();
   size_t alloc_size = n * sizeof(Type);
-  // We also need to store the total number of bytes we allocated.
-  alloc_size += header_reserved_bytes;
-  _type_handle.inc_memory_usage(TypeHandle::MC_array, alloc_size);
   void *ptr = (TYPENAME pallocator_array<Type>::pointer)PANDA_MALLOC_ARRAY(alloc_size);
-  *((size_t *)ptr) = alloc_size;
-  return (TYPENAME pallocator_array<Type>::pointer)(((char *)ptr) + header_reserved_bytes);
+#ifdef _DEBUG
+  assert(alloc_size == MemoryHook::get_ptr_size(ptr));
+#endif
+  _type_handle.inc_memory_usage(TypeHandle::MC_array, alloc_size);
+  return (TYPENAME pallocator_array<Type>::pointer)ASSUME_ALIGNED(ptr, MEMORY_HOOK_ALIGNMENT);
 #else
   return (TYPENAME pallocator_array<Type>::pointer)PANDA_MALLOC_ARRAY(n * sizeof(Type));
 #endif  // DO_MEMORY_USAGE
@@ -65,10 +64,10 @@ INLINE void pallocator_array<Type>::
 deallocate(TYPENAME pallocator_array<Type>::pointer p, TYPENAME pallocator_array<Type>::size_type) {
   TAU_PROFILE("pallocator_array:deallocate()", " ", TAU_USER);
 #ifdef DO_MEMORY_USAGE
-  // Now we need to recover the total number of bytes.
-  const size_t header_reserved_bytes = MemoryHook::get_header_reserved_bytes();
-  void *ptr = (void *)((char *)p - header_reserved_bytes);
-  size_t alloc_size = *((size_t *)ptr);
+  // Now we need to recover the total number of bytes.  Fortunately, in the
+  // case of DO_MEMORY_USAGE, MemoryHook already keeps track of this.
+  void *ptr = (void *)p;
+  size_t alloc_size = MemoryHook::get_ptr_size(ptr);
   _type_handle.dec_memory_usage(TypeHandle::MC_array, alloc_size);
   PANDA_FREE_ARRAY(ptr);
 #else

+ 18 - 10
panda/src/gobj/vertexDataBuffer.I

@@ -67,17 +67,22 @@ INLINE const unsigned char *VertexDataBuffer::
 get_read_pointer(bool force) const {
   LightMutexHolder holder(_lock);
 
+  const unsigned char *ptr;
   if (_resident_data != (unsigned char *)NULL || _size == 0) {
-    return _resident_data;
+    ptr = _resident_data;
+  } else {
+    nassertr(_block != (VertexDataBlock *)NULL, NULL);
+    nassertr(_reserved_size >= _size, NULL);
+
+    // We don't necessarily need to page the buffer all the way into independent
+    // status; it's sufficient just to return the block's pointer, which will
+    // force its page to resident status.
+    ptr = _block->get_pointer(force);
   }
-
-  nassertr(_block != (VertexDataBlock *)NULL, NULL);
-  nassertr(_reserved_size >= _size, NULL);
-
-  // We don't necessarily need to page the buffer all the way into independent
-  // status; it's sufficient just to return the block's pointer, which will
-  // force its page to resident status.
-  return _block->get_pointer(force);
+#ifdef _DEBUG
+  assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
+#endif
+  return (const unsigned char *)ASSUME_ALIGNED(ptr, MEMORY_HOOK_ALIGNMENT);
 }
 
 /**
@@ -91,7 +96,10 @@ get_write_pointer() {
     do_page_in();
   }
   nassertr(_reserved_size >= _size, NULL);
-  return _resident_data;
+#ifdef _DEBUG
+  assert(((uintptr_t)_resident_data % MEMORY_HOOK_ALIGNMENT) == 0);
+#endif
+  return (unsigned char *)ASSUME_ALIGNED(_resident_data, MEMORY_HOOK_ALIGNMENT);
 }
 
 /**