home *** CD-ROM | disk | FTP | other *** search
- /*
- File: MemPtchM.cpp
-
- Contains: Code to make MacOS memory routines call this memory manager
-
- Owned by: Jens Alfke (based on code by Troy Gaul)
-
- Copyright: © 1995 - 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <1> 6/19/96 jpa first checked in
-
- In Progress:
-
- */
-
-
- #include "MemMgr.h"
- #include "PlatfMem.h"
-
- #include <CodeFragments.h>
- #include <MixedMode.h>
- #include <Traps.h>
-
-
- //==============================================================================
- // Debugging support
- //==============================================================================
-
- #define WARN_ON_PATCH_CALL 0 // Set to 1 to break on every patch call
-
- #define PATCH_WARN \
- if(!MM_DEBUG || !WARN_ON_PATCH_CALL) ; else MM_SHOW_WARNING
-
-
- //==============================================================================
- // Constants / Types
- //==============================================================================
-
- const Size kSizeThreshold = 0; // Min block size to allocate with MMM
- const OSType kTag = 'ø∫pt'; // Magic tag at start of block
-
- // Typedef of private SetEmulatorRegister SPI call:
- typedef void (*SetEmulatorRegisterProcPtr) ( registerSelectorType, long newValue );
-
-
- //==============================================================================
- // Structs
- //==============================================================================
-
- struct BlockHeader {
- Size size; // Logical size of block (MMM only knows physical size)
- OSType tag; // Magic tag (kTag) to detect if this is a block I allocated
- };
-
- #define HEADER_OF_BLOCK(B) ((BlockHeader*)((char*)(B)-sizeof(BlockHeader)))
- #define BLOCK_OF_HEADER(H) ((void*)((char*)(H)+sizeof(BlockHeader)))
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // Global Variables
- //——————————————————————————————————————————————————————————————————————————————
-
- static MemHeap* gOSHeap = kMMNULL;
-
- static long gOverridePtrs = 0;
- static long gOverrideHandles = 0;
-
- #if GENERATINGPOWERPC
- SetEmulatorRegisterProcPtr gSetEmulatorRegisterAddr = kMMNULL;
- #endif
-
- static UniversalProcPtr gNewHandleAddress = NULL;
- static UniversalProcPtr gNewPtrAddress = NULL;
- static UniversalProcPtr gDisposePtrAddress = NULL;
- static UniversalProcPtr gGetPtrSizeAddress = NULL;
- static UniversalProcPtr gSetPtrSizeAddress = NULL;
- static UniversalProcPtr gMaxBlockAddress = NULL;
- static UniversalProcPtr gPtrZoneAddress = NULL;
-
- #if MM_DEBUG
- long gNewPtrBlockCount = 0;
- #endif
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // ProcInfos
- //——————————————————————————————————————————————————————————————————————————————
-
- enum
- {
- uppNewHandleProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(Handle)))
- | REGISTER_RESULT_LOCATION(kRegisterA0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size)))
- ,
- uppNewPtrProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(Ptr)))
- | REGISTER_RESULT_LOCATION(kRegisterA0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size)))
- ,
- uppDisposePtrProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
- | REGISTER_RESULT_LOCATION(kRegisterD0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
- ,
- uppGetPtrSizeProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(Size)))
- | REGISTER_RESULT_LOCATION(kRegisterD0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
- ,
- uppSetPtrSizeProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
- | REGISTER_RESULT_LOCATION(kRegisterD0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
- | REGISTER_ROUTINE_PARAMETER(3, kRegisterD0, SIZE_CODE(sizeof(Size)))
- ,
- uppMaxBlockProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(long)))
- | REGISTER_RESULT_LOCATION(kRegisterD0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- ,
- uppPtrZoneProcInfo
- = kRegisterBased
- | RESULT_SIZE(SIZE_CODE(sizeof(THz)))
- | REGISTER_RESULT_LOCATION(kRegisterA0)
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
- };
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // FindEmulatorCall
- //——————————————————————————————————————————————————————————————————————————————
-
- // From MixedModePriv.h:
- // extern long SetEmulatorRegister(registerSelectorType registerSelector, long newValue);
-
- #if GENERATINGPOWERPC
- static OSErr
- FindEmulatorCall( )
- {
- CFragConnectionID conn;
- Ptr mainAddr;
- Str255 errName;
- OSErr err;
- err = GetSharedLibrary("\pPrivateInterfaceLib",kCurrentCFragArch,kLoadLib,
- &conn,&mainAddr,errName);
- if( err ) return err;
-
- SymClass symClass;
- err= FindSymbol(conn,"\pSetEmulatorRegister",(Ptr*)&gSetEmulatorRegisterAddr,&symClass);
-
- CloseConnection(&conn);
- return err;
- }
- #endif
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // SetStatus
- //——————————————————————————————————————————————————————————————————————————————
- static void
- SetStatus( OSErr status )
- {
- // Used by NewHandle, NewPtr and PtrZone, which return error codes in D0.
- LMSetMemErr(status);
- #if GENERATINGPOWERPC
- (*gSetEmulatorRegisterAddr)(kRegisterD0,status);
- #endif
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // NewHandlePatch
- //——————————————————————————————————————————————————————————————————————————————
-
- static pascal Handle
- NewHandlePatch(unsigned short trapWord, Size byteCount)
- {
- Handle result;
- if( gOverrideHandles>0
- && (trapWord == _NewHandle || trapWord == _NewHandleClear)
- && byteCount >= kSizeThreshold
- && GetZone()==ApplicationZone() ) {
-
- long temp = gOverrideHandles; // Temporarily disable to avoid infinite regress
- gOverrideHandles = 0;
-
- result= (Handle) MMAllocateHandleIn(sizeof(BlockHeader) + byteCount, kMMTempMemory);
-
- gOverrideHandles = temp;
-
- if( result ) {
- if( trapWord == _NewHandleClear )
- PlatformZapMem(*result,byteCount,0);
- SetStatus(noErr);
- PATCH_WARN("NewHandle(%ld) = %p",byteCount,result);
- return result;
- } else
- MM_WARN("NewHandle(%ld) FAILED; trying app heap...",byteCount);
- // If allocation in temp mem failed, try the app heap...
- }
-
- result= (Handle)CallOSTrapUniversalProc(gNewHandleAddress, uppNewHandleProcInfo,
- trapWord, byteCount);
- #if GENERATINGPOWERPC
- SetStatus(MemError());
- #endif
-
- return result;
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // NewPtrPatch
- //——————————————————————————————————————————————————————————————————————————————
-
- static pascal Ptr
- NewPtrPatch(unsigned short trapWord, Size byteCount)
- {
- Ptr result;
- if( gOverridePtrs>0
- && (trapWord == _NewPtr || trapWord == _NewPtrClear)
- && byteCount >= kSizeThreshold
- && GetZone()==ApplicationZone() ) {
-
- BlockHeader *header;
- if (trapWord == _NewPtr)
- header = (BlockHeader*) MMAllocateIn(sizeof(BlockHeader) + byteCount, gOSHeap);
- else
- header = (BlockHeader*) MMAllocateClearIn(sizeof(BlockHeader) + byteCount, gOSHeap);
-
- if( header ) {
- header->tag = kTag;
- header->size = byteCount;
- result = (Ptr) BLOCK_OF_HEADER(header);
- #if MM_DEBUG
- gNewPtrBlockCount++;
- #endif
- SetStatus(noErr);
- PATCH_WARN("NewPtr(%ld) = %p",byteCount,result);
- return result;
- } else
- MM_WARN("NewPtr(%ld) FAILED; trying app heap...",byteCount);
- // If allocation in temp mem failed, try the app heap...
- }
-
- result= (Ptr)CallOSTrapUniversalProc(gNewPtrAddress, uppNewPtrProcInfo,
- trapWord, byteCount);
- #if GENERATINGPOWERPC
- SetStatus(MemError());
- #endif
-
- return result;
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // DisposePtrPatch
- //——————————————————————————————————————————————————————————————————————————————
- static pascal OSErr
- DisposePtrPatch(unsigned short trapWord, Ptr p)
- {
- BlockHeader *h = HEADER_OF_BLOCK(p);
- if (p && h->tag == kTag)
- {
- PATCH_WARN("DisposePtr(%p);g",p);
- h->tag = 0xDDDD; // Minimizes chance this will look like a block later
- MMFree(h);
- LMSetMemErr(noErr);
- #if MM_DEBUG
- gNewPtrBlockCount--;
- if( gNewPtrBlockCount==-1 ) MM_WARN("Too many NewPtr blocks disposed!?!?");
- #endif
- return noErr;
- }
- else
- {
- return CallOSTrapUniversalProc(gDisposePtrAddress, uppDisposePtrProcInfo,
- trapWord, p);
- }
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // GetPtrSizePatch
- //——————————————————————————————————————————————————————————————————————————————
- static pascal Size
- GetPtrSizePatch(unsigned short trapWord, Ptr p)
- {
- BlockHeader *h = HEADER_OF_BLOCK(p);
- if (p && h->tag == kTag)
- {
- PATCH_WARN("GetPtrSize(%p)",p);
- LMSetMemErr(noErr);
- return h->size;
- }
- else
- {
- return CallOSTrapUniversalProc(gGetPtrSizeAddress, uppGetPtrSizeProcInfo,
- trapWord, p);
- }
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // SetPtrSizePatch
- //——————————————————————————————————————————————————————————————————————————————
- static pascal OSErr
- SetPtrSizePatch(unsigned short trapWord, Ptr p, Size newSize)
- {
- BlockHeader *h = HEADER_OF_BLOCK(p);
- if (p && h->tag == kTag)
- {
- // Our memory manager lacks a way to grow a block into an adjacent free
- // block. This is probably not a big deal. Grow it as much as it can:
- PATCH_WARN("SetPtrSize(%p,%ld)",p,newSize);
- OSErr err;
- if( newSize <= MMBlockSize(h) ) {
- h->size = newSize;
- err= noErr;
- } else
- err= memFullErr;
- LMSetMemErr(err);
- return err;
- }
- else
- {
- return CallOSTrapUniversalProc(gSetPtrSizeAddress, uppSetPtrSizeProcInfo,
- trapWord, p, newSize);
- }
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // MaxBlockPatch
- //——————————————————————————————————————————————————————————————————————————————
- static pascal long
- MaxBlockPatch( unsigned short trapWord )
- {
- Size space = (Size) CallOSTrapUniversalProc(gMaxBlockAddress, uppMaxBlockProcInfo,
- trapWord);
- if( GetZone()==ApplicationZone() ) {
- PATCH_WARN("MaxBlock()");
-
- Size unused;
- Size tempSpace = TempMaxMem(&unused);
- if( tempSpace > space )
- space = tempSpace;
- }
- return space;
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // PtrZonePatch
- //——————————————————————————————————————————————————————————————————————————————
- static pascal THz
- PtrZonePatch(unsigned short trapword, Ptr p)
- {
- BlockHeader *h = HEADER_OF_BLOCK(p);
- if (p && h->tag == kTag)
- {
- // Not much we can do here but lie, since the actual zone is not a MacOS
- // zone in any sense. But we know the block _would_ have been in the app zone:
- PATCH_WARN("PtrZone(%p)",p);
- return ApplicationZone();
- SetStatus(noErr);
- }
- else
- {
- return (THz) CallOSTrapUniversalProc(gPtrZoneAddress, uppPtrZoneProcInfo,
- trapword, p);
- SetStatus(MemError());
- }
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // Routine descriptors
- //——————————————————————————————————————————————————————————————————————————————
-
- static RoutineDescriptor NewHandlePatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppNewHandleProcInfo, NewHandlePatch);
-
- static RoutineDescriptor NewPtrPatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppNewPtrProcInfo, NewPtrPatch);
-
- static RoutineDescriptor DisposePtrPatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppDisposePtrProcInfo, DisposePtrPatch);
-
- static RoutineDescriptor GetPtrSizePatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppGetPtrSizeProcInfo, GetPtrSizePatch);
-
- static RoutineDescriptor SetPtrSizePatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppSetPtrSizeProcInfo, SetPtrSizePatch);
-
- static RoutineDescriptor MaxBlockPatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppMaxBlockProcInfo, MaxBlockPatch);
-
- static RoutineDescriptor PtrZonePatchRD
- = BUILD_ROUTINE_DESCRIPTOR(uppPtrZoneProcInfo, PtrZonePatch);
-
-
- #if GENERATING68K
- /*
- What the heck is this stuff? On 68K we have some headaches trying to patch
- NewPtr, which returns two values: the pointer in A0 and an OSErr in D0.
- MixedMode only allows one return value. To work around this on 68K, the
- _real_ trap patch will be classic non-CFM 68K assembly which calls the CFM
- patch (NewPtrPatch) through a RoutineDescriptor, then sets D0.
- A gotcha here is that the value in the RoutineDescriptor is different for
- different CFM contexts, since it points to a TVector. This makes sense,
- since NewPtrPatch has to reference the global gOSHeap. To allow this,
- we can't use normal code since it's shared. So we force the stub to be
- generated in the global data space, which is per-context. Hence the hand
- assembly below.
- */
-
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=mac68k
- #endif
-
- struct PatchWrapper {
- short code1[1];
- UniversalProcPtr upp;
- short code2[4];
- };
-
- static PatchWrapper gNewHandlePatch = {
- {0x4EB9}, &NewHandlePatchRD, // jsr &NewHandlePatchRD
- {0x3038, 0x0220, // move.w MemErr,D0
- 0x48C0, // ext.l D0
- 0x4E75} // rts
- };
- static PatchWrapper gNewPtrPatch = {
- {0x4EB9}, &NewPtrPatchRD, // jsr &NewPtrPatchRD
- {0x3038, 0x0220, // move.w MemErr,D0
- 0x48C0, // ext.l D0
- 0x4E75} // rts
- };
- static PatchWrapper gPtrZonePatch = {
- {0x4EB9}, &PtrZonePatchRD, // jsr &PtrZonePatchRD
- {0x3038, 0x0220, // move.w MemErr,D0
- 0x48C0, // ext.l D0
- 0x4E75} // rts
- };
-
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=reset
- #endif
- #endif
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // MMOverridePlatform
- //——————————————————————————————————————————————————————————————————————————————
- void
- MMOverridePlatform( MMBoolean ptrs, MMBoolean handles )
- {
- if( ptrs ) {
- gOverridePtrs++;
- if( gNewPtrAddress == kMMNULL ) {
-
- // Install patches 1st time called:
- #if GENERATINGPOWERPC
- OSErr err= FindEmulatorCall();
- if( err != noErr ) {
- MM_WARN("Couldn't find SetEmulatorRegister, err %d",err);
- return;
- }
- #endif
-
- gOSHeap = MMGetDefaultHeap();
-
- gNewPtrAddress = GetOSTrapAddress(_NewPtr);
- gPtrZoneAddress = GetOSTrapAddress(_PtrZone);
- gDisposePtrAddress = GetOSTrapAddress(_DisposePtr);
- gGetPtrSizeAddress = GetOSTrapAddress(_GetPtrSize);
- gSetPtrSizeAddress = GetOSTrapAddress(_SetPtrSize);
- // gMaxBlockAddress = GetOSTrapAddress(_MaxBlock);
-
- #if GENERATING68K
- SetOSTrapAddress((UniversalProcPtr) &gNewPtrPatch, _NewPtr);
- SetOSTrapAddress((UniversalProcPtr) &gPtrZonePatch, _PtrZone);
- #else
- SetOSTrapAddress((UniversalProcPtr) &NewPtrPatchRD, _NewPtr);
- SetOSTrapAddress((UniversalProcPtr) &PtrZonePatchRD, _PtrZone);
- #endif
- SetOSTrapAddress((UniversalProcPtr) &DisposePtrPatchRD, _DisposePtr);
- SetOSTrapAddress((UniversalProcPtr) &GetPtrSizePatchRD, _GetPtrSize);
- SetOSTrapAddress((UniversalProcPtr) &SetPtrSizePatchRD, _SetPtrSize);
- // SetOSTrapAddress((UniversalProcPtr) &MaxBlockPatchRD, _MaxBlock);
-
- #if GENERATING68K
- #else
- #endif
- }
- }
-
- if( handles ) {
- gOverrideHandles++;
- if( gNewHandleAddress == kMMNULL ) {
- gNewHandleAddress = GetOSTrapAddress(_NewHandle);
- #if GENERATING68K
- SetOSTrapAddress((UniversalProcPtr) &gNewHandlePatch, _NewHandle);
- #else
- SetOSTrapAddress((UniversalProcPtr) &NewHandlePatchRD, _NewHandle);
- #endif
-
- /* MM_WARN("Testing handles...");
- Handle h = NewHandle(1234);
- MM_WARN("Handle is at %p",h);
- DisposeHandle(h);
- MM_WARN("...Done testing handles.");*/
- }
- }
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // MMEndOverridePlatform
- //——————————————————————————————————————————————————————————————————————————————
- void
- MMEndOverridePlatform( MMBoolean ptrs, MMBoolean handles )
- {
- if( ptrs ) {
- if( gOverridePtrs > 0 )
- gOverridePtrs--;
- else
- MM_WARN("Too many MMEndOverridePlatform(true,...)");
- }
- if( handles ) {
- if( gOverrideHandles > 0 )
- gOverrideHandles--;
- else
- MM_WARN("Too many MMEndOverridePlatform(...,true)");
- }
- }
-
-
- //——————————————————————————————————————————————————————————————————————————————
- // MMOverridingPlatform
- //——————————————————————————————————————————————————————————————————————————————
- void
- MMOverridingPlatform( MMBoolean *ptrs, MMBoolean *handles )
- {
- if( ptrs ) *ptrs = (gOverridePtrs>0);
- if( handles ) *handles = (gOverrideHandles>0);
- }
-