/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- new
- new
- delete
- new
- MMgcConstructTaggedArray
- MMgcDestructTaggedScalarChecked
- MMgcDestructTaggedArrayChecked
- DECLARE_PRIM_ARRAY
- DECLARE_PRIM_ARRAY_DELETE
- new
- delete
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GCGLOBALNEW__
#define __GCGLOBALNEW__
#ifdef MMGC_ENABLE_CPP_EXCEPTIONS
#define MMGC_NEW_THROWS_CLAUSE throw (std::bad_alloc)
#define MMGC_DELETE_THROWS_CLAUSE throw ()
#else
#define MMGC_NEW_THROWS_CLAUSE
#define MMGC_DELETE_THROWS_CLAUSE
#endif
namespace MMgc
{
#ifdef MMGC_USE_SYSTEM_MALLOC
/**
* Allocate memory from the system heap using VMPI_alloc, with options.
*
* @param size the size in bytes of the request
* @param opts an options bit vector
*
* @return A pointer to a suitable memory area. NULL only if kCanFail is part of
* opts. The memory is zeroed only of kZero is part of opts.
*
* @note If memory cannot be allocated and kCanFail is not part of opts then the regular
* OOM handling is run, in the hope that this will free some memory on the system
* heap as well. If memory is not available on a second allocation attempt then
* the system will enter the abort state.
*/
void *SystemNew(size_t size, FixedMallocOpts opts);
/**
* Free memory allocated with SystemNew. p may be NULL.
*/
void SystemDelete(void* p);
#endif
/**
* Simply an abstraction around a lower-level allocator: no headers, no tagging.
* @return NULL only if ((opts & kCanFail) != 0), zeroed memory only if ((opts & kZero) != 0).
*/
REALLY_INLINE void *AllocCallInline(size_t size, FixedMallocOpts opts=kNone)
{
#ifdef MMGC_USE_SYSTEM_MALLOC
return SystemNew(size, opts);
#else
return FixedMalloc::GetFixedMalloc()->OutOfLineAlloc(size, opts);
#endif
}
/**
* Out-of-line implementation of AllocCallInline.
*/
void *AllocCall(size_t, FixedMallocOpts opts=kNone);
/**
* Simply an abstraction around a lower-level deallocator, for objects allocated
* by AllocCallInline / AllocCall (no headers, no tagging).
*
* @param p The object to be deallocated. May be NULL.
*/
REALLY_INLINE void DeleteCallInline(void *p)
{
#ifdef MMGC_USE_SYSTEM_MALLOC
SystemDelete(p);
#else
FixedMalloc::GetFixedMalloc()->OutOfLineFree(p);
#endif
}
/**
* Out-of-line implementation of DeleteCallInline.
*/
void DeleteCall(void *);
};
#ifdef MMGC_OVERRIDE_GLOBAL_NEW
// Global operator new and delete implementations to allocate/free from FixedMalloc.
// Using these may create a problem if compiled with system (OS) headers that also use the default
// new & delete. This happens for example in ATL of the Windows ActiveX builds. Also, out of memory
// handling will release everything allocated with FixedMalloc when abort due to OOM occurs. If
// things in the system headers/plugin interface/platform globals are allocated with these, it will
// result most likely in a crash. By using the GCAllocObject you can try to go around some of these
// issues, but atleast to system headers may pose a problem.
// User-defined operator new.
REALLY_INLINE void *operator new(size_t size) MMGC_NEW_THROWS_CLAUSE
{
return MMgc::AllocCallInline(size);
}
REALLY_INLINE void *operator new(size_t size, MMgc::FixedMallocOpts opts) MMGC_NEW_THROWS_CLAUSE
{
return MMgc::AllocCallInline(size, opts);
}
REALLY_INLINE void *operator new[](size_t size) MMGC_NEW_THROWS_CLAUSE
{
return MMgc::AllocCallInline(size);
}
REALLY_INLINE void *operator new[](size_t size, MMgc::FixedMallocOpts opts) MMGC_NEW_THROWS_CLAUSE
{
return MMgc::AllocCallInline(size, opts);
}
// User-defined operator delete.
REALLY_INLINE void operator delete( void *p) MMGC_DELETE_THROWS_CLAUSE
{
MMgc::DeleteCallInline(p);
}
REALLY_INLINE void operator delete[]( void *p ) MMGC_DELETE_THROWS_CLAUSE
{
MMgc::DeleteCallInline(p);
}
// map these to nothingness
#define MMGC_DECLARE_OPERATOR_DELETES_FOR_CLASS
#define MMGC_DECLARE_SPECIALIZED_DESTRUCTORCALL_TEMPLATES( TYPE )
#define MMGC_DECLARE_GLOBAL_DELETE_FNCS_AS_FRIEND( TYPE )
#define MMGC_USING_DELETE_OPERATOR( TYPE )
#else /* MMGC_OVERRIDE_GLOBAL_NEW */
// Defines allocation and deallocation functions used by allocation and deallocation macros.
// operator new and new[] have a specialized signature by having an ignored MMgc::kUseFixedMalloc parameter.
// Specialized operator delete and delete[] are provided to get rid of compiler warnings.
void* operator new(size_t size, MMgc::NewDummyOperand /*ignored*/) MMGC_NEW_THROWS_CLAUSE;
void *operator new(size_t size, MMgc::NewDummyOperand /*ignored*/, MMgc::FixedMallocOpts opts) MMGC_NEW_THROWS_CLAUSE;
// Empty deletes to get rid of warnings
// has impl for solaris (maybe solaris is generating C++ exception based delete calls?)
REALLY_INLINE void operator delete(void *, MMgc::NewDummyOperand /* ignored */) MMGC_DELETE_THROWS_CLAUSE { GCAssert(false); }
// b/c we need to use the fancy template routines for new[] these arent used
//void* operator new[](size_t size, size_t arraySize, MMgc::NewDummyOperand /*ignored*/) MMGC_NEW_THROWS_CLAUSE;
//void* operator new[](size_t size, size_t arraySize, MMgc::NewDummyOperand /*ignored*/, MMgc::FixedMallocOpts opts) NEW_THROWS_CLAUSE;
//void operator delete[](void *p, MMgc::NewDummyOperand /* ignored */) MMGC_DELETE_THROWS_CLAUSE;
// These values are '8' because some architectures (MIPS for sure, PPC probably) require
// that structures be aligned on the natural boundary for their largest element, which
// is typically a 'double', ie, 8 bytes.
#define MMGC_ARRAYHEADER_SIZE 8 // Space for array length before array
#define MMGC_GUARDCOOKIE_SIZE 8 // Space for cookie before object (precedes header)
namespace MMgc
{
/**********************************
* INTERNAL APIS
**********************************/
#ifdef MMGC_DELETE_DEBUGGING
#define mmgc_debug_only(_x) _x
#else
#define mmgc_debug_only(_x)
#endif
#ifdef MMGC_DELETE_DEBUGGING
// Verify that p points to an object allocated by NewTaggedScalar.
void VerifyTaggedScalar(void* p);
// Verify that p points to an object allocated by NewTaggedArray.
void VerifyTaggedArray(void* p, bool primitive);
#endif
/**
* Allocate space for a scalar, with error checking (in debug builds).
* The operators new are defined in GCGlobalNew.cpp; they inline NewTaggedScalar as
* their entire function body, so NewTaggedScalar defines the semantics of 'new'.
*
* @param size The size in bytes of the object
* @param opts A bit vector of the usual MMgc options (kCanFail, kZero).
*
* @return A pointer to the object. Returns NULL only if ((opts & kCanFail) != 0)
* and the object can't be allocated due to an out-of-memory condition or
* if the object would exceed the maximum object size.
*
* In debug builds, this tags the memory, and the untagging call
*/
void* NewTaggedScalar(size_t size, FixedMallocOpts opts=kNone);
/**
* Allocate space for an array, with error checking (in debug builds).
*
* @param count The number of array elements
* @param elsize The size in bytes of each array element
* @param opts A bit vector of the usual MMgc options (kCanFail, kZero).
* @param isPrimitive A flag indicating whether the array needs a header storing
* the value of count: if false, the header is created and
* the value of count is stored; if true, it is not.
*
* @return A pointer to element 0 of the array. Returns NULL only if ((opts & kCanFail) != 0)
* and the object can't be allocated due to an out-of-memory condition or
* if the object would exceed the maximum object size.
*/
void* NewTaggedArray(size_t count, size_t elsize, FixedMallocOpts opts, bool isPrimitive);
/* Deallocate an object allocated by NewTaggedScalar. Does /not/ check the tag.
*
* @param p A non-NULL pointer returned from NewTaggedScalar.
*/
void DeleteTaggedScalar(void *);
/* Deallocate an object allocated by NewTaggedScalar after checking
* the tag (in debug builds).
*
* @param p A pointer returned from NewTaggedScalar, or NULL.
*/
void DeleteTaggedScalarChecked(void* p);
/* Deallocate an object allocated by NewTaggedArray /if/ the allocation
* call specified isPrimitive=false. Does /not/ check the tag.
*
* @param p A non-NULL pointer returned from NewTaggedArray with isPrimitive=false.
*/
void DeleteTaggedArrayWithHeader(void *);
/* Delete an object allocated by NewTaggedVecor /if/ the allocation
* call specified isPrimitive=true, after checking the tag (in debug builds).
*
* @param p A pointer returned from NewTaggedArray with isPrimitive=false, or NULL.
*/
void DeleteTaggedArrayWithHeaderChecked(void* p, bool primitive);
};
template <class T>
T *MMgcConstructTaggedArray(T* /*dummy template arg*/, size_t count, MMgc::FixedMallocOpts opts)
{
T *mem = (T*) MMgc::NewTaggedArray(count, sizeof(T), opts, false /* !isPrimitive */);
T *tp = mem;
for(size_t i=count; i>0; i--, tp++)
new ((void*)tp) T;
return mem;
}
#define DECLARE_PRIM_ARRAY_NEW(_x) \
template <> REALLY_INLINE _x *MMgcConstructTaggedArray(_x*, size_t count, MMgc::FixedMallocOpts opts) \
{ \
return (_x*)MMgc::NewTaggedArray(count, sizeof(_x), opts, true /* isPrimitive */); \
}
// Scalar delete mechanism. First calls the destructor and then deletefunc to release the memory.
template <typename T> REALLY_INLINE void MMgcDestructTaggedScalarChecked( T* mem )
{
if( mem )
{
mmgc_debug_only(MMgc::VerifyTaggedScalar(mem);)
// Call destructor first and then release memory
mem->~T();
MMgc::DeleteTaggedScalar( mem );
}
}
// Array delete mechanism
template <typename T> REALLY_INLINE void MMgcDestructTaggedArrayChecked( T* mem )
{
if( mem )
{
mmgc_debug_only(MMgc::VerifyTaggedArray(mem, false);)
char *p = (char*)mem - MMGC_ARRAYHEADER_SIZE;
size_t count = *(size_t*)(void*)p;
T* tail = mem + count;
while ( tail > mem )
{
tail--;
tail->~T();
}
MMgc::DeleteTaggedArrayWithHeader( mem );
}
}
#define DECLARE_PRIM_ARRAY_DELETE(_x) \
template <> REALLY_INLINE void MMgcDestructTaggedArrayChecked( _x* mem ) \
{ \
MMgc::DeleteTaggedArrayWithHeaderChecked( mem, true ); \
} \
\
template <> REALLY_INLINE void MMgcDestructTaggedScalarChecked(_x *mem) { \
MMgc::DeleteTaggedScalarChecked(mem); \
}
#define DECLARE_PRIM_ARRAY(_x) \
DECLARE_PRIM_ARRAY_NEW(_x) \
DECLARE_PRIM_ARRAY_DELETE(_x) \
// Specialized function templates, for built-in types so that we
// don't call destructor and add extra overhead.
DECLARE_PRIM_ARRAY(uint8_t)
DECLARE_PRIM_ARRAY(int8_t)
#ifdef __GNUC__
// msvc correctly treats char and (u)int8_t as the same but gcc doesn't
DECLARE_PRIM_ARRAY(char)
#endif
DECLARE_PRIM_ARRAY(uint16_t)
DECLARE_PRIM_ARRAY(int16_t)
DECLARE_PRIM_ARRAY(uint32_t)
DECLARE_PRIM_ARRAY(int32_t)
DECLARE_PRIM_ARRAY(uint64_t)
DECLARE_PRIM_ARRAY(int64_t)
DECLARE_PRIM_ARRAY(float)
DECLARE_PRIM_ARRAY(double)
DECLARE_PRIM_ARRAY(void*)
DECLARE_PRIM_ARRAY(void**)
template <> REALLY_INLINE void *MMgcConstructTaggedArray(void*, size_t count, MMgc::FixedMallocOpts opts)
{
return (void*)MMgc::NewTaggedArray(count, sizeof(void*), opts, true /* isPrimitive */);
}
DECLARE_PRIM_ARRAY_DELETE(void)
#undef DECLARE_PRIM_ARRAY_NEW
#undef DECLARE_PRIM_ARRAY_DELETE
#undef DECLARE_PRIM_ARRAY
#ifdef __GNUC__
// G++ pukes on the ::, MSC requires them
// If a class has private destructor adding this macro will allow the delete mechanisms to call that.
#define MMGC_DECLARE_GLOBAL_DELETE_FNCS_AS_FRIEND( TYPE ) \
friend void MMgcDestructTaggedScalarChecked<>( TYPE* ); \
friend void MMgcDestructTaggedArrayChecked<>( TYPE* );
#else
// If a class has private destructor adding this macro will allow the delete mechanisms to call that.
#define MMGC_DECLARE_GLOBAL_DELETE_FNCS_AS_FRIEND( TYPE ) \
friend void ::MMgcDestructTaggedScalarChecked<>( TYPE* ); \
friend void ::MMgcDestructTaggedArrayChecked<>( TYPE* );
#endif
// this is necessary for the friend calls above to resolve properly w GCC
//using namespace MMgc;
// If a class is a base class for multiple inheritance or virtual inheritance, it may need to define
// these macros (MMGC_DECLARE_OPERATOR_DELETES_FOR_CLASS) inside the class definition to create a class specific delete,
// and MMGC_DECLARE_SPECIALIZED_DESTRUCTORCALL_TEMPLATES outside the class definition to have specialized function
// template for the destructor.
// This is done in cases where the pointer to be destructed is actually the pointer of a non-first base class.
#define MMGC_DECLARE_SPECIALIZED_DESTRUCTORCALL_TEMPLATES( TYPE ) \
MMGC_DECLARE_SPECIALIZED_DESTRUCTORCALL_TEMPLATE( TYPE ) \
MMGC_DECLARE_SPECIALIZED_DESTRUCTORARRAYCALL_TEMPLATE( TYPE )
#define MMGC_DECLARE_SPECIALIZED_DESTRUCTORCALL_TEMPLATE( TYPE ) \
template <> REALLY_INLINE void MMgcDestructTaggedScalarChecked( TYPE* mem ) { if(mem) delete mem; }
#define MMGC_DECLARE_SPECIALIZED_DESTRUCTORARRAYCALL_TEMPLATE( TYPE ) \
template <> REALLY_INLINE void MMgcDestructTaggedArrayChecked( TYPE* mem ) { if(mem) delete[] mem; }
// These dont need to call destructors as the operator delete will do that automatically for us.
#define MMGC_DECLARE_OPERATOR_DELETES_FOR_CLASS \
MMGC_DECLARE_SCALAR_DELETE_FOR_CLASS \
MMGC_DECLARE_VECTOR_DELETE_FOR_CLASS
#define MMGC_DECLARE_SCALAR_DELETE_FOR_CLASS \
void operator delete(void* p) { MMgc::DeleteTaggedScalarChecked(p); }
#define MMGC_DECLARE_VECTOR_DELETE_FOR_CLASS \
void operator delete[](void* p) { MMgc::DeleteTaggedArrayWithHeaderChecked(p, false); }
// If a class derives from multiple baseclasses that define delete operator, this can be used to
// select with one to use.
#define MMGC_USING_DELETE_OPERATOR( TYPE ) \
using TYPE::operator delete
#ifndef MMGC_OVERRIDE_NEWDELETE_DEBUGGING
//#define MMGC_OVERRIDE_NEWDELETE_DEBUGGING
#endif
#ifdef MMGC_OVERRIDE_NEWDELETE_DEBUGGING
// These help to track where global operator new/delete/new[]/delete[] are used in compile time in MSVC.
// If you compile the project with /EHsc /Ob1 /W4 flags and compile. This will generate C4714 warnings
// (forceinline failed) for places where these operators are used. So far the try catch seems to be the
// way to do this, but for loops are supposed to generate that as well. May not be turned on on builds that
// are to be executed.
REALLY_INLINE void *operator new(size_t size) MMGC_NEW_THROWS_CLAUSE
{
(void)size; GCAssert(false);
/*
try
{
}
catch (...)
{
}*/
return (void*)-1;
}
REALLY_INLINE void *operator new[](size_t size) MMGC_NEW_THROWS_CLAUSE
{
(void)size;GCAssert(false);
/*
try
{
}
catch (...)
{
}*/
return (void*)-1;
}
// User-defined operator delete.
REALLY_INLINE void operator delete( void *p) MMGC_DELETE_THROWS_CLAUSE
{
(void)p;
GCAssert(false); /*
try
{
}
catch (...)
{
}*/
}
REALLY_INLINE void operator delete[]( void *p ) MMGC_DELETE_THROWS_CLAUSE
{
(void)p;
GCAssert(false);/*
try
{
}
catch (...)
{
}*/
}
#endif // MMGC_OVERRIDE_NEWDELETE_DEBUGGING
#ifndef MMGC_DELETE_DEBUGGING
namespace MMgc
{
// Debug versions of these functions are out-of-line.
REALLY_INLINE void DeleteTaggedScalar( void* p )
{
DeleteCallInline(p);
}
REALLY_INLINE void DeleteTaggedArrayWithHeader( void* p )
{
if( p )
{
p = ((char*)p - MMGC_ARRAYHEADER_SIZE);
DeleteCallInline(p);
}
}
REALLY_INLINE void DeleteTaggedScalarChecked(void* p)
{
if( p )
{
DeleteTaggedScalar( p );
}
}
REALLY_INLINE void DeleteTaggedArrayWithHeaderChecked(void* p, bool primitive)
{
(void)primitive;
if(p)
{
// not using DeleteTaggedArrayWithHeader, that's for non-Simple case with count cookie
DeleteTaggedScalar( p );
}
}
}
#endif // MMGC_DELETE_DEBUGGING
#endif /* MMGC_OVERRIDE_GLOBAL_NEW */
#endif // __GCGLOBALNEW__