581 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			581 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#ifndef HX_GC_H
							 | 
						||
| 
								 | 
							
								#define HX_GC_H
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <hx/Tls.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Under the current scheme (as defined by HX_HCSTRING/HX_CSTRING in hxcpp.h)
							 | 
						||
| 
								 | 
							
								//  each constant string data is prepended with a 4-byte header that says the string
							 | 
						||
| 
								 | 
							
								//  is constant (ie, not part of GC) and whether there is(not) a pre-computed hash at
							 | 
						||
| 
								 | 
							
								//  the end of the data.
							 | 
						||
| 
								 | 
							
								// When HX_SMART_STRINGS is active, a bit says whether it is char16_t encoded.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_GC_CONST_ALLOC_BIT  0x80000000
							 | 
						||
| 
								 | 
							
								#define HX_GC_CONST_ALLOC_MARK_BIT  0x80
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Tell compiler the extra functions are supported
							 | 
						||
| 
								 | 
							
								#define HXCPP_GC_FUNCTIONS_1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Function called by the haxe code...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_TELEMETRY
							 | 
						||
| 
								 | 
							
								extern void __hxt_gc_new(hx::StackContext *inStack, void* obj, int inSize, const char *inName);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Helpers for debugging code
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_reachable(hx::Object *inKeep);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_enable(bool inEnable);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_collect(bool inMajor=true);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void   __hxcpp_gc_compact();
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES int   __hxcpp_gc_trace(hx::Class inClass, bool inPrint);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES int   __hxcpp_gc_used_bytes();
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES double __hxcpp_gc_mem_info(int inWhat);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_enter_gc_free_zone();
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_exit_gc_free_zone();
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_gc_safe_point();
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_spam_collects(int inEveryNCalls);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_set_minimum_working_memory(int inBytes);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_set_minimum_free_space(int inBytes);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void  __hxcpp_set_target_free_space_percentage(int inPercentage);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES bool __hxcpp_is_const_string(const ::String &inString);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic _hx_gc_freeze(Dynamic inObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef void (hx::Object::*_hx_member_finalizer)(void);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void __hxcpp_add_member_finalizer(hx::Object *inObject, _hx_member_finalizer, bool inPin);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef void (*_hx_alloc_finalizer)(void *inPtr);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void __hxcpp_add_alloc_finalizer(void *inAlloc, _hx_alloc_finalizer, bool inPin);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								inline void _hx_add_finalizable( hx::ObjectPtr<T> inObj, bool inPin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  _hx_member_finalizer finalizer = (_hx_member_finalizer)&T::finalize;
							 | 
						||
| 
								 | 
							
								  __hxcpp_add_member_finalizer(inObj.mPtr, finalizer, inPin);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								inline void _hx_add_finalizable( T *inObj, bool inPin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  _hx_member_finalizer finalizer = (_hx_member_finalizer)&T::finalize;
							 | 
						||
| 
								 | 
							
								  __hxcpp_add_member_finalizer(inObj, finalizer, inPin);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								T _hx_allocate_extended(int inExtra)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   typedef typename T::Obj Obj;
							 | 
						||
| 
								 | 
							
								   Obj *obj = new (inExtra) Obj();
							 | 
						||
| 
								 | 
							
								   return obj;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								inline void _hx_allocate_extended( hx::ObjectPtr<T> inObj, bool inPin)
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Finalizers from haxe code...
							 | 
						||
| 
								 | 
							
								void  __hxcpp_gc_do_not_kill(Dynamic inObj);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// This is the correctly typed version - no change of getting function proto wrong
							 | 
						||
| 
								 | 
							
								void _hx_set_finalizer(Dynamic inObj, void (*inFunc)(Dynamic) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void  __hxcpp_set_finalizer(Dynamic inObj, void *inFunction);
							 | 
						||
| 
								 | 
							
								hx::Object *__hxcpp_get_next_zombie();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_TELEMETRY
							 | 
						||
| 
								 | 
							
								void __hxcpp_set_hxt_finalizer(void* inObj, void *inFunc);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								hx::Object *__hxcpp_weak_ref_create(Dynamic inObject);
							 | 
						||
| 
								 | 
							
								hx::Object *__hxcpp_weak_ref_get(Dynamic inRef);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unsigned int __hxcpp_obj_hash(Dynamic inObj);
							 | 
						||
| 
								 | 
							
								int __hxcpp_obj_id(Dynamic inObj);
							 | 
						||
| 
								 | 
							
								hx::Object *__hxcpp_id_obj(int);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace hx
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								// Generic allocation routine.
							 | 
						||
| 
								 | 
							
								// If inSize is small (<4k) it will be allocated from the immix pool.
							 | 
						||
| 
								 | 
							
								// Larger, and it will be allocated from a separate memory pool
							 | 
						||
| 
								 | 
							
								// inIsObject specifies whether "__Mark"  should be called on the resulting object
							 | 
						||
| 
								 | 
							
								void *InternalNew(int inSize,bool inIsObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Used internall - realloc array data
							 | 
						||
| 
								 | 
							
								void *InternalRealloc(int inFromSize, void *inData,int inSize,bool inAllowExpansion=false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void InternalReleaseMem(void *inMem);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unsigned int ObjectSizeSafe(void *inData);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Const buffers are allocated outside the GC system, and do not require marking
							 | 
						||
| 
								 | 
							
								// String buffers can optionally have a pre-computed hash appended with this method
							 | 
						||
| 
								 | 
							
								void *InternalCreateConstBuffer(const void *inData,int inSize,bool inAddStringHash=false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Called after collection by an unspecified thread
							 | 
						||
| 
								 | 
							
								typedef void (*finalizer)(hx::Object *v);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Used internally by the runtime.
							 | 
						||
| 
								 | 
							
								// The constructor will add this object to the internal list of finalizers.
							 | 
						||
| 
								 | 
							
								// If the parent object is not marked by the end of the collect, the finalizer will trigger.
							 | 
						||
| 
								 | 
							
								struct InternalFinalizer
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   InternalFinalizer(hx::Object *inObj, finalizer inFinalizer=0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #ifdef HXCPP_VISIT_ALLOCS
							 | 
						||
| 
								 | 
							
								   void Visit(VisitContext *__inCtx);
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								   void Detach();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   bool      mValid;
							 | 
						||
| 
								 | 
							
								   finalizer mFinalizer;
							 | 
						||
| 
								 | 
							
								   hx::Object  *mObject;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Attach a finalizer to any object allocation.  This can be called from haxe code, but be aware that
							 | 
						||
| 
								 | 
							
								// you can't make any GC calls from the finalizer.
							 | 
						||
| 
								 | 
							
								void  GCSetFinalizer( hx::Object *, hx::finalizer f );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// If another thread wants to do a collect, it will signal this variable.
							 | 
						||
| 
								 | 
							
								// This automatically gets checked when you call "new", but if you are in long-running
							 | 
						||
| 
								 | 
							
								//  loop with no new call, you might starve another thread if you to not check this.
							 | 
						||
| 
								 | 
							
								//  0xffffffff = pause requested
							 | 
						||
| 
								 | 
							
								extern int gPauseForCollect;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Minimum total memory - used + buffer for new objects
							 | 
						||
| 
								 | 
							
								extern int sgMinimumWorkingMemory;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Minimum free memory - not counting used memory
							 | 
						||
| 
								 | 
							
								extern int sgMinimumFreeSpace;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Also ensure that the free memory is larger than this amount of used memory
							 | 
						||
| 
								 | 
							
								extern int sgTargetFreeSpacePercentage;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern HXCPP_EXTERN_CLASS_ATTRIBUTES int gByteMarkID;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Call in response to a gPauseForCollect. Normally, this is done for you in "new"
							 | 
						||
| 
								 | 
							
								void PauseForCollect();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Used by WeakHash to work out if it needs to dispose its keys
							 | 
						||
| 
								 | 
							
								bool IsWeakRefValid(hx::Object *inPtr);
							 | 
						||
| 
								 | 
							
								bool IsWeakRefValid(const HX_CHAR *inPtr);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Used by CFFI to scan a block of memory for GC Pointers. May picks up random crap
							 | 
						||
| 
								 | 
							
								//  that points to real, active objects.
							 | 
						||
| 
								 | 
							
								void MarkConservative(int *inBottom, int *inTop,hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Create/Remove a root.
							 | 
						||
| 
								 | 
							
								// All statics are explicitly registered - this saves adding the whole data segment
							 | 
						||
| 
								 | 
							
								//  to the collection list.
							 | 
						||
| 
								 | 
							
								// It takes a pointer-pointer so it can move the contents, and the caller can change the contents
							 | 
						||
| 
								 | 
							
								void GCAddRoot(hx::Object **inRoot);
							 | 
						||
| 
								 | 
							
								void GCRemoveRoot(hx::Object **inRoot);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// This is used internally in hxcpp
							 | 
						||
| 
								 | 
							
								// It calls InternalNew, and takes care of null-terminating the result
							 | 
						||
| 
								 | 
							
								char *NewString(int inLen);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The concept of 'private' is from the old conservative Gc method.
							 | 
						||
| 
								 | 
							
								// Now with explicit marking, these functions do the same thing, which is
							 | 
						||
| 
								 | 
							
								//  to allocate some GC memory and optionally copy the 'inData' into those bytes
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void *NewGCBytes(void *inData,int inSize);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void *NewGCPrivate(void *inData,int inSize);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Force a collect from the calling thread
							 | 
						||
| 
								 | 
							
								// Only one thread should call this at a time
							 | 
						||
| 
								 | 
							
								int InternalCollect(bool inMajor,bool inCompact);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Disable the garbage collector.  It will try to increase its internal buffers to honour extra requests.
							 | 
						||
| 
								 | 
							
								//  If it runs out of memory, it will actually try to do a collect.
							 | 
						||
| 
								 | 
							
								void InternalEnableGC(bool inEnable);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Record that fact that external memory has been allocated and associated with a haxe object
							 | 
						||
| 
								 | 
							
								//  eg. BitmapData.  This will help the collector know when to collect
							 | 
						||
| 
								 | 
							
								void GCChangeManagedMemory(int inDelta, const char *inWhy=0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Haxe threads can center GC free zones, where they can't make GC allocation calls, and should not mess with GC memory.
							 | 
						||
| 
								 | 
							
								// This means that they do not need to pause while the GC collections happen, and other threads will not
							 | 
						||
| 
								 | 
							
								//  wait for them to "check in" before collecting.  The standard runtime makes these calls around OS calls, such as "Sleep"
							 | 
						||
| 
								 | 
							
								void EnterGCFreeZone();
							 | 
						||
| 
								 | 
							
								void ExitGCFreeZone();
							 | 
						||
| 
								 | 
							
								// retuns true if ExitGCFreeZone should be called
							 | 
						||
| 
								 | 
							
								bool TryGCFreeZone();
							 | 
						||
| 
								 | 
							
								// retuns true if ExitGCFreeZone was called
							 | 
						||
| 
								 | 
							
								bool TryExitGCFreeZone();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class HXCPP_EXTERN_CLASS_ATTRIBUTES AutoGCFreeZone
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
									AutoGCFreeZone() : locked(true) { EnterGCFreeZone(); }
							 | 
						||
| 
								 | 
							
									~AutoGCFreeZone() { if (locked) ExitGCFreeZone(); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void close() { if (locked) ExitGCFreeZone(); locked = false; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bool locked;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Defined in Class.cpp, these function is called from the Gc to start the marking/visiting
							 | 
						||
| 
								 | 
							
								void MarkClassStatics(hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_VISIT_ALLOCS
							 | 
						||
| 
								 | 
							
								void VisitClassStatics(hx::VisitContext *__inCtx);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Called by haxe/application code to mark allocations.
							 | 
						||
| 
								 | 
							
								//  "Object" allocs will recursively call __Mark
							 | 
						||
| 
								 | 
							
								inline void MarkAlloc(void *inPtr ,hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								inline void MarkObjectAlloc(hx::Object *inPtr ,hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Implemented differently for efficiency
							 | 
						||
| 
								 | 
							
								void MarkObjectArray(hx::Object **inPtr, int inLength, hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								void MarkStringArray(String *inPtr, int inLength, hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Provide extra debug info to the marking routines
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_DEBUG
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void MarkSetMember(const char *inName ,hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void MarkPushClass(const char *inName ,hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void MarkPopClass(hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Used by runtime if it is being paranoid about pointers.  It checks that the pointer is real and alive at last collect.
							 | 
						||
| 
								 | 
							
								void GCCheckPointer(void *);
							 | 
						||
| 
								 | 
							
								void GCOnNewPointer(void *);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Called internally before and GC operations
							 | 
						||
| 
								 | 
							
								void CommonInitAlloc();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Threading ...
							 | 
						||
| 
								 | 
							
								void RegisterNewThread(void *inTopOfStack);
							 | 
						||
| 
								 | 
							
								void RegisterCurrentThread(void *inTopOfStack);
							 | 
						||
| 
								 | 
							
								void UnregisterCurrentThread();
							 | 
						||
| 
								 | 
							
								void GCPrepareMultiThreaded();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // end namespace hx
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Inline code tied to the immix implementation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace hx
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_USE_INLINE_IMMIX_OPERATOR_NEW
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//#define HX_STACK_CTX ::hx::ImmixAllocator *_hx_stack_ctx =  hx::gMultiThreadMode ? hx::tlsImmixAllocator : hx::gMainThreadAlloc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Each line ast 128 bytes (2^7)
							 | 
						||
| 
								 | 
							
								#define IMMIX_LINE_BITS    7
							 | 
						||
| 
								 | 
							
								#define IMMIX_LINE_LEN     (1<<IMMIX_LINE_BITS)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_GC_REMEMBERED          0x40
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The size info is stored in the header 8 bits to the right
							 | 
						||
| 
								 | 
							
								#define IMMIX_ALLOC_SIZE_SHIFT  6
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Indicates that __Mark must be called recursively
							 | 
						||
| 
								 | 
							
								#define IMMIX_ALLOC_IS_CONTAINER   0x00800000
							 | 
						||
| 
								 | 
							
								// String is char16_t type
							 | 
						||
| 
								 | 
							
								#define HX_GC_STRING_CHAR16_T      0x00200000
							 | 
						||
| 
								 | 
							
								// String has hash data at end
							 | 
						||
| 
								 | 
							
								#define HX_GC_STRING_HASH          0x00100000
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_GC_STRING_HASH_BIT      0x10
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_BIG_ENDIAN
							 | 
						||
| 
								 | 
							
								   #define HX_GC_STRING_HASH_OFFSET        -3
							 | 
						||
| 
								 | 
							
								   #define HX_GC_CONST_ALLOC_MARK_OFFSET   -4
							 | 
						||
| 
								 | 
							
								   #define HX_ENDIAN_MARK_ID_BYTE        -4
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								   #define HX_GC_STRING_HASH_OFFSET        -2
							 | 
						||
| 
								 | 
							
								   #define HX_GC_CONST_ALLOC_MARK_OFFSET   -1
							 | 
						||
| 
								 | 
							
								   #define HX_ENDIAN_MARK_ID_BYTE       -1
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The gPauseForCollect bits will turn spaceEnd negative, and so force the slow path
							 | 
						||
| 
								 | 
							
								#ifndef HXCPP_SINGLE_THREADED_APP
							 | 
						||
| 
								 | 
							
								   #define WITH_PAUSE_FOR_COLLECT_FLAG | hx::gPauseForCollect
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								   #define WITH_PAUSE_FOR_COLLECT_FLAG
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct StackContext;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								EXTERN_FAST_TLS_DATA(StackContext, tlsStackContext);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern StackContext *gMainThreadContext;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern unsigned int gImmixStartFlag[128];
							 | 
						||
| 
								 | 
							
								extern int gMarkID;
							 | 
						||
| 
								 | 
							
								extern int gMarkIDWithContainer;
							 | 
						||
| 
								 | 
							
								extern void BadImmixAlloc();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ImmixAllocator
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   virtual ~ImmixAllocator() {}
							 | 
						||
| 
								 | 
							
								   virtual void *CallAlloc(int inSize,unsigned int inObjectFlags) = 0;
							 | 
						||
| 
								 | 
							
								   virtual void SetupStackAndCollect(bool inMajor, bool inForceCompact, bool inLocked=false,bool inFreeIsFragged=false) = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #ifdef HXCPP_GC_NURSERY
							 | 
						||
| 
								 | 
							
								   unsigned char  *spaceFirst;
							 | 
						||
| 
								 | 
							
								   unsigned char  *spaceOversize;
							 | 
						||
| 
								 | 
							
								   #else
							 | 
						||
| 
								 | 
							
								   int            spaceStart;
							 | 
						||
| 
								 | 
							
								   int            spaceEnd;
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								   unsigned int   *allocStartFlags;
							 | 
						||
| 
								 | 
							
								   unsigned char  *allocBase;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   // These allocate the function using the garbage-colleced malloc
							 | 
						||
| 
								 | 
							
								   inline static void *alloc(ImmixAllocator *alloc, size_t inSize, bool inContainer, const char *inName )
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      #ifdef HXCPP_GC_NURSERY
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         unsigned char *buffer = alloc->spaceFirst;
							 | 
						||
| 
								 | 
							
								         unsigned char *end = buffer + (inSize + 4);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         if ( end > alloc->spaceOversize )
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            // Fall back to external method
							 | 
						||
| 
								 | 
							
								            buffer = (unsigned char *)alloc->CallAlloc(inSize, inContainer ? IMMIX_ALLOC_IS_CONTAINER : 0);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         else
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            alloc->spaceFirst = end;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (inContainer)
							 | 
						||
| 
								 | 
							
								               ((unsigned int *)buffer)[-1] = inSize | IMMIX_ALLOC_IS_CONTAINER;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								               ((unsigned int *)buffer)[-1] = inSize;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         #ifdef HXCPP_TELEMETRY
							 | 
						||
| 
								 | 
							
								         __hxt_gc_new((hx::StackContext *)alloc,buffer, inSize, inName);
							 | 
						||
| 
								 | 
							
								         #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         return buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      #else
							 | 
						||
| 
								 | 
							
								         #ifndef HXCPP_ALIGN_ALLOC
							 | 
						||
| 
								 | 
							
								            // Inline the fast-path if we can
							 | 
						||
| 
								 | 
							
								            // We know the object can hold a pointer (vtable) and that the size is int-aligned
							 | 
						||
| 
								 | 
							
								            int start = alloc->spaceStart;
							 | 
						||
| 
								 | 
							
								            int end = start + sizeof(int) + inSize;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if ( end <= alloc->spaceEnd )
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               alloc->spaceStart = end;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								               unsigned int *buffer = (unsigned int *)(alloc->allocBase + start);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								               int startRow = start>>IMMIX_LINE_BITS;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								               alloc->allocStartFlags[ startRow ] |= gImmixStartFlag[start&127];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								               if (inContainer)
							 | 
						||
| 
								 | 
							
								                  *buffer++ =  (( (end+(IMMIX_LINE_LEN-1))>>IMMIX_LINE_BITS) -startRow) |
							 | 
						||
| 
								 | 
							
								                               (inSize<<IMMIX_ALLOC_SIZE_SHIFT) |
							 | 
						||
| 
								 | 
							
								                               hx::gMarkIDWithContainer;
							 | 
						||
| 
								 | 
							
								               else
							 | 
						||
| 
								 | 
							
								                  *buffer++ =  (( (end+(IMMIX_LINE_LEN-1))>>IMMIX_LINE_BITS) -startRow) |
							 | 
						||
| 
								 | 
							
								                               (inSize<<IMMIX_ALLOC_SIZE_SHIFT) |
							 | 
						||
| 
								 | 
							
								                               hx::gMarkID;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								               #if defined(HXCPP_GC_CHECK_POINTER) && defined(HXCPP_GC_DEBUG_ALWAYS_MOVE)
							 | 
						||
| 
								 | 
							
								               hx::GCOnNewPointer(buffer);
							 | 
						||
| 
								 | 
							
								               #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								               #ifdef HXCPP_TELEMETRY
							 | 
						||
| 
								 | 
							
								               __hxt_gc_new((hx::StackContext *)alloc,buffer, inSize, inName);
							 | 
						||
| 
								 | 
							
								               #endif
							 | 
						||
| 
								 | 
							
								               return buffer;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								         #endif // HXCPP_ALIGN_ALLOC
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         // Fall back to external method
							 | 
						||
| 
								 | 
							
								         void *result = alloc->CallAlloc(inSize, inContainer ? IMMIX_ALLOC_IS_CONTAINER : 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         #ifdef HXCPP_TELEMETRY
							 | 
						||
| 
								 | 
							
								            __hxt_gc_new((hx::StackContext *)alloc,result, inSize, inName);
							 | 
						||
| 
								 | 
							
								         #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         return result;
							 | 
						||
| 
								 | 
							
								      #endif // HXCPP_GC_NURSERY
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef ImmixAllocator GcAllocator;
							 | 
						||
| 
								 | 
							
								typedef ImmixAllocator Ctx;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_GC_GENERATIONAL
							 | 
						||
| 
								 | 
							
								  #define HX_OBJ_WB_CTX(obj,value,ctx) { \
							 | 
						||
| 
								 | 
							
								        unsigned char &mark =  ((unsigned char *)(obj))[ HX_ENDIAN_MARK_ID_BYTE]; \
							 | 
						||
| 
								 | 
							
								        if (mark == hx::gByteMarkID && value && !((unsigned char *)(value))[ HX_ENDIAN_MARK_ID_BYTE  ] ) { \
							 | 
						||
| 
								 | 
							
								            mark|=HX_GC_REMEMBERED; \
							 | 
						||
| 
								 | 
							
								            ctx->pushReferrer(obj); \
							 | 
						||
| 
								 | 
							
								     } }
							 | 
						||
| 
								 | 
							
								  #define HX_OBJ_WB_PESSIMISTIC_CTX(obj,ctx) { \
							 | 
						||
| 
								 | 
							
								     unsigned char &mark =  ((unsigned char *)(obj))[ HX_ENDIAN_MARK_ID_BYTE]; \
							 | 
						||
| 
								 | 
							
								     if (mark == hx::gByteMarkID)  { \
							 | 
						||
| 
								 | 
							
								        mark|=HX_GC_REMEMBERED; \
							 | 
						||
| 
								 | 
							
								        ctx->pushReferrer(obj); \
							 | 
						||
| 
								 | 
							
								     } }
							 | 
						||
| 
								 | 
							
								  // I'm not sure if this will ever trigger...
							 | 
						||
| 
								 | 
							
								  #define HX_OBJ_WB_NEW_MARKED_OBJECT(obj) { \
							 | 
						||
| 
								 | 
							
								     if (((unsigned char *)(obj))[ HX_ENDIAN_MARK_ID_BYTE]==hx::gByteMarkID) hx::NewMarkedObject(obj); \
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								  #define HX_OBJ_WB_CTX(obj,value,ctx)
							 | 
						||
| 
								 | 
							
								  #define HX_OBJ_WB_PESSIMISTIC_CTX(obj,ctx)
							 | 
						||
| 
								 | 
							
								  #define HX_OBJ_WB_NEW_MARKED_OBJECT(obj)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_OBJ_WB(obj,value) HX_OBJ_WB_CTX(obj,value,_hx_ctx)
							 | 
						||
| 
								 | 
							
								#define HX_ARRAY_WB(array,index,value) HX_OBJ_WB(array,value)
							 | 
						||
| 
								 | 
							
								#define HX_OBJ_WB_PESSIMISTIC(obj) HX_OBJ_WB_PESSIMISTIC_CTX(obj,_hx_ctx)
							 | 
						||
| 
								 | 
							
								#define HX_OBJ_WB_GET(obj,value) HX_OBJ_WB_CTX(obj,value,HX_CTX_GET)
							 | 
						||
| 
								 | 
							
								#define HX_OBJ_WB_PESSIMISTIC_GET(obj) HX_OBJ_WB_PESSIMISTIC_CTX(obj,HX_CTX_GET)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES extern unsigned int gPrevMarkIdMask;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Called only once it is determined that a new mark is required
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void MarkAllocUnchecked(void *inPtr ,hx::MarkContext *__inCtx); 
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void MarkObjectAllocUnchecked(hx::Object *inPtr ,hx::MarkContext *__inCtx);
							 | 
						||
| 
								 | 
							
								HXCPP_EXTERN_CLASS_ATTRIBUTES void NewMarkedObject(hx::Object *inPtr);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								inline void MarkAlloc(void *inPtr ,hx::MarkContext *__inCtx)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   #ifdef EMSCRIPTEN
							 | 
						||
| 
								 | 
							
								   // Unaligned must be constants...
							 | 
						||
| 
								 | 
							
								   if ( !( ((size_t)inPtr) & 3) )
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								   // This will also skip const regions
							 | 
						||
| 
								 | 
							
								   if ( !(((unsigned int *)inPtr)[-1] & gPrevMarkIdMask) )
							 | 
						||
| 
								 | 
							
								      MarkAllocUnchecked(inPtr,__inCtx);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								inline void MarkObjectAlloc(hx::Object *inPtr ,hx::MarkContext *__inCtx)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   #ifdef EMSCRIPTEN
							 | 
						||
| 
								 | 
							
								   // Unaligned must be constants...
							 | 
						||
| 
								 | 
							
								   if ( !( ((size_t)inPtr) & 3) )
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								   // This will also skip const regions
							 | 
						||
| 
								 | 
							
								   if ( !(((unsigned int *)inPtr)[-1] & gPrevMarkIdMask) )
							 | 
						||
| 
								 | 
							
								      MarkObjectAllocUnchecked(inPtr,__inCtx);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // end namespace hx
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// It was theoretically possible to redefine the MarkContext arg type (or skip it)
							 | 
						||
| 
								 | 
							
								//  incase the particular GC scheme did not need it.  This may take a bit of extra
							 | 
						||
| 
								 | 
							
								//  work to get going again
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_MARK_ARG __inCtx
							 | 
						||
| 
								 | 
							
								//#define HX_MARK_ADD_ARG ,__inCtx
							 | 
						||
| 
								 | 
							
								#define HX_MARK_PARAMS hx::MarkContext *__inCtx
							 | 
						||
| 
								 | 
							
								//#define HX_MARK_ADD_PARAMS ,hx::MarkContext *__inCtx
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_VISIT_ALLOCS
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_ARG __inCtx
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_PARAMS hx::VisitContext *__inCtx
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_ARG
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_PARAMS
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// These macros add debug to the mark/visit calls if required
							 | 
						||
| 
								 | 
							
								// They also perform some inline checking to avoid function calls if possible
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_DEBUG
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_MARK_MEMBER_NAME(x,name) { hx::MarkSetMember(name, __inCtx); hx::MarkMember(x, __inCtx ); }
							 | 
						||
| 
								 | 
							
								#define HX_MARK_BEGIN_CLASS(x) hx::MarkPushClass(#x, __inCtx );
							 | 
						||
| 
								 | 
							
								#define HX_MARK_END_CLASS() hx::MarkPopClass(__inCtx );
							 | 
						||
| 
								 | 
							
								#define HX_MARK_MEMBER(x) { hx::MarkSetMember(0, __inCtx); hx::MarkMember(x, __inCtx ); }
							 | 
						||
| 
								 | 
							
								#define HX_MARK_MEMBER_ARRAY(x,len) { hx::MarkSetMember(0, __inCtx); hx::MarkMemberArray(x, len, __inCtx ); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_MARK_MEMBER_NAME(x,name) hx::MarkMember(x, __inCtx )
							 | 
						||
| 
								 | 
							
								#define HX_MARK_BEGIN_CLASS(x)
							 | 
						||
| 
								 | 
							
								#define HX_MARK_END_CLASS()
							 | 
						||
| 
								 | 
							
								#define HX_MARK_MEMBER(x) hx::MarkMember(x, __inCtx )
							 | 
						||
| 
								 | 
							
								#define HX_MARK_MEMBER_ARRAY(x,len) hx::MarkMemberArray(x, len, __inCtx )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_MARK_OBJECT(ioPtr) if (ioPtr) hx::MarkObjectAlloc(ioPtr, __inCtx );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_MARK_STRING(ioPtr) \
							 | 
						||
| 
								 | 
							
								   if (ioPtr) hx::MarkAlloc((void *)ioPtr, __inCtx );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_MARK_ARRAY(ioPtr) { if (ioPtr) hx::MarkAlloc((void *)ioPtr, __inCtx ); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_MEMBER_NAME(x,name) hx::VisitMember(x, __inCtx )
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_MEMBER(x) hx::VisitMember(x, __inCtx )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_OBJECT(ioPtr) \
							 | 
						||
| 
								 | 
							
								  { if (ioPtr && !(((unsigned char *)ioPtr)[HX_GC_CONST_ALLOC_MARK_OFFSET] & HX_GC_CONST_ALLOC_MARK_BIT) ) __inCtx->visitObject( (hx::Object **)&ioPtr); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_STRING(ioPtr) \
							 | 
						||
| 
								 | 
							
								   if (ioPtr && !(((unsigned char *)ioPtr)[HX_GC_CONST_ALLOC_MARK_OFFSET] & HX_GC_CONST_ALLOC_MARK_BIT) ) __inCtx->visitAlloc((void **)&ioPtr);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HX_VISIT_ARRAY(ioPtr) { if (ioPtr) __inCtx->visitAlloc((void **)&ioPtr); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 |