LCOV - code coverage report
Current view: top level - mm - dumpmemory.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 51 53 96.2 %
Date: 2017-07-14 10:03:36 Functions: 62 85 72.9 %

          Line data    Source code
       1             : /* src/mm/dumpmemory.hpp - dump memory management
       2             : 
       3             :    Copyright (C) 1996-2013
       4             :    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
       5             :    Copyright (C) 2008 Theobroma Systems Ltd.
       6             : 
       7             :    This file is part of CACAO.
       8             : 
       9             :    This program is free software; you can redistribute it and/or
      10             :    modify it under the terms of the GNU General Public License as
      11             :    published by the Free Software Foundation; either version 2, or (at
      12             :    your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful, but
      15             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :    General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program; if not, write to the Free Software
      21             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      22             :    02110-1301, USA.
      23             : 
      24             : */
      25             : 
      26             : 
      27             : #ifndef DUMPMEMORY_HPP_
      28             : #define DUMPMEMORY_HPP_ 1
      29             : 
      30             : #include <assert.h>                     // for assert
      31             : #include <stddef.h>                     // for size_t, NULL
      32             : #include <stdint.h>                     // for uint8_t
      33             : #include <cstddef>                      // for ptrdiff_t, size_t
      34             : #include <list>                         // for list
      35             : #include <new>                          // for operator new
      36             : #include <vector>                       // for vector
      37             : #include "config.h"                     // for ENABLE_MEMCHECK
      38             : #include "mm/memory.hpp"                // for MEMORY_CANARY_SIZE, etc
      39             : #include "threads/thread.hpp"           // for thread_get_current, etc
      40             : #include "vm/os.hpp"                    // for os
      41             : 
      42             : class DumpMemoryAllocation;
      43             : class DumpMemoryArea;
      44             : class DumpMemoryBlock;
      45             : 
      46             : /**
      47             :  * All classes intended to be allocated on dump memory should extend this
      48             :  * base class to inherit the appropriate allocation operators.
      49             :  */
      50      461177 : class DumpClass {
      51             : public:
      52             :         void* operator new(size_t size);
      53             :         void operator delete(void* p);
      54             : };
      55             : 
      56             : 
      57             : /**
      58             :  * Thread-local dump memory structure.
      59             :  */
      60             : class DumpMemory {
      61             : private:
      62             :         size_t                     _size;  ///< Size of the dump areas in this dump memory.
      63             :         size_t                     _used;  ///< Used memory in this dump memory.
      64             :         std::list<DumpMemoryArea*> _areas; ///< Pointer to the current dump area.
      65             : 
      66             : public:
      67             :         DumpMemory();
      68             :         ~DumpMemory();
      69             : 
      70             :         static inline DumpMemory* get_current();
      71             :         static inline void*       allocate(size_t size);
      72             : 
      73             :         inline void   add_size(size_t size) { _size += size; }
      74             : 
      75             :         inline size_t get_size() const { return _size; }
      76             :         inline size_t get_used() const { return _used; }
      77             : 
      78             :         inline DumpMemoryArea* get_current_area() const;
      79             : 
      80             :         static void* reallocate(void* src, size_t len1, size_t len2);
      81             : 
      82             :         void  add_area(DumpMemoryArea* dma);
      83             :         void  remove_area(DumpMemoryArea* dma);
      84             : };
      85             : 
      86             : 
      87             : /**
      88             :  * Dump memory area.
      89             :  */
      90             : class DumpMemoryArea {
      91             : private:
      92             :         size_t                        _size;   ///< Size of the current memory block.
      93             :         size_t                        _used;   ///< Used memory in the current memory block.
      94             :         std::vector<DumpMemoryBlock*> _blocks; ///< List of memory blocks in this area.
      95             : #if defined(ENABLE_MEMCHECK)
      96             :         std::vector<DumpMemoryAllocation*> _allocs; ///< List of allocations in this area.
      97             : #endif
      98             : 
      99             : public:
     100             :         DumpMemoryArea(size_t size = 0);
     101             :         ~DumpMemoryArea();
     102             : 
     103     2620983 :         inline size_t get_size() const { return _size; }
     104     1310460 :         inline size_t get_used() const { return _used; }
     105             : 
     106             :         // Inline functions.
     107             :         inline void*            allocate(size_t size);
     108             :         inline DumpMemoryBlock* get_current_block() const;
     109             : 
     110             :         DumpMemoryBlock* allocate_new_block(size_t size);
     111             : 
     112             : #if defined(ENABLE_MEMCHECK)
     113             : private:
     114             :         void check_canaries();
     115             : #endif
     116             : };
     117             : 
     118             : 
     119             : /**
     120             :  * Dump memory block.
     121             :  */
     122             : class DumpMemoryBlock {
     123             : private:
     124             :         static const size_t DEFAULT_SIZE = 2 << 13; // 2 * 8192 bytes
     125             : 
     126             :         size_t _size;  ///< Size of the current memory block.
     127             :         size_t _used;  ///< Used memory in the current memory block.
     128             :         void*  _block; ///< List of memory blocks in this area.
     129             : 
     130             : public:
     131             :         DumpMemoryBlock(size_t size = 0);
     132             :         ~DumpMemoryBlock();
     133             : 
     134     1550997 :         inline size_t get_size() const { return _size; }
     135             :         inline size_t get_used() const { return _used; }
     136     9852863 :         inline size_t get_free() const { return _size - _used; }
     137             : 
     138             :         // Inline functions.
     139             :         inline void* allocate(size_t size);
     140             : };
     141             : 
     142             : 
     143             : /**
     144             :  * Allocator for the dump memory.
     145             :  */
     146             : template<class T> class DumpMemoryAllocator {
     147             : public:
     148             :         // Type definitions.
     149             :         typedef T              value_type;
     150             :         typedef T*             pointer;
     151             :         typedef const T*       const_pointer;
     152             :         typedef T&             reference;
     153             :         typedef const T&       const_reference;
     154             :         typedef std::size_t    size_type;
     155             :         typedef std::ptrdiff_t difference_type;
     156             : 
     157             :         // Rebind allocator to type U.
     158             :         template <class U> struct rebind {
     159             :                 typedef DumpMemoryAllocator<U> other;
     160             :         };
     161             : 
     162             :         // Constructors and destructor, nothing to do because the
     163             :         // allocator has no state.
     164      461178 :         DumpMemoryAllocator() throw() {}
     165             :         DumpMemoryAllocator(const DumpMemoryAllocator&) throw() {}
     166     4307142 :         template <class U> DumpMemoryAllocator(const DumpMemoryAllocator<U>&) throw() {}
     167             : 
     168     4557672 :         ~DumpMemoryAllocator() throw() {}
     169             : 
     170     2567950 :         pointer allocate(size_type n, void* = 0) {
     171             : //              printf("allocate: n=%d * %d\n", n, sizeof(T));
     172     2567950 :                 return static_cast<pointer>(DumpMemory::allocate(n * sizeof(T)));
     173             :         }
     174             : 
     175             :         // ** Reallocate block of storage (non-standard!)
     176             :         inline pointer reallocate(pointer p, size_type old_sz, size_type new_sz) {
     177             :                 return static_cast<pointer>(DumpMemory::reallocate(p, old_sz * sizeof(T), new_sz * sizeof(T)));
     178             :         }
     179             : 
     180             :         // Initialize elements of allocated storage p with value value.
     181     2567950 :         void construct(pointer p, const T& value) {
     182             : //              printf("construct: p=%p, value=%p\n", (void*) p, (void*) value);
     183             :                 // Initialize memory with placement new.
     184     2567950 :                 new ((void*) p) T(value);
     185     2567950 :         }
     186             : 
     187             :         // Destroy elements of initialized storage p.
     188     1739192 :         void destroy(pointer p) {
     189             : //              printf("destroy: p=%p\n", (void*) p);
     190             :                 // Destroy objects by calling their destructor.
     191     1709334 :                 p->~T();
     192     1739192 :         }
     193             : 
     194     1739192 :         void deallocate(pointer p, size_type n) {
     195             : //              printf("deallocate: p=%p, n=%d\n", (void*) p, n);
     196             :                 // We don't need to deallocate on dump memory.
     197     1739192 :         }
     198             : };
     199             : 
     200             : 
     201             : /**
     202             :  * Dump memory allocation, used for for ENABLE_MEMCHECK.
     203             :  */
     204             : #if defined(ENABLE_MEMCHECK)
     205             : class DumpMemoryAllocation {
     206             : private:
     207             :         size_t _size;
     208             :         void*  _mem;
     209             : 
     210             : public:
     211             :         DumpMemoryAllocation() : _size(0), _mem(NULL) {}
     212             :         DumpMemoryAllocation(size_t size, void* mem) : _size(size), _mem(mem) {}
     213             :         ~DumpMemoryAllocation() {};
     214             : 
     215             :         inline size_t get_size() const { return _size; }
     216             :         inline void*  get_mem()  const { return _mem; }
     217             : };
     218             : #endif
     219             : 
     220             : 
     221             : // Includes.
     222             : #include "mm/memory.hpp"
     223             : 
     224             : #include "vm/statistics.hpp"
     225             : 
     226             : // Inline functions.
     227             : 
     228      210648 : inline void* DumpClass::operator new(size_t size)
     229             : {
     230      210648 :         return DumpMemory::allocate(size);
     231             : }
     232             : 
     233           0 : inline void DumpClass::operator delete(void* p)
     234             : {
     235             :         // We don't need to deallocate on dump memory.
     236           0 : }
     237             : 
     238    13784028 : inline DumpMemory* DumpMemory::get_current()
     239             : {
     240             :         // Get the DumpMemory object of the current thread.
     241    13784028 :         threadobject* t = thread_get_current();
     242    13784057 :         DumpMemory* dm = t->_dumpmemory;
     243    13784057 :         return dm;
     244             : }
     245             : 
     246    11163262 : inline DumpMemoryArea* DumpMemory::get_current_area() const
     247             : {
     248    11163262 :         return _areas.back();
     249             : }
     250             : 
     251    11163258 : inline void* DumpMemory::allocate(size_t size)
     252             : {
     253    11163258 :         DumpMemory* dm = get_current();
     254    11163264 :         DumpMemoryArea* dma = dm->get_current_area();
     255             : 
     256    11163212 :         size_t alignedsize = size;
     257             : 
     258             : #if defined(ENABLE_MEMCHECK)
     259             :         alignedsize += 2 * MEMORY_CANARY_SIZE;
     260             : #endif
     261             : 
     262             :         // Align the allocation size.
     263    11163212 :         alignedsize = MEMORY_ALIGN(alignedsize, ALIGNSIZE);
     264             : 
     265    11163212 :         void* p = dma->allocate(alignedsize);
     266             : 
     267             :         // Increase the used count of the dump memory.
     268    11163317 :         dm->_used += alignedsize;
     269             : 
     270    11163317 :         return p;
     271             : }
     272             : 
     273    11163231 : inline DumpMemoryBlock* DumpMemoryArea::get_current_block() const
     274             : {
     275    11163231 :         return _blocks.empty() ? NULL : _blocks.back();
     276             : }
     277             : 
     278    11163226 : inline void* DumpMemoryArea::allocate(size_t size)
     279             : {
     280    11163226 :         DumpMemoryBlock* dmb = get_current_block();
     281             : 
     282             :         // Check if we have a memory block or have enough memory in the
     283             :         // current memory block.
     284    11163304 :         if (dmb == NULL || size > dmb->get_free()) {
     285             :                 // No, allocate a new one.
     286     1550992 :                 dmb = allocate_new_block(size);
     287             : 
     288             :                 // Increase the size of the memory area.  We use get_size()
     289             :                 // here because the default size is very likely to be bigger
     290             :                 // than size.
     291     1550997 :                 _size += dmb->get_size();
     292             :         }
     293             : 
     294    11163302 :         void* p = dmb->allocate(size);
     295             : 
     296             : #if defined(ENABLE_MEMCHECK)
     297             :         uint8_t *pm;
     298             :         size_t   origsize = size - 2 * MEMORY_CANARY_SIZE;
     299             : 
     300             :         // Make p point after the bottom canary.
     301             : 
     302             :         p = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
     303             : 
     304             :         // Add the allocation to our list of allocations
     305             : 
     306             :         DumpMemoryAllocation* dma = new DumpMemoryAllocation(origsize, p);
     307             : 
     308             :         _allocs.push_back(dma);
     309             : 
     310             :         // Write the canaries.
     311             : 
     312             :         pm = ((uint8_t *) p) - MEMORY_CANARY_SIZE;
     313             : 
     314             :         for (int i = 0; i < MEMORY_CANARY_SIZE; ++i)
     315             :                 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
     316             : 
     317             :         pm = ((uint8_t *) p) + dma->get_size();
     318             : 
     319             :         for (int i = 0; i < MEMORY_CANARY_SIZE; ++i)
     320             :                 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
     321             : 
     322             :         // Clear the memory.
     323             : 
     324             :         (void) os::memset(p, MEMORY_CLEAR_BYTE, dma->get_size());
     325             : #endif /* defined(ENABLE_MEMCHECK) */
     326             : 
     327             :         // Increase the used size of the memory area.
     328    11163312 :         _used += size;
     329             : 
     330    11163312 :         return p;
     331             : }
     332             : 
     333             : /**
     334             :  * Allocate memory in the current dump memory area.
     335             :  *
     336             :  * This function is a fast allocator suitable for scratch memory that
     337             :  * can be collectively freed when the current activity (eg. compiling)
     338             :  * is done.
     339             :  *
     340             :  * You cannot selectively free dump memory. Before you start
     341             :  * allocating it, you remember the current size returned by
     342             :  * `dumpmemory_marker`. Later, when you no longer need the memory,
     343             :  * call `dumpmemory_release` with the remembered size and all dump
     344             :  * memory allocated since the call to `dumpmemory_marker` will be
     345             :  * freed.
     346             :  *
     347             :  * @parm size Size of block to allocate in bytes. May be zero, in which case NULL is returned
     348             :  *
     349             :  * @return Pointer to allocated memory, or NULL iff size was zero.
     350             :  */
     351    11163321 : void* DumpMemoryBlock::allocate(size_t size)
     352             : {
     353    11163321 :         if (size == 0)
     354      850180 :                 return NULL;
     355             : 
     356             :         // Sanity check.
     357    10313141 :         assert(size <= (_size - _used));
     358             : 
     359             :         // Calculate the memory address of the newly allocated memory.
     360    10313141 :         void* p = (void*) (((uint8_t*) _block) + _used);
     361             : 
     362             :         // Increase used memory block size by the allocated memory size.
     363    10313141 :         _used += size;
     364             : 
     365    10313141 :         return p;
     366             : }
     367             : 
     368             : // Legacy C interface.
     369             : 
     370             : #define DNEW(type)                    ((type*) DumpMemory::allocate(sizeof(type)))
     371             : #define DMNEW(type,num)               ((type*) DumpMemory::allocate(sizeof(type) * (num)))
     372             : #define DMREALLOC(ptr,type,num1,num2) ((type*) DumpMemory::reallocate((ptr), sizeof(type) * (num1), sizeof(type) * (num2)))
     373             : 
     374             : #endif // DUMPMEMORY_HPP_
     375             : 
     376             : 
     377             : /*
     378             :  * These are local overrides for various environment variables in Emacs.
     379             :  * Please do not remove this and leave it at the end of the file, where
     380             :  * Emacs will automagically detect them.
     381             :  * ---------------------------------------------------------------------
     382             :  * Local variables:
     383             :  * mode: c++
     384             :  * indent-tabs-mode: t
     385             :  * c-basic-offset: 4
     386             :  * tab-width: 4
     387             :  * End:
     388             :  * vim:noexpandtab:sw=4:ts=4:
     389             :  */

Generated by: LCOV version 1.11