Milán Major

netscape-revival

1 branch
Code

nspr-/src/md_Mac/mdmacmem.c

#include "fastmem.h"
#include "prmacos.h"
#include "mdmacmem.h"
#include "prgc.h"
#include "stdlib.h"
#include <Memory.h>

//##############################################################################
//##############################################################################
#pragma mark DECLARATIONS AND ENUMERATIONS

typedef struct MemoryCacheFlusherProcRec MemoryCacheFlusherProcRec;

struct MemoryCacheFlusherProcRec {
	MemoryCacheFlusherProc			flushProc;
	MemoryCacheFlusherProcRec		*next;
};

typedef struct PreAllocationProcRec PreAllocationProcRec;

struct PreAllocationProcRec {
	PreAllocationHookProc			preAllocProc;
	PreAllocationProcRec			*next;
};

MemoryCacheFlusherProcRec	*gFirstFlusher = NULL;
PreAllocationProcRec		*gFirstPreAllocator = NULL;

void CallPreAllocators(void);
void MacintoshInitializeMemory(void);

//##############################################################################
//##############################################################################
#pragma mark INITIALIZATION

void MacintoshInitializeMemory(void)
{
	UInt32 i;
	MaxApplZone();
	for (i = 1; i <= 30; i++)
		MoreMasters();
#if DEBUG_MAC_MEMORY
	InstallMemoryManagerPatches();
#endif
}

//##############################################################################
//##############################################################################
#pragma mark FIXED-SIZE ALLOCATION DECLARATIONS

DeclareFixedSizeFastAllocator(4, 8);
DeclareFixedSizeFastAllocator(8, 8);
DeclareFixedSizeFastAllocator(12, 8);
//DeclareFixedSizeCompactAllocator(4);
//DeclareFixedSizeCompactAllocator(8);
//DeclareFixedSizeCompactAllocator(12);
DeclareFixedSizeCompactAllocator(16);
DeclareFixedSizeCompactAllocator(24);
DeclareFixedSizeCompactAllocator(32);
DeclareSmallHeapAllocator();

AllocMemoryBlockDescriptor gFastMemSmallSizeAllocators[] = {
	{	&StandardAlloc,				0 	},
	{	&FixedSizeFastAlloc,		(void *)&gFixedSizeFast4Root 	},
	{	&FixedSizeFastAlloc,		(void *)&gFixedSizeFast8Root 	},
	{	&FixedSizeFastAlloc,		(void *)&gFixedSizeFast12Root 	},
	{	&FixedSizeCompactAlloc,		(void *)&gFixedSizeCompact16Root 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&FixedSizeCompactAlloc,		(void *)&gFixedSizeCompact24Root 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&FixedSizeCompactAlloc,		(void *)&gFixedSizeCompact32Root 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	},
	{	&SmallHeapAlloc,			(void *)&gSmallHeapRoot 	}
};


//##############################################################################
//##############################################################################
#pragma mark -
#pragma mark INSTALLING MEMORY MANAGER HOOKS

void InstallPreAllocationHook(PreAllocationHookProc newHook)
{
	PreAllocationProcRec			*preAllocatorRec;

	preAllocatorRec = (PreAllocationProcRec *)(NewPtr(sizeof(PreAllocationProcRec)));

	if (preAllocatorRec != NULL) {
	
		preAllocatorRec->next = gFirstPreAllocator;
		preAllocatorRec->preAllocProc = newHook;
		gFirstPreAllocator = preAllocatorRec;		
	
	}

}

void InstallMemoryCacheFlusher(MemoryCacheFlusherProc newFlusher)
{	
	MemoryCacheFlusherProcRec		*previousFlusherRec = NULL;
	MemoryCacheFlusherProcRec		*cacheFlusherRec = gFirstFlusher;
	
	while (cacheFlusherRec != NULL) {
		previousFlusherRec = cacheFlusherRec;
		cacheFlusherRec = cacheFlusherRec->next;
	}

	cacheFlusherRec =  (MemoryCacheFlusherProcRec *)NewPtrClear(sizeof(MemoryCacheFlusherProcRec));
	
	if (cacheFlusherRec == NULL)
		return;

	cacheFlusherRec->flushProc = newFlusher;

	if (previousFlusherRec != NULL) {
		previousFlusherRec->next = cacheFlusherRec;
	}
	
	else {
		gFirstFlusher = cacheFlusherRec;
	}
	
}

