diff options
author | Juan Linietsky <reduzio@gmail.com> | 2017-01-06 10:15:44 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2017-01-06 10:15:44 -0300 |
commit | 53ce643e520de193c085c0c23046dcbd2e5308a5 (patch) | |
tree | d8336629c4ce789eb441fc3bd428e317d8ad8e9c /core | |
parent | 99ceddd11ef652a3b8e6bf5d09dcc519d957ce14 (diff) |
-Changed memory functions, Memory::alloc_static*, simplified them, made them aligned to 16
-Changed Vector<> template to fit this.
Diffstat (limited to 'core')
-rw-r--r-- | core/os/memory.cpp | 205 | ||||
-rw-r--r-- | core/os/memory.h | 135 | ||||
-rw-r--r-- | core/os/memory_pool_dynamic_static.cpp | 2 | ||||
-rw-r--r-- | core/os/memory_pool_dynamic_static.h | 2 | ||||
-rw-r--r-- | core/os/memory_pool_static.cpp | 49 | ||||
-rw-r--r-- | core/os/memory_pool_static.h | 69 | ||||
-rw-r--r-- | core/os/os.cpp | 8 | ||||
-rw-r--r-- | core/pool_allocator.cpp | 4 | ||||
-rw-r--r-- | core/safe_refcount.cpp | 61 | ||||
-rw-r--r-- | core/safe_refcount.h | 312 | ||||
-rw-r--r-- | core/typedefs.h | 4 | ||||
-rw-r--r-- | core/vector.h | 71 |
12 files changed, 329 insertions, 593 deletions
diff --git a/core/os/memory.cpp b/core/os/memory.cpp index 4922a18335..cf42c3681a 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -30,9 +30,68 @@ #include "error_macros.h" #include "copymem.h" #include <stdio.h> +#include <stdlib.h> + + +MID::MID(MemoryPoolDynamic::ID p_id) { + + data = (Data*)memalloc(sizeof(Data)); + data->refcount.init(); + data->id=p_id; +} + +void MID::unref() { + + if (!data) + return; + if (data->refcount.unref()) { + + if (data->id!=MemoryPoolDynamic::INVALID_ID) + MemoryPoolDynamic::get_singleton()->free(data->id); + memfree(data); + } + + data=NULL; +} +Error MID::_resize(size_t p_size) { + + if (p_size==0 && (!data || data->id==MemoryPoolDynamic::INVALID_ID)) + return OK; + if (p_size && !data) { + // create data because we'll need it + data = (Data*)memalloc(sizeof(Data)); + ERR_FAIL_COND_V( !data,ERR_OUT_OF_MEMORY ); + data->refcount.init(); + data->id=MemoryPoolDynamic::INVALID_ID; + } + + if (p_size==0 && data && data->id==MemoryPoolDynamic::INVALID_ID) { + + MemoryPoolDynamic::get_singleton()->free(data->id); + data->id=MemoryPoolDynamic::INVALID_ID; + } + + if (p_size>0) { + + if (data->id==MemoryPoolDynamic::INVALID_ID) { + + data->id=MemoryPoolDynamic::get_singleton()->alloc(p_size,"Unnamed MID"); + ERR_FAIL_COND_V( data->id==MemoryPoolDynamic::INVALID_ID, ERR_OUT_OF_MEMORY ); + + } else { + + MemoryPoolDynamic::get_singleton()->realloc(data->id,p_size); + ERR_FAIL_COND_V( data->id==MemoryPoolDynamic::INVALID_ID, ERR_OUT_OF_MEMORY ); + + } + } + + return OK; +} + void * operator new(size_t p_size,const char *p_description) { - return Memory::alloc_static( p_size, p_description ); + return Memory::alloc_static( p_size, false ); } void * operator new(size_t p_size,void* (*p_allocfunc)(size_t p_size)) { @@ -42,49 +101,147 @@ void * operator new(size_t p_size,void* (*p_allocfunc)(size_t p_size)) { #include <stdio.h> -void * Memory::alloc_static(size_t p_bytes,const char *p_alloc_from) { +#ifdef DEBUG_ENABLED +size_t Memory::mem_usage=0; +size_t Memory::max_usage=0; +#endif - ERR_FAIL_COND_V( !MemoryPoolStatic::get_singleton(), NULL ); - return MemoryPoolStatic::get_singleton()->alloc(p_bytes,p_alloc_from); -} -void * Memory::realloc_static(void *p_memory,size_t p_bytes) { +size_t Memory::alloc_count=0; - ERR_FAIL_COND_V( !MemoryPoolStatic::get_singleton(), NULL ); - return MemoryPoolStatic::get_singleton()->realloc(p_memory,p_bytes); -} -void Memory::free_static(void *p_ptr) { +void * Memory::alloc_static(size_t p_bytes,bool p_pad_align) { - ERR_FAIL_COND( !MemoryPoolStatic::get_singleton()); - MemoryPoolStatic::get_singleton()->free(p_ptr); -} +#ifdef DEBUG_ENABLED + bool prepad=true; +#else + bool prepad=p_pad_align; +#endif + + void * mem = malloc( p_bytes + (prepad?PAD_ALIGN:0)); + + alloc_count++; -size_t Memory::get_static_mem_available() { + ERR_FAIL_COND_V(!mem,NULL); - ERR_FAIL_COND_V( !MemoryPoolStatic::get_singleton(), 0); - return MemoryPoolStatic::get_singleton()->get_available_mem(); + if (prepad) { + uint64_t *s = (uint64_t*)mem; + *s=p_bytes; + uint8_t *s8 = (uint8_t*)mem; + +#ifdef DEBUG_ENABLED + mem_usage+=p_bytes; + if (mem_usage>max_usage) { + max_usage=mem_usage; + } +#endif + return s8 + PAD_ALIGN; + } else { + return mem; + } } -size_t Memory::get_static_mem_max_usage() { +void * Memory::realloc_static(void *p_memory,size_t p_bytes,bool p_pad_align) { + + if (p_memory==NULL) { + return alloc_static(p_bytes,p_pad_align); + } + + uint8_t *mem = (uint8_t*)p_memory; + +#ifdef DEBUG_ENABLED + bool prepad=true; +#else + bool prepad=p_pad_align; +#endif + + if (prepad) { + mem-=PAD_ALIGN; + uint64_t *s = (uint64_t*)mem; + +#ifdef DEBUG_ENABLED + mem_usage-=*s; + mem_usage+=p_bytes; +#endif + + if (p_bytes==0) { + free(mem); + return NULL; + } else { + *s=p_bytes; + + mem = (uint8_t*)realloc(mem,p_bytes+PAD_ALIGN); + ERR_FAIL_COND_V(!mem,NULL); + + s = (uint64_t*)mem; + + *s=p_bytes; + + return mem+PAD_ALIGN; + } + } else { + + mem = (uint8_t*)realloc(mem,p_bytes); + + ERR_FAIL_COND_V(mem==NULL && p_bytes>0,NULL); - ERR_FAIL_COND_V( !MemoryPoolStatic::get_singleton(), 0); - return MemoryPoolStatic::get_singleton()->get_max_usage(); + return mem; + } } -size_t Memory::get_static_mem_usage() { +void Memory::free_static(void *p_ptr,bool p_pad_align) { - ERR_FAIL_COND_V( !MemoryPoolStatic::get_singleton(), 0); - return MemoryPoolStatic::get_singleton()->get_total_usage(); + ERR_FAIL_COND(p_ptr==NULL); + + uint8_t *mem = (uint8_t*)p_ptr; + +#ifdef DEBUG_ENABLED + bool prepad=true; +#else + bool prepad=p_pad_align; +#endif + + alloc_count--; + + if (prepad) { + mem-=PAD_ALIGN; + uint64_t *s = (uint64_t*)mem; + +#ifdef DEBUG_ENABLED + mem_usage-=*s; +#endif + + free(mem); + } else { + + free(mem); + } } -void Memory::dump_static_mem_to_file(const char* p_file) { +size_t Memory::get_mem_available() { + + return 0xFFFFFFFFFFFFF; + +} - MemoryPoolStatic::get_singleton()->dump_mem_to_file(p_file); +size_t Memory::get_mem_usage(){ +#ifdef DEBUG_ENABLED + return mem_usage; +#else + return 0; +#endif +} +size_t Memory::get_mem_max_usage(){ +#ifdef DEBUG_ENABLED + return max_usage; +#else + return 0; +#endif } + MID Memory::alloc_dynamic(size_t p_bytes, const char *p_descr) { MemoryPoolDynamic::ID id = MemoryPoolDynamic::get_singleton()->alloc(p_bytes,p_descr); diff --git a/core/os/memory.h b/core/os/memory.h index b3b806f7c6..6a939e3d6f 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -32,13 +32,18 @@ #include <stddef.h> #include "safe_refcount.h" #include "os/memory_pool_dynamic.h" -#include "os/memory_pool_static.h" + /** @author Juan Linietsky <reduzio@gmail.com> */ +#ifndef PAD_ALIGN +#define PAD_ALIGN 16 //must always be greater than this at much +#endif + + class MID { struct Data { @@ -49,19 +54,7 @@ class MID { mutable Data *data; - void unref() { - if (!data) - return; - if (data->refcount.unref()) { - - if (data->id!=MemoryPoolDynamic::INVALID_ID) - MemoryPoolDynamic::get_singleton()->free(data->id); - MemoryPoolStatic::get_singleton()->free(data); - } - - data=NULL; - } void ref(Data *p_data) { @@ -95,49 +88,13 @@ friend class MID_Lock; return NULL; } - Error _resize(size_t p_size) { - - if (p_size==0 && (!data || data->id==MemoryPoolDynamic::INVALID_ID)) - return OK; - if (p_size && !data) { - // create data because we'll need it - data = (Data*)MemoryPoolStatic::get_singleton()->alloc(sizeof(Data),"MID::Data"); - ERR_FAIL_COND_V( !data,ERR_OUT_OF_MEMORY ); - data->refcount.init(); - data->id=MemoryPoolDynamic::INVALID_ID; - } - - if (p_size==0 && data && data->id==MemoryPoolDynamic::INVALID_ID) { - - MemoryPoolDynamic::get_singleton()->free(data->id); - data->id=MemoryPoolDynamic::INVALID_ID; - } - - if (p_size>0) { - - if (data->id==MemoryPoolDynamic::INVALID_ID) { - data->id=MemoryPoolDynamic::get_singleton()->alloc(p_size,"Unnamed MID"); - ERR_FAIL_COND_V( data->id==MemoryPoolDynamic::INVALID_ID, ERR_OUT_OF_MEMORY ); + void unref(); + Error _resize(size_t p_size); - } else { - - MemoryPoolDynamic::get_singleton()->realloc(data->id,p_size); - ERR_FAIL_COND_V( data->id==MemoryPoolDynamic::INVALID_ID, ERR_OUT_OF_MEMORY ); - - } - } - - return OK; - } friend class Memory; - MID(MemoryPoolDynamic::ID p_id) { - - data = (Data*)MemoryPoolStatic::get_singleton()->alloc(sizeof(Data),"MID::Data"); - data->refcount.init(); - data->id=p_id; - } + MID(MemoryPoolDynamic::ID p_id); public: bool is_valid() const { return data; } @@ -173,15 +130,23 @@ public: class Memory{ Memory(); +#ifdef DEBUG_ENABLED + static size_t mem_usage; + static size_t max_usage; +#endif + + static size_t alloc_count; + public: - static void * alloc_static(size_t p_bytes,const char *p_descr=""); - static void * realloc_static(void *p_memory,size_t p_bytes); - static void free_static(void *p_ptr); - static size_t get_static_mem_available(); - static size_t get_static_mem_usage(); - static size_t get_static_mem_max_usage(); - static void dump_static_mem_to_file(const char* p_file); + static void * alloc_static(size_t p_bytes,bool p_pad_align=false); + static void * realloc_static(void *p_memory,size_t p_bytes,bool p_pad_align=false); + static void free_static(void *p_ptr,bool p_pad_align=false); + + static size_t get_mem_available(); + static size_t get_mem_usage(); + static size_t get_mem_max_usage(); + static MID alloc_dynamic(size_t p_bytes, const char *p_descr=""); static Error realloc_dynamic(MID p_mid,size_t p_bytes); @@ -191,15 +156,10 @@ public: }; -template<class T> -struct MemAalign { - static _FORCE_INLINE_ int get_align() { return DEFAULT_ALIGNMENT; } -}; - class DefaultAllocator { public: - _FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, ""); } - _FORCE_INLINE_ static void free(void *p_ptr) { return Memory::free_static(p_ptr); } + _FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, false); } + _FORCE_INLINE_ static void free(void *p_ptr) { return Memory::free_static(p_ptr,false); } }; @@ -209,19 +169,10 @@ void * operator new(size_t p_size,void* (*p_allocfunc)(size_t p_size)); ///< ope void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory -#ifdef DEBUG_MEMORY_ENABLED - -#define memalloc(m_size) Memory::alloc_static(m_size, __FILE__ ":" __STR(__LINE__) ", memalloc.") -#define memrealloc(m_mem,m_size) Memory::realloc_static(m_mem,m_size) -#define memfree(m_size) Memory::free_static(m_size) - -#else - #define memalloc(m_size) Memory::alloc_static(m_size) #define memrealloc(m_mem,m_size) Memory::realloc_static(m_mem,m_size) #define memfree(m_size) Memory::free_static(m_size) -#endif #ifdef DEBUG_MEMORY_ENABLED #define dynalloc(m_size) Memory::alloc_dynamic(m_size, __FILE__ ":" __STR(__LINE__) ", type: DYNAMIC") @@ -245,16 +196,8 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { return p_obj; } -#ifdef DEBUG_MEMORY_ENABLED - -#define memnew(m_class) _post_initialize(new(__FILE__ ":" __STR(__LINE__) ", memnew type: " __STR(m_class)) m_class) - -#else - #define memnew(m_class) _post_initialize(new("") m_class) -#endif - _ALWAYS_INLINE_ void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_description) { // void *failptr=0; // ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */ @@ -275,7 +218,7 @@ void memdelete(T *p_class) { if (!predelete_handler(p_class)) return; // doesn't want to be deleted p_class->~T(); - Memory::free_static(p_class); + Memory::free_static(p_class,false); } template<class T,class A> @@ -288,15 +231,9 @@ void memdelete_allocator(T *p_class) { } #define memdelete_notnull(m_v) { if (m_v) memdelete(m_v); } -#ifdef DEBUG_MEMORY_ENABLED - -#define memnew_arr( m_class, m_count ) memnew_arr_template<m_class>(m_count,__FILE__ ":" __STR(__LINE__) ", memnew_arr type: " _STR(m_class)) - -#else #define memnew_arr( m_class, m_count ) memnew_arr_template<m_class>(m_count) -#endif template<typename T> T* memnew_arr_template(size_t p_elements,const char *p_descr="") { @@ -307,11 +244,11 @@ T* memnew_arr_template(size_t p_elements,const char *p_descr="") { same strategy used by std::vector, and the DVector class, so it should be safe.*/ size_t len = sizeof(T) * p_elements; - unsigned int *mem = (unsigned int*)Memory::alloc_static( len + MAX(sizeof(size_t), DEFAULT_ALIGNMENT), p_descr ); + uint64_t *mem = (uint64_t*)Memory::alloc_static( len , true ); T *failptr=0; //get rid of a warning ERR_FAIL_COND_V( !mem, failptr ); - *mem=p_elements; - mem = (unsigned int *)( ((uint8_t*)mem) + MAX(sizeof(size_t), DEFAULT_ALIGNMENT)); + *(mem-1)=p_elements; + T* elems = (T*)mem; /* call operator new */ @@ -330,20 +267,22 @@ T* memnew_arr_template(size_t p_elements,const char *p_descr="") { template<typename T> size_t memarr_len(const T *p_class) { - uint8_t* ptr = ((uint8_t*)p_class) - MAX(sizeof(size_t), DEFAULT_ALIGNMENT); - return *(size_t*)ptr; + uint64_t* ptr = (uint64_t*)p_class; + return *(ptr-1); } template<typename T> void memdelete_arr(T *p_class) { - unsigned int * elems = (unsigned int*)(((uint8_t*)p_class) - MAX(sizeof(size_t), DEFAULT_ALIGNMENT)); + uint64_t* ptr = (uint64_t*)p_class; + + uint64_t elem_count = *(ptr-1); - for (unsigned int i=0;i<*elems;i++) { + for (uint64_t i=0;i<elem_count;i++) { p_class[i].~T(); }; - Memory::free_static(elems); + Memory::free_static(ptr,true); } diff --git a/core/os/memory_pool_dynamic_static.cpp b/core/os/memory_pool_dynamic_static.cpp index 9db4916cbd..b7a1bbc19f 100644 --- a/core/os/memory_pool_dynamic_static.cpp +++ b/core/os/memory_pool_dynamic_static.cpp @@ -221,7 +221,7 @@ Error MemoryPoolDynamicStatic::unlock(ID p_id) { size_t MemoryPoolDynamicStatic::get_available_mem() const { - return Memory::get_static_mem_available(); + return Memory::get_mem_available(); } size_t MemoryPoolDynamicStatic::get_total_usage() const { diff --git a/core/os/memory_pool_dynamic_static.h b/core/os/memory_pool_dynamic_static.h index 85c969174a..a72d39355c 100644 --- a/core/os/memory_pool_dynamic_static.h +++ b/core/os/memory_pool_dynamic_static.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/os/memory_pool_static.cpp b/core/os/memory_pool_static.cpp deleted file mode 100644 index bd2ca1436f..0000000000 --- a/core/os/memory_pool_static.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************/ -/* memory_pool_static.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "memory_pool_static.h" - -MemoryPoolStatic *MemoryPoolStatic::singleton=0; - -MemoryPoolStatic *MemoryPoolStatic::get_singleton() { - - return singleton; -} - - -MemoryPoolStatic::MemoryPoolStatic() { - - singleton=this; -} - - -MemoryPoolStatic::~MemoryPoolStatic() { - singleton=NULL; -} - - diff --git a/core/os/memory_pool_static.h b/core/os/memory_pool_static.h deleted file mode 100644 index 634d3eda60..0000000000 --- a/core/os/memory_pool_static.h +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************/ -/* memory_pool_static.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef MEMORY_POOL_STATIC_H -#define MEMORY_POOL_STATIC_H - -#include <stddef.h> - -#include "core/typedefs.h" - -/** - @author Juan Linietsky <red@lunatea> -*/ -class MemoryPoolStatic { -private: - - static MemoryPoolStatic *singleton; - -public: - - static MemoryPoolStatic *get_singleton(); - - virtual void* alloc(size_t p_bytes,const char *p_description)=0; ///< Pointer in p_description shold be to a const char const like "hello" - virtual void* realloc(void * p_memory,size_t p_bytes)=0; ///< Pointer in p_description shold be to a const char const like "hello" - virtual void free(void *p_ptr)=0; ///< Pointer in p_description shold be to a const char const - - virtual size_t get_available_mem() const=0; - virtual size_t get_total_usage()=0; - virtual size_t get_max_usage()=0; - - /* Most likely available only if memory debugger was compiled in */ - virtual int get_alloc_count()=0; - virtual void * get_alloc_ptr(int p_alloc_idx)=0; - virtual const char* get_alloc_description(int p_alloc_idx)=0; - virtual size_t get_alloc_size(int p_alloc_idx)=0; - - virtual void dump_mem_to_file(const char* p_file)=0; - - MemoryPoolStatic(); - virtual ~MemoryPoolStatic(); - -}; - -#endif diff --git a/core/os/os.cpp b/core/os/os.cpp index 75773a9076..7333d667db 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -187,7 +187,7 @@ const char *OS::get_last_error() const { void OS::dump_memory_to_file(const char* p_file) { - Memory::dump_static_mem_to_file(p_file); +// Memory::dump_static_mem_to_file(p_file); } static FileAccess *_OSPRF=NULL; @@ -367,7 +367,7 @@ Error OS::dialog_input_text(String p_title, String p_description, String p_parti int OS::get_static_memory_usage() const { - return Memory::get_static_mem_usage(); + return Memory::get_mem_usage(); } int OS::get_dynamic_memory_usage() const{ @@ -376,7 +376,7 @@ int OS::get_dynamic_memory_usage() const{ int OS::get_static_memory_peak_usage() const { - return Memory::get_static_mem_max_usage(); + return Memory::get_mem_max_usage(); } Error OS::set_cwd(const String& p_cwd) { @@ -392,7 +392,7 @@ bool OS::has_touchscreen_ui_hint() const { int OS::get_free_static_memory() const { - return Memory::get_static_mem_available(); + return Memory::get_mem_available(); } void OS::yield() { diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index 00351890c7..e425218060 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -604,7 +604,7 @@ void PoolAllocator::create_pool(void * p_mem,int p_size,int p_max_entries) { PoolAllocator::PoolAllocator(int p_size,bool p_needs_locking,int p_max_entries) { - mem_ptr=Memory::alloc_static( p_size,"PoolAllocator()"); + mem_ptr=memalloc( p_size); ERR_FAIL_COND(!mem_ptr); align=1; create_pool(mem_ptr,p_size,p_max_entries); @@ -648,7 +648,7 @@ PoolAllocator::PoolAllocator(int p_align,int p_size,bool p_needs_locking,int p_m PoolAllocator::~PoolAllocator() { if (mem_ptr) - Memory::free_static( mem_ptr ); + memfree( mem_ptr ); memdelete_arr( entry_array ); memdelete_arr( entry_indices ); diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp index de6b688b8a..f0d4fbd610 100644 --- a/core/safe_refcount.cpp +++ b/core/safe_refcount.cpp @@ -29,27 +29,76 @@ #include "safe_refcount.h" +// Atomic functions, these are used for multithread safe reference counters! + +#ifdef NO_THREADS + + +uint32_t atomic_conditional_increment( register uint32_t * pw ) { + + if (*pw==0) + return 0; + + (*pw)++; + + return *pw; +} + +uint32_t atomic_decrement( register uint32_t * pw ) { + + (*pw)--; + + return *pw; + +} + +#else + #ifdef _MSC_VER // don't pollute my namespace! #include <windows.h> -long atomic_conditional_increment( register long * pw ) { +uint32_t atomic_conditional_increment( register uint32_t * pw ) { /* try to increment until it actually works */ // taken from boost while (true) { - long tmp = static_cast< long const volatile& >( *pw ); + uint32_t tmp = static_cast< uint32_t const volatile& >( *pw ); if( tmp == 0 ) - return 0; // if zero, can't add to it anymore - if( InterlockedCompareExchange( pw, tmp + 1, tmp ) == tmp ) + return 0; // if zero, can't add to it anymore + if( InterlockedCompareExchange( (LONG volatile*)pw, tmp + 1, tmp ) == tmp ) return tmp+1; } +} + +uint32_t atomic_decrement( register uint32_t * pw ) { + return InterlockedDecrement( (LONG volatile*)pw ); +} + +#elif defined(__GNUC__) +uint32_t atomic_conditional_increment( register uint32_t * pw ) { + + while (true) { + uint32_t tmp = static_cast< uint32_t const volatile& >( *pw ); + if( tmp == 0 ) + return 0; // if zero, can't add to it anymore + if( __sync_val_compare_and_swap( pw, tmp, tmp + 1 ) == tmp ) + return tmp+1; + } } -long atomic_decrement( register long * pw ) { - return InterlockedDecrement( pw ); +uint32_t atomic_decrement( register uint32_t * pw ) { + + return __sync_sub_and_fetch(pw,1); + } +#else + //no threads supported? +#error Must provide atomic functions for this platform or compiler! + +#endif + #endif diff --git a/core/safe_refcount.h b/core/safe_refcount.h index 5bb2a4564b..08bea9d244 100644 --- a/core/safe_refcount.h +++ b/core/safe_refcount.h @@ -33,309 +33,17 @@ /* x86/x86_64 GCC */ #include "platform_config.h" +#include "typedefs.h" -#ifdef NO_THREADS - -struct SafeRefCount { - - int count; - -public: - - // destroy() is called when weak_count_ drops to zero. - - bool ref() { //true on success - - if (count==0) - return false; - count++; - - return true; - } - - int refval() { //true on success - - if (count==0) - return 0; - count++; - return count; - } - - bool unref() { // true if must be disposed of - - if (count>0) - count--; - - return count==0; - } - - long get() const { // nothrow - - return static_cast<int const volatile &>( count ); - } - - void init(int p_value=1) { - - count=p_value; - }; - -}; - - - - - - - - -#else - -#if defined( PLATFORM_REFCOUNT ) - -#include "platform_refcount.h" - - -#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) - -#define REFCOUNT_T volatile int -#define REFCOUNT_GET_T int const volatile& - -static inline int atomic_conditional_increment( volatile int * pw ) { - // int rv = *pw; - // if( rv != 0 ) ++*pw; - // return rv; - - int rv, tmp; - - __asm__ - ( - "movl %0, %%eax\n\t" - "0:\n\t" - "test %%eax, %%eax\n\t" - "je 1f\n\t" - "movl %%eax, %2\n\t" - "incl %2\n\t" - "lock\n\t" - "cmpxchgl %2, %0\n\t" - "jne 0b\n\t" - "1:": - "=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2) - "m"( *pw ): // input (%3) - "cc" // clobbers - ); - - return rv; -} - -static inline int atomic_decrement( volatile int *pw) { - - // return --(*pw); - - unsigned char rv; - - __asm__ - ( - "lock\n\t" - "decl %0\n\t" - "setne %1": - "=m" (*pw), "=qm" (rv): - "m" (*pw): - "memory" - ); - return static_cast<int>(rv); -} - -/* PowerPC32/64 GCC */ - -#elif ( defined( __GNUC__ ) ) && ( defined( __powerpc__ ) || defined( __ppc__ ) ) - -#define REFCOUNT_T int -#define REFCOUNT_GET_T int const volatile& - -inline int atomic_conditional_increment( int * pw ) -{ - // if( *pw != 0 ) ++*pw; - // return *pw; - - int rv; - - __asm__ - ( - "0:\n\t" - "lwarx %1, 0, %2\n\t" - "cmpwi %1, 0\n\t" - "beq 1f\n\t" - "addi %1, %1, 1\n\t" - "1:\n\t" - "stwcx. %1, 0, %2\n\t" - "bne- 0b": - - "=m"( *pw ), "=&b"( rv ): - "r"( pw ), "m"( *pw ): - "cc" - ); - - return rv; -} - - -inline int atomic_decrement( int * pw ) -{ - // return --*pw; - - int rv; - - __asm__ __volatile__ - ( - "sync\n\t" - "0:\n\t" - "lwarx %1, 0, %2\n\t" - "addi %1, %1, -1\n\t" - "stwcx. %1, 0, %2\n\t" - "bne- 0b\n\t" - "isync": - - "=m"( *pw ), "=&b"( rv ): - "r"( pw ), "m"( *pw ): - "memory", "cc" - ); - - return rv; -} - -/* CW ARM */ - -#elif defined( __GNUC__ ) && ( defined( __arm__ ) ) - -#define REFCOUNT_T int -#define REFCOUNT_GET_T int const volatile& - -inline int atomic_conditional_increment(volatile int* v) -{ - int t; - int tmp; - - __asm__ __volatile__( - "1: ldrex %0, [%2] \n" - " cmp %0, #0 \n" - " beq 2f \n" - " add %0, %0, #1 \n" - "2: \n" - " strex %1, %0, [%2] \n" - " cmp %1, #0 \n" - " bne 1b \n" - - : "=&r" (t), "=&r" (tmp) - : "r" (v) - : "cc", "memory"); - - return t; -} - - -inline int atomic_decrement(volatile int* v) -{ - int t; - int tmp; - - __asm__ __volatile__( - "1: ldrex %0, [%2] \n" - " add %0, %0, #-1 \n" - " strex %1, %0, [%2] \n" - " cmp %1, #0 \n" - " bne 1b \n" - - : "=&r" (t), "=&r" (tmp) - : "r" (v) - : "cc", "memory"); - - return t; -} - - - -/* CW PPC */ - -#elif ( defined( __MWERKS__ ) ) && defined( __POWERPC__ ) - -inline long atomic_conditional_increment( register long * pw ) -{ - register int a; - - asm - { - loop: - - lwarx a, 0, pw - cmpwi a, 0 - beq store - - addi a, a, 1 - - store: - - stwcx. a, 0, pw - bne- loop - } - - return a; -} - - -inline long atomic_decrement( register long * pw ) -{ - register int a; - - asm { - - sync - - loop: - - lwarx a, 0, pw - addi a, a, -1 - stwcx. a, 0, pw - bne- loop - - isync - } - - return a; -} - -/* Any Windows (MSVC) */ - -#elif defined( _MSC_VER ) - -// made functions to not pollute namespace.. - -#define REFCOUNT_T long -#define REFCOUNT_GET_T long const volatile& - -long atomic_conditional_increment( register long * pw ); -long atomic_decrement( register long * pw ); - -#if 0 -#elif defined( __GNUC__ ) && defined( ARMV6_ENABLED) - - -#endif - - - - -#else - -#error This platform cannot use safe refcount, compile with NO_THREADS or implement it. - -#endif +uint32_t atomic_conditional_increment( register uint32_t * counter ); +uint32_t atomic_decrement( register uint32_t * pw ); struct SafeRefCount { - REFCOUNT_T count; + uint32_t count; public: @@ -346,7 +54,7 @@ public: return atomic_conditional_increment( &count ) != 0; } - int refval() { //true on success + uint32_t refval() { //true on success return atomic_conditional_increment( &count ); } @@ -360,20 +68,18 @@ public: return false; } - long get() const { // nothrow + uint32_t get() const { // nothrow - return static_cast<REFCOUNT_GET_T>( count ); + return count; } - void init(int p_value=1) { + void init(uint32_t p_value=1) { count=p_value; - }; + } }; -#endif // no thread safe - #endif diff --git a/core/typedefs.h b/core/typedefs.h index b24f259cc6..176c77570d 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -77,10 +77,6 @@ #endif -#ifndef DEFAULT_ALIGNMENT -#define DEFAULT_ALIGNMENT 1 -#endif - //custom, gcc-safe offsetof, because gcc complains a lot. template<class T> diff --git a/core/vector.h b/core/vector.h index 8113099a61..3227561000 100644 --- a/core/vector.h +++ b/core/vector.h @@ -46,19 +46,20 @@ class Vector { // internal helpers - _FORCE_INLINE_ SafeRefCount* _get_refcount() const { + _FORCE_INLINE_ uint32_t* _get_refcount() const { if (!_ptr) return NULL; - return reinterpret_cast<SafeRefCount*>((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount)); + return reinterpret_cast<uint32_t*>(_ptr)-2; } - _FORCE_INLINE_ int* _get_size() const { + _FORCE_INLINE_ uint32_t* _get_size() const { if (!_ptr) - return NULL; - return reinterpret_cast<int*>((uint8_t*)_ptr-sizeof(int)); + return NULL; + + return reinterpret_cast<uint32_t*>(_ptr)-1; } _FORCE_INLINE_ T* _get_data() const { @@ -71,7 +72,7 @@ class Vector { _FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { //return nearest_power_of_2_templated(p_elements*sizeof(T)+sizeof(SafeRefCount)+sizeof(int)); - return nearest_power_of_2(p_elements*sizeof(T)+sizeof(SafeRefCount)+sizeof(int)); + return nearest_power_of_2(p_elements*sizeof(T)); } _FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const { @@ -79,8 +80,8 @@ class Vector { size_t o; size_t p; if (_mul_overflow(p_elements, sizeof(T), &o)) return false; - if (_add_overflow(o, sizeof(SafeRefCount)+sizeof(int), &p)) return false; - *out = nearest_power_of_2(p); + *out = nearest_power_of_2(o); + if (_add_overflow(o, 32, &p)) return false; //no longer allocated here return true; #else // Speed is more important than correctness here, do the operations unchecked @@ -104,7 +105,7 @@ public: _FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ int size() const { - int* size = _get_size(); + uint32_t* size = (uint32_t*)_get_size(); if (size) return *size; else @@ -190,22 +191,22 @@ void Vector<T>::_unref(void *p_data) { if (!p_data) return; - SafeRefCount *src = reinterpret_cast<SafeRefCount*>((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount)); + uint32_t *refc = _get_refcount(); - if (!src->unref()) + if (atomic_decrement(refc)>0) return; // still in use // clean up - int *count = (int*)(src+1); + uint32_t *count = _get_size(); T *data = (T*)(count+1); - for (int i=0;i<*count;i++) { + for (uint32_t i=0;i<*count;i++) { // call destructors data[i].~T(); } // free mem - memfree((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount)); + Memory::free_static((uint8_t*)p_data,true); } @@ -215,18 +216,22 @@ void Vector<T>::_copy_on_write() { if (!_ptr) return; - if (_get_refcount()->get() > 1 ) { + uint32_t *refc = _get_refcount(); + + if (*refc > 1) { /* in use by more than me */ - void* mem_new = memalloc(_get_alloc_size(*_get_size())); - SafeRefCount *src_new=(SafeRefCount *)mem_new; - src_new->init(); - int * _size = (int*)(src_new+1); - *_size=*_get_size(); + uint32_t current_size = *_get_size(); + + uint32_t* mem_new = (uint32_t*)Memory::alloc_static(_get_alloc_size(current_size),true); - T*_data=(T*)(_size+1); + + *(mem_new-2)=1; //refcount + *(mem_new-1)=current_size; //size + + T*_data=(T*)(mem_new); // initialize new elements - for (int i=0;i<*_size;i++) { + for (uint32_t i=0;i<current_size;i++) { memnew_placement(&_data[i], T( _get_data()[i] ) ); } @@ -280,16 +285,17 @@ Error Vector<T>::resize(int p_size) { if (size()==0) { // alloc from scratch - void* ptr=memalloc(alloc_size); + uint32_t *ptr=(uint32_t*)Memory::alloc_static(alloc_size,true); ERR_FAIL_COND_V( !ptr ,ERR_OUT_OF_MEMORY); - _ptr=(T*)((uint8_t*)ptr+sizeof(int)+sizeof(SafeRefCount)); - _get_refcount()->init(); // init refcount - *_get_size()=0; // init size (currently, none) + *(ptr-1)=0; //size, currently none + *(ptr-2)=1; //refcount + + _ptr=(T*)ptr; } else { - void *_ptrnew = (T*)memrealloc((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount), alloc_size); + void *_ptrnew = (T*)Memory::realloc_static(_ptr, alloc_size,true); ERR_FAIL_COND_V( !_ptrnew ,ERR_OUT_OF_MEMORY); - _ptr=(T*)((uint8_t*)_ptrnew+sizeof(int)+sizeof(SafeRefCount)); + _ptr=(T*)(_ptrnew); } // construct the newly created elements @@ -305,16 +311,16 @@ Error Vector<T>::resize(int p_size) { } else if (p_size<size()) { // deinitialize no longer needed elements - for (int i=p_size;i<*_get_size();i++) { + for (uint32_t i=p_size;i<*_get_size();i++) { T* t = &_get_data()[i]; t->~T(); } - void *_ptrnew = (T*)memrealloc((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount), alloc_size); + void *_ptrnew = (T*)Memory::realloc_static(_ptr, alloc_size,true); ERR_FAIL_COND_V( !_ptrnew ,ERR_OUT_OF_MEMORY); - _ptr=(T*)((uint8_t*)_ptrnew+sizeof(int)+sizeof(SafeRefCount)); + _ptr=(T*)(_ptrnew); *_get_size()=p_size; @@ -382,8 +388,9 @@ void Vector<T>::_copy_from(const Vector& p_from) { if (!p_from._ptr) return; //nothing to do - if (p_from._get_refcount()->ref()) // could reference + if (atomic_conditional_increment(p_from._get_refcount())>0) { // could reference _ptr=p_from._ptr; + } } |