void CallPreAllocators(void)
{
	PreAllocationProcRec		*currentPreAllocator = gFirstPreAllocator;

	while (currentPreAllocator != NULL) {
		(*(currentPreAllocator->preAllocProc))();
		currentPreAllocator = currentPreAllocator->next;
	}
	
}

UInt8 CallCacheFlushers(size_t blockSize)
{
	MemoryCacheFlusherProcRec		*currentCacheFlusher = gFirstFlusher;
	UInt8							result = false;

	while (currentCacheFlusher != NULL) {
		result |= (*(currentCacheFlusher->flushProc))(blockSize);
		currentCacheFlusher = currentCacheFlusher->next;
	}
	
	//	The garbage collection flusher should always be last
	
	result |= GarbageCollectorCacheFlusher(blockSize);
	
	return result;
	
}

//##############################################################################
//##############################################################################
#pragma mark -
#pragma mark RAW MEMORY ALLOCATION

//	kArchitechtureStartupOverhead is negative for 68K because
//	when the 68K version first starts up, not all of it's code
//	resources are loaded, even though there is space in the heap
//	for them.  This makes the initialize overhead
//	kArchitechtureStartupOverhead - (Size of missing code = 1.74MB) = -1MB

#define 	kMallocFractionOfFigmentHeap 	0.6
#if GENERATINGPOWERPC
#define		kArchitechtureStartupOverhead	740 * 1024
#else
#define		kArchitechtureStartupOverhead	(-1024 * 1024)
#endif

enum {
	kMallocCleanupEmergencyFundSize			= 8 * 1024,
	kMallocCleanupEmergencyFundIncrement	= 128
};

Handle		gMallocCleanupEmergencyFund = NULL;
Ptr			gMallocSubAllocationHeap = NULL;

long pascal MallocGrowZoneProc(Size cbNeeded)
{
	return 0;
}

#if GENERATINGCFM
RoutineDescriptor 	gMallocGrowZoneProcRD = BUILD_ROUTINE_DESCRIPTOR(uppGrowZoneProcInfo, &MallocGrowZoneProc);
#else
#define gMallocGrowZoneProcRD MallocGrowZoneProc
#endif

Ptr AllocateRawMemory(Size blockSize)
{
	THz			savedZone;
	Ptr			resultPtr;

	if (gMallocCleanupEmergencyFund == NULL)
		gMallocCleanupEmergencyFund = NewHandle(kMallocCleanupEmergencyFundSize);

	savedZone = GetZone();

	//	If we don't have a sub-heap yet, create one.
	
	if (gMallocSubAllocationHeap == NULL) {
		Size		newHeapSize;
		float		tmp;
		newHeapSize = FreeMem();
		newHeapSize += kArchitechtureStartupOverhead;
		tmp = (float)newHeapSize * kMallocFractionOfFigmentHeap;
		newHeapSize = tmp;
		gMallocSubAllocationHeap = NewPtr(newHeapSize);
		InitZone((GrowZoneUPP)&gMallocGrowZoneProcRD, 16, gMallocSubAllocationHeap + newHeapSize, gMallocSubAllocationHeap);
	}

	SetZone((THz)gMallocSubAllocationHeap);

	resultPtr = NewPtr(blockSize);
	
	if (resultPtr == NULL) {

		if (InMemory_ReserveInMacHeap())
			return NULL;

		SetZone(savedZone);
		Memory_ReserveInMallocHeap(blockSize);
		SetZone((THz)gMallocSubAllocationHeap);
		resultPtr = NewPtr(blockSize);
	
	}
	
	SetZone(savedZone);

#if DEBUG
	if (resultPtr == NULL)
		DebugStr("\pAllocateRawMemory FAILED!");
#endif

	return resultPtr;
	
}

void FreeRawMemory(Ptr reclaimedRawBlock)
{
	DisposePtr(reclaimedRawBlock);
}

//##############################################################################
//##############################################################################
#pragma mark -
#pragma mark MEMORY UTILS

Boolean gInMemory_ReserveInMacHeap = false;

Boolean InMemory_ReserveInMacHeap()
{
	return gInMemory_ReserveInMacHeap;
}

Boolean ReclaimMemory(size_t amountNeeded)
{
	THz				savedZone;
	Boolean			result;
	Size			reclaimSize;
	
	savedZone = GetZone();
	SetZone((THz)gMallocSubAllocationHeap);

	if (gMallocCleanupEmergencyFund != NULL)
		DisposeHandle(gMallocCleanupEmergencyFund);
		
	SetZone(savedZone);
	result = CallCacheFlushers(amountNeeded);

	SetZone((THz)gMallocSubAllocationHeap);
	
	reclaimSize = kMallocCleanupEmergencyFundSize;
	gMallocCleanupEmergencyFund = NULL;
	
	while ((gMallocCleanupEmergencyFund == NULL) && (reclaimSize != 0)) {
		gMallocCleanupEmergencyFund = NewHandle(reclaimSize);
		reclaimSize -= kMallocCleanupEmergencyFundIncrement;
	}
	
	SetZone(savedZone);
	
	return result;

}

Boolean Memory_ReserveInMacHeap(size_t spaceNeeded)
{
	Boolean		result = true;
	
	gInMemory_ReserveInMacHeap = true;
	
	if (MaxBlock() < spaceNeeded)
		result = ReclaimMemory(spaceNeeded);
	
	gInMemory_ReserveInMacHeap = false;

	return result;
	
}

Boolean Memory_ReserveInMallocHeap(size_t spaceNeeded)
{
	THz			savedZone;
	Boolean		result = true;
	Size		freeMem;
	
	gInMemory_ReserveInMacHeap = true;
	
	savedZone = GetZone();
	SetZone((THz)gMallocSubAllocationHeap);
	freeMem = MaxBlock();
	SetZone(savedZone);
	
	if (freeMem < spaceNeeded)
		result = ReclaimMemory(spaceNeeded);

	gInMemory_ReserveInMacHeap = false;

	return result;
	
}

size_t Memory_FreeMemoryRemaining()
{
	size_t		mainHeap;
	size_t		mallocHeap;
	THz			savedZone;
	
	mainHeap = FreeMem();
	
	savedZone = GetZone();
	SetZone((THz)gMallocSubAllocationHeap);
	mallocHeap = FreeMem();
	SetZone(savedZone);
	
	return (mainHeap < mallocHeap) ? mainHeap : mallocHeap; 

}

//##############################################################################
//##############################################################################
#pragma mark -
#pragma mark FLUSHING THE GARBAGE COLLECTOR

extern int _pr_intsOff;

unsigned char GarbageCollectorCacheFlusher(size_t size)
{
	UInt32		oldPriority;

	//	If java wasn't completely initialized, then bail 
	//	harmlessly.
	
	if (PR_GetGCInfo()->lock == NULL)
		return false;

#if DEBUG
	if (_pr_intsOff == 1)
		DebugStr("\pGarbageCollectorCacheFlusher at interrupt time!");
#endif

	//	The synchronization here is very tricky.  We really
	//	don't want any other threads to run while we are 
	//	cleaning up the gc heap... they could call malloc,
	//	and then we would be in trouble in a big way.  So,
	//	we jack up our priority and that of the finalizer
	//	so that we won't yield to other threads.
	//	dkc 5/17/96

	oldPriority = PR_GetThreadPriority(PR_CurrentThread());
	_pr_intsOff = 1;
	_PR_SetThreadPriority(PR_CurrentThread(), 30);
	_pr_intsOff = 0;

	//	Garbage collect twice.  This will finalize any
	//	dangling AWT resources (images, components), and
	//	then free up their GC space, too.
	//	dkc 2/15/96
	
	PR_GC();
	
	//	By setting the finalizer priority to 31, then we 
	//	ensure it will run before us.  When it finishes
	//	its list of finalizations, it returns to us
	//	for the second garbage collection.
	
	PR_Yield();

	PR_GC();
	
	//	Restore our old priorities.
	
	_pr_intsOff = 1;
	_PR_SetThreadPriority(PR_CurrentThread(), oldPriority);
	_pr_intsOff = 0;

	//	And release any other resources that might be around.
	
	_PR_FreeZombies();

	return false;

}