Heap.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097
  1. //---------------------------------------------------------------------------
  2. //
  3. // Heap.cpp -- This file contains the definition for the Base HEAP
  4. // Manager Class. The Base HEAP manager creates,
  5. // manages and destroys block of memory using Win32
  6. // Virtual memory calls.h
  7. //
  8. //---------------------------------------------------------------------------//
  9. // Copyright (C) Microsoft Corporation. All rights reserved. //
  10. //===========================================================================//
  11. //---------------------------------------------------------------------------
  12. // Include Files
  13. #ifndef HEAP_H
  14. #include "heap.h"
  15. #endif
  16. #ifndef FILE_H
  17. #include "file.h"
  18. #endif
  19. #include <windows.h>
  20. #include <imagehlp.h>
  21. #include <gameos.hpp>
  22. #include <tchar.h>
  23. #include <stdio.h> // For sprintf
  24. #include <string.h> // For strchr
  25. //---------------------------------------------------------------------------
  26. // Static Globals
  27. static char CorruptMsg[] = "Heap check failed.\n";
  28. static char pformat[] = "%s %s\n";
  29. GlobalHeapRec HeapList::heapRecords[MAX_HEAPS];
  30. HeapListPtr globalHeapList = NULL;
  31. unsigned long memCoreLeft = 0;
  32. unsigned long memTotalLeft = 0;
  33. unsigned long totalSize = 0;
  34. unsigned long totalCoreLeft = 0;
  35. unsigned long totalLeft = 0;
  36. bool HeapList::heapInstrumented = 0;
  37. //
  38. // Returns a context ready for stack walking from current address
  39. //
  40. void GetCurrentContext( CONTEXT* Context )
  41. {
  42. memset( Context, 0, sizeof(CONTEXT) );
  43. _asm
  44. {
  45. mov ebx,Context
  46. mov [ebx]+CONTEXT.Ebp,ebp
  47. mov [ebx]+CONTEXT.Esp,esp
  48. call GetEIP
  49. mov [ebx]+CONTEXT.Eip,eax
  50. jmp Exit
  51. GetEIP:
  52. pop eax
  53. push eax
  54. ret
  55. Exit:
  56. }
  57. }
  58. void InitStackWalk(STACKFRAME *sf, CONTEXT *Context);
  59. int WalkStack(STACKFRAME *sf);
  60. char* DecodeAddress( DWORD Address , bool brief);
  61. //---------------------------------------------------------------------------
  62. // Macro definitions
  63. #define USE_BEST_FIT
  64. #ifdef _DEBUG
  65. #define SAFE_HEAP
  66. #endif
  67. #ifdef _DEBUG
  68. #define CHECK_HEAP
  69. #endif
  70. #ifdef LAB_ONLY
  71. #define CHECK_HEAP
  72. #endif
  73. //---------------------------------------------------------------------------
  74. // Class HeapManager Member Functions
  75. HeapManager::~HeapManager (void)
  76. {
  77. destroy();
  78. }
  79. //---------------------------------------------------------------------------
  80. void HeapManager::destroy (void)
  81. {
  82. long result = 0;
  83. //-----------------------------
  84. // Remove this from the UEBER HEAP
  85. #ifdef CHECK_HEAP
  86. globalHeapList->removeHeap(this);
  87. #endif
  88. if (committedSize)
  89. {
  90. result = VirtualFree(heap,totalSize,MEM_DECOMMIT);
  91. if (result == FALSE)
  92. result = GetLastError();
  93. }
  94. if (totalSize && memReserved && heap)
  95. {
  96. result = VirtualFree(heap,0,MEM_RELEASE);
  97. if (result == FALSE)
  98. result = GetLastError();
  99. }
  100. init();
  101. }
  102. //---------------------------------------------------------------------------
  103. HeapManager::HeapManager (void)
  104. {
  105. init();
  106. }
  107. //---------------------------------------------------------------------------
  108. void HeapManager::init (void)
  109. {
  110. heap = NULL;
  111. memReserved = FALSE;
  112. totalSize = 0;
  113. committedSize = 0;
  114. nxt = NULL;
  115. }
  116. //---------------------------------------------------------------------------
  117. HeapManager::operator MemoryPtr (void)
  118. {
  119. return getHeapPtr();
  120. }
  121. //---------------------------------------------------------------------------
  122. MemoryPtr HeapManager::getHeapPtr (void)
  123. {
  124. if (memReserved && totalSize && committedSize && heap)
  125. return heap;
  126. return NULL;
  127. }
  128. //---------------------------------------------------------------------------
  129. long HeapManager::createHeap (unsigned long memSize)
  130. {
  131. heap = (MemoryPtr)VirtualAlloc(NULL,memSize,MEM_RESERVE,PAGE_READWRITE);
  132. if (heap)
  133. {
  134. memReserved = TRUE;
  135. totalSize = memSize;
  136. return NO_ERR;
  137. }
  138. return COULDNT_CREATE;
  139. }
  140. //---------------------------------------------------------------------------
  141. long HeapManager::commitHeap (unsigned long commitSize)
  142. {
  143. if (commitSize == 0)
  144. commitSize = totalSize;
  145. if (commitSize > totalSize)
  146. return ALLOC_TOO_BIG;
  147. if (commitSize < totalSize)
  148. return COULDNT_COMMIT;
  149. unsigned long memLeft = totalSize - committedSize;
  150. if (!memLeft)
  151. {
  152. return OUT_OF_MEMORY;
  153. }
  154. if (memLeft < commitSize)
  155. {
  156. commitSize = memLeft;
  157. }
  158. MemoryPtr result = (MemoryPtr)VirtualAlloc(heap,commitSize,MEM_COMMIT,PAGE_READWRITE);
  159. if (result == heap)
  160. {
  161. long actualSize = commitSize;
  162. committedSize += actualSize;
  163. #ifdef CHECK_HEAP
  164. //-----------------------------
  165. // Add this to the UEBER HEAP
  166. globalHeapList->addHeap(this);
  167. #endif
  168. //------------------------------
  169. // Store off who called this.
  170. // If this was a UserHeap,
  171. // the UserHeap class will
  172. // do its own unwind.
  173. unsigned long currentEbp;
  174. unsigned long prevEbp;
  175. unsigned long retAddr;
  176. __asm
  177. {
  178. mov currentEbp,esp
  179. }
  180. prevEbp = *((unsigned long *)currentEbp);
  181. retAddr = *((unsigned long *)(currentEbp+4));
  182. whoMadeMe = retAddr;
  183. return NO_ERR;
  184. }
  185. gosASSERT(false);
  186. return COULDNT_COMMIT;
  187. }
  188. //---------------------------------------------------------------------------
  189. long HeapManager::decommitHeap (unsigned long decommitSize)
  190. {
  191. long result = 0;
  192. if (decommitSize == 0)
  193. decommitSize = totalSize;
  194. if (decommitSize > committedSize)
  195. decommitSize = committedSize;
  196. if (decommitSize < committedSize)
  197. decommitSize = totalSize;
  198. unsigned long decommitAddress = decommitSize;
  199. committedSize -= decommitAddress;
  200. result = VirtualFree((void *)committedSize,decommitSize,MEM_DECOMMIT);
  201. if (result == FALSE)
  202. result = GetLastError();
  203. return NO_ERR;
  204. }
  205. /////////////////////////////////////////////////////////////
  206. //---------------------------------------------------------------------------
  207. // Class UserHeap Member Functions
  208. UserHeap::UserHeap (void) : HeapManager()
  209. {
  210. heapStart = NULL;
  211. heapEnd = NULL;
  212. firstNearBlock = NULL;
  213. heapSize = 0;
  214. #ifdef CHECK_HEAP
  215. mallocFatals = TRUE;
  216. #else
  217. mallocFatals = FALSE;
  218. #endif
  219. heapState = NO_ERR;
  220. }
  221. //---------------------------------------------------------------------------
  222. long UserHeap::init (unsigned long memSize, char *heapId, bool useGOS)
  223. {
  224. if (heapId)
  225. {
  226. heapName = (char *)::gos_Malloc(strlen(heapId)+1);
  227. strcpy(heapName,heapId);
  228. }
  229. else
  230. heapName = NULL;
  231. if (!useGOS)
  232. {
  233. long result = createHeap(memSize);
  234. if (result)
  235. STOP(("Could not create Heap %s. Error:%x",heapId,result));
  236. result = commitHeap(memSize);
  237. if (result)
  238. STOP(("Could not create Heap %s. Error:%x",heapId,result));
  239. //------------------------------
  240. // Store off who called this.
  241. // If this was a UserHeap,
  242. // the UserHeap class will
  243. // do its own unwind.
  244. unsigned long currentEbp;
  245. unsigned long prevEbp;
  246. unsigned long retAddr;
  247. __asm
  248. {
  249. mov currentEbp,esp
  250. }
  251. prevEbp = *((unsigned long *)currentEbp);
  252. retAddr = *((unsigned long *)(currentEbp+4));
  253. whoMadeMe = retAddr;
  254. //------------------------------------------------------------------------
  255. // Now that we have a pointer to the memory, setup the HEAP.
  256. unsigned long heapTop = (unsigned long)heap;
  257. heapTop += memSize;
  258. heapTop -= 16;
  259. heapTop &= ~3; //Force top to be DWORD boundary.
  260. unsigned long heapBottom = (unsigned long)heap;
  261. heapStart = (HeapBlockPtr)heapBottom;
  262. heapEnd = (HeapBlockPtr)heapTop;
  263. heapStart->blockSize = heapTop - heapBottom;
  264. heapStart->upperBlock = 0; //Nothing above this in memory.
  265. heapEnd->blockSize = 1; //Mark as last block.
  266. heapEnd->previous = (HeapBlockPtr)0x1572; //Mark as last block.
  267. heapEnd->upperBlock = (HeapBlockPtr)heapBottom;
  268. //--------------------------------
  269. // Set all free memory to -1.
  270. // Any access before ready and Exception city.
  271. MemoryPtr start = (MemoryPtr)heapBottom;
  272. start += sizeof(HeapBlock);
  273. unsigned long length = heapTop-heapBottom;
  274. length -= sizeof(HeapBlock);
  275. FillMemory(start,length,0xff);
  276. //----------------------------------
  277. // linkup heap blocks
  278. firstNearBlock = NULL;
  279. relink(heapStart);
  280. heapSize = memSize;
  281. #ifdef _DEBUG
  282. recordArray = NULL;
  283. recordCount = 0;
  284. logMallocs = FALSE;
  285. #endif;
  286. gosHeap = 0;
  287. }
  288. else
  289. {
  290. gosHeap = gos_CreateMemoryHeap(heapId,memSize);
  291. useGOSGuardPage = true;
  292. heapStart = NULL;
  293. heapEnd = NULL;
  294. firstNearBlock = NULL;
  295. heapSize = 0;
  296. heapName = NULL;
  297. heapState = NO_ERR;
  298. #ifdef _DEBUG
  299. recordArray = NULL;
  300. #endif
  301. }
  302. return NO_ERR;
  303. }
  304. #ifdef _DEBUG
  305. //---------------------------------------------------------------------------
  306. void UserHeap::startHeapMallocLog (void)
  307. {
  308. if (!recordArray)
  309. {
  310. recordArray = new memRecord[NUMMEMRECORDS];
  311. memset(recordArray, 0, sizeof(memRecord) * NUMMEMRECORDS);
  312. recordCount = 0;
  313. }
  314. logMallocs = TRUE;
  315. }
  316. //---------------------------------------------------------------------------
  317. void UserHeap::stopHeapMallocLog (void)
  318. {
  319. logMallocs = FALSE;
  320. }
  321. //---------------------------------------------------------------------------
  322. void UserHeap::dumpRecordLog (void)
  323. {
  324. if (recordArray)
  325. {
  326. File log;
  327. char msg[256];
  328. sprintf(msg,"heapdump.%s.log",heapName);
  329. log.create(msg);
  330. for (int i=0; i<NUMMEMRECORDS; i++)
  331. {
  332. if (recordArray[i].ptr)
  333. {
  334. sprintf(msg, "Allocated block at DS:%08X, size = %u\n", recordArray[i].ptr, recordArray[i].size);
  335. log.writeLine(msg);
  336. char* addressName = DecodeAddress(recordArray[i].stack[0],false);
  337. sprintf(msg, "Call stack: %08X : %s", recordArray[i].stack[0],addressName);
  338. log.writeLine(msg);
  339. for (int j=1; j<12; j++)
  340. {
  341. if (recordArray[i].stack[j] == 0x0)
  342. break;
  343. char* addressName = DecodeAddress(recordArray[i].stack[j],false);
  344. sprintf(msg, " %08X : %s", recordArray[i].stack[j],addressName);
  345. log.writeLine(msg);
  346. }
  347. log.writeByte('\n');
  348. }
  349. }
  350. log.close();
  351. }
  352. }
  353. #endif
  354. //---------------------------------------------------------------------------
  355. UserHeap::~UserHeap (void)
  356. {
  357. destroy();
  358. }
  359. //---------------------------------------------------------------------------
  360. void UserHeap::destroy (void)
  361. {
  362. HeapManager::destroy();
  363. if (!gosHeap)
  364. {
  365. heapStart = NULL;
  366. heapEnd = NULL;
  367. firstNearBlock = NULL;
  368. heapSize = 0;
  369. if (heapName)
  370. {
  371. ::gos_Free(heapName);
  372. heapName = NULL;
  373. }
  374. heapState = NO_ERR;
  375. #ifdef _DEBUG
  376. if (recordArray)
  377. {
  378. delete [] recordArray;
  379. recordArray = NULL;
  380. }
  381. #endif
  382. }
  383. else
  384. {
  385. gos_DestroyMemoryHeap(gosHeap,false);
  386. gosHeap = NULL;
  387. }
  388. }
  389. //---------------------------------------------------------------------------
  390. unsigned long UserHeap::totalCoreLeft (void)
  391. {
  392. unsigned long result = 0;
  393. if (gosHeap)
  394. return result;
  395. #ifdef SAFE_HEAP
  396. long localHeapState = heapState;
  397. #endif
  398. HeapBlockPtr localFirst = firstNearBlock;
  399. long heapBlockSize = -(long)allocatedBlockSize;
  400. if (!firstNearBlock)
  401. {
  402. #ifdef _DEBUG
  403. PAUSE(("Heap %s firstNearBlock is NULL.",heapName));
  404. #endif
  405. return 0;
  406. }
  407. #ifdef SAFE_HEAP
  408. __asm
  409. {
  410. cmp localHeapState,0
  411. jne error1
  412. }
  413. #endif
  414. __asm
  415. {
  416. xor eax,eax
  417. mov edi,10000
  418. mov ecx,heapBlockSize
  419. mov ebx,localFirst
  420. mov edx,ebx //edx = is place holder for first node
  421. }
  422. BytesLoop:
  423. __asm
  424. {
  425. mov ebx,[ebx].next
  426. add eax,[ebx].blockSize
  427. add eax,ecx
  428. dec edi
  429. je short error1
  430. cmp ebx,edx
  431. jne short BytesLoop
  432. jmp short DoneTC
  433. }
  434. error1:
  435. __asm
  436. {
  437. xor eax,eax
  438. }
  439. DoneTC:
  440. __asm
  441. {
  442. mov result,eax
  443. }
  444. return(result);
  445. }
  446. //---------------------------------------------------------------------------
  447. unsigned long UserHeap::coreLeft (void)
  448. {
  449. unsigned long result = 0;
  450. if (gosHeap)
  451. return result;
  452. #ifdef SAFE_HEAP
  453. long localHeapState = heapState;
  454. #endif
  455. HeapBlockPtr localFirst = firstNearBlock;
  456. long heapBlockSize = -(long)allocatedBlockSize;
  457. #ifdef USE_BEST_FIT
  458. __asm
  459. {
  460. xor eax,eax
  461. }
  462. #ifdef SAFE_HEAP
  463. __asm
  464. {
  465. cmp localHeapState,0
  466. jne short DoneCL
  467. }
  468. #endif
  469. __asm
  470. {
  471. mov ebx,localFirst
  472. or ebx,ebx
  473. je short DoneCL
  474. mov ebx,[ebx].previous
  475. mov eax,[ebx].blockSize // size of last block in list
  476. add eax,heapBlockSize
  477. }
  478. DoneCL:
  479. __asm
  480. {
  481. mov result, eax
  482. }
  483. return(result);
  484. #else // !DEFINED BEST_FIT
  485. __asm
  486. {
  487. xor eax,eax
  488. }
  489. #ifdef SAFE_HEAP
  490. __asm
  491. {
  492. cmp localHeapState,0
  493. jne short DoneCL
  494. }
  495. #endif
  496. __asm
  497. {
  498. mov ebx,localFirst
  499. or ebx,ebx
  500. je short DoneCL
  501. mov ecx,10000
  502. }
  503. TopLoop:
  504. __asm
  505. {
  506. cmp [ebx].blockSize,eax
  507. jb Next
  508. mov eax,[ebx].blockSize
  509. }
  510. Next:
  511. __asm
  512. {
  513. dec ecx
  514. jle DoneCL
  515. mov ebx,[ebx].next
  516. cmp ebx,localFirst
  517. jne TopLoop
  518. add eax,heapBlockSize
  519. }
  520. DoneCL:
  521. __asm
  522. {
  523. mov result, eax
  524. }
  525. return(result);
  526. #endif
  527. }
  528. //---------------------------------------------------------------------------
  529. void * UserHeap::Malloc (unsigned long memSize)
  530. {
  531. void * result = NULL;
  532. if (gosHeap)
  533. {
  534. gos_PushCurrentHeap( gosHeap );
  535. result = gos_Malloc(memSize);
  536. gos_PopCurrentHeap();
  537. return result;
  538. }
  539. HeapBlockPtr blockOffs = NULL;
  540. HeapBlockPtr localFirst = firstNearBlock;
  541. long heapBlockSize = sizeof(HeapBlock);
  542. bool mf = mallocFatals;
  543. #ifdef _DEBUG
  544. heapBlockSize += 4;
  545. #endif
  546. long errorResult = 0;
  547. __asm
  548. {
  549. mov eax,memSize
  550. or eax,eax
  551. je Alloc_zero
  552. }
  553. #ifdef _DEBUG
  554. __asm
  555. {
  556. add eax,4 // extra space for who made me pointer
  557. }
  558. #endif
  559. __asm
  560. {
  561. add eax,11 //force minimum allocation 8+3
  562. and al, 0xfc //NOT 3 //force dword alignment
  563. cmp eax,heapBlockSize
  564. jae short SizeDone
  565. mov eax,heapBlockSize
  566. }
  567. SizeDone:
  568. __asm
  569. {
  570. cmp eax,memSize
  571. jb Alloc_Overflow
  572. //search free list for first available block
  573. mov ebx,localFirst
  574. or ebx,ebx
  575. je Zero_Free
  576. mov edx,ebx //marker to beginning of list
  577. }
  578. SearchLoop:
  579. __asm
  580. {
  581. mov ecx,[ebx].blockSize
  582. sub ecx,eax //unsigned math
  583. jnb short FoundBlock
  584. mov ebx,[ebx].next
  585. cmp edx,ebx
  586. jne SearchLoop //have we come back to first node?
  587. //else block was not found
  588. add ecx,eax // ECX = biggest block
  589. mov edx,[memSize] // EDX = bytes asked for
  590. mov eax,OUT_OF_MEMORY // EAX = Out of memory error number
  591. jmp Alloc_error
  592. }
  593. FoundBlock:
  594. // ebx = offset of found block
  595. // ecx = size of leftover block
  596. // eax = size of block to allocate
  597. __asm
  598. {
  599. mov blockOffs,ebx
  600. cmp ecx,heapBlockSize //any memory left to reallocate?
  601. jae short UnlinkNormal
  602. or [ebx].blockSize,1 //mark allocated
  603. }
  604. //This code is the unlink macro.
  605. __asm
  606. {
  607. cmp [ebx].next,ebx
  608. jne short ULine1
  609. //else list is now empty
  610. mov localFirst,0
  611. jmp short ULine3
  612. }
  613. ULine1:
  614. __asm
  615. {
  616. mov edx,localFirst
  617. cmp ebx,edx
  618. jne short ULine2 //unlinking first element?
  619. mov eax,[ebx].next
  620. mov localFirst,eax
  621. }
  622. ULine2:
  623. __asm
  624. {
  625. mov edi,[ebx].next //edi = ebx.next
  626. mov ebx,[ebx].previous
  627. mov [edi].previous,ebx //ebx.next.prev = ebx.prev
  628. mov [ebx].next,edi //ebx.prev.next = ebx.next
  629. }
  630. ULine3: //End of Unlink code
  631. __asm
  632. {
  633. mov eax,blockOffs
  634. jmp short Alloc_Done
  635. }
  636. UnlinkNormal:
  637. __asm
  638. {
  639. mov edi,ebx
  640. add edi,[ebx].blockSize //edi -> lower block
  641. add [edi].upperBlock,ecx //update lower pointer to the new block
  642. mov [ebx].blockSize,ecx
  643. mov edi,ebx
  644. add edi,ecx //edi -> newblock
  645. or al,1 //mark new block as allocated
  646. mov [edi].blockSize,eax
  647. mov [edi].upperBlock,ebx
  648. }
  649. //-------------------------------------------------------------------------------------
  650. //SORT Routine
  651. #ifdef USE_BEST_FIT
  652. __asm
  653. {
  654. pushad
  655. }
  656. //-------------------------------------
  657. //see if we have to do any work at all
  658. HeapBlockPtr localFirstSort = firstNearBlock;
  659. __asm
  660. {
  661. mov edx,localFirstSort
  662. mov ecx,[ebx].blockSize
  663. mov edi,[ebx].next
  664. cmp edi,[ebx].previous
  665. jne short __Line1 //either 1 or two members in list
  666. cmp edi,ebx
  667. je __Done //only one member in list
  668. //else there are only two
  669. mov localFirstSort,ebx //assume we are the smaller block
  670. cmp ecx,[edi].blockSize
  671. jbe __Done //we were right
  672. mov localFirstSort,edi //else other guy is smaller
  673. jmp __Done
  674. }
  675. __Line1: // else see if we are not in the correct order
  676. __asm
  677. {
  678. cmp ecx,[edi].blockSize
  679. jbe short __Line2
  680. //else see if next guy in line is the localFirst
  681. cmp edi,edx //did we just compare with Beginning of list?
  682. jne short __Line3 //no
  683. }
  684. __Line2:
  685. __asm
  686. {
  687. mov edi,[ebx].previous
  688. cmp ecx,[edi].blockSize
  689. jae short __Done
  690. //else we are less than guy to our left
  691. cmp ebx,edx //are we the first block in list?
  692. je short __Done
  693. __Line3: //else we must unlink our block, saving a pointer to lower neighbor
  694. push edi
  695. push ebx
  696. //Unlink Routine inline here
  697. cmp [ebx].next,ebx
  698. jne short _ULine1
  699. //else list is now empty
  700. mov localFirstSort,0
  701. jmp short _ULine3
  702. }
  703. _ULine1:
  704. __asm
  705. {
  706. mov edx,localFirstSort
  707. cmp ebx,edx
  708. jne short _ULine2 //unlinking first element?
  709. mov eax,[ebx].next
  710. mov localFirstSort,eax
  711. }
  712. _ULine2:
  713. __asm
  714. {
  715. mov edi,[ebx].next //edi = ebx.next
  716. mov ebx,[ebx].previous
  717. mov [edi].previous,ebx //ebx.next.prev = ebx.prev
  718. mov [ebx].next,edi //ebx.prev.next = ebx.next
  719. }
  720. _ULine3:
  721. __asm
  722. {
  723. // ecx = unchanged, the size of our block
  724. pop ebx // ebx -> our block we have just unlinked.
  725. pop edi // edi -> block to start our search on.
  726. mov edx,localFirstSort
  727. cmp [ebx].previous,edi
  728. je short __Line4 // search previous nodes
  729. }
  730. // stop when guy to the right is higher than us, or is the FirstMemBlock
  731. __Loop1:
  732. __asm
  733. {
  734. mov esi,edi
  735. mov edi,[edi].next
  736. cmp edi,edx //have we wrapped around?
  737. je short __FoundPlace
  738. cmp [edi].blockSize,ecx
  739. jae short __FoundPlace
  740. jmp __Loop1
  741. }
  742. __Line4:
  743. //stop when guy to the left is lower than us, or we stopped on the FirstMemBlock
  744. __Loop2:
  745. __asm
  746. {
  747. mov esi,edi
  748. mov edi,[edi].previous
  749. cmp esi,edx //have we wrapped around?
  750. je short __Line5
  751. cmp [edi].blockSize,ecx
  752. ja __Loop2
  753. }
  754. __Line5:
  755. __asm
  756. {
  757. xchg esi,edi
  758. }
  759. __FoundPlace: // esi-> first block, edi->second block, ebx -> us
  760. //ebx = offset of new block
  761. __asm
  762. {
  763. mov [ebx].previous,esi
  764. mov [ebx].next,edi
  765. mov [esi].next,ebx
  766. mov [edi].previous,ebx
  767. mov edi,edx
  768. cmp ecx,[edi].blockSize //see if we are now smallest
  769. jae short __Done
  770. mov localFirstSort,ebx //we are smallest
  771. }
  772. __Done:
  773. firstNearBlock = localFirstSort;
  774. //-------------------------------------------------------------------------------------
  775. //SORT Routine
  776. __asm
  777. {
  778. POPAD
  779. }
  780. #endif
  781. __asm
  782. {
  783. mov eax,edi
  784. jmp short Alloc_Done
  785. }
  786. //-----------------------------------------error handling
  787. Alloc_zero:
  788. __asm
  789. {
  790. mov eax,ALLOC_ZERO
  791. jmp short Alloc_error
  792. }
  793. Zero_Free:
  794. __asm
  795. {
  796. mov eax,NULL_FREE_LIST
  797. jmp short Alloc_error
  798. }
  799. Alloc_Overflow:
  800. __asm
  801. {
  802. mov eax,ALLOC_OVERFLOW
  803. }
  804. Alloc_error:
  805. __asm
  806. {
  807. mov errorResult,eax
  808. cmp mf,0
  809. // cmp [this].mallocFatals,0
  810. #ifdef CHECK_HEAP
  811. je noFatal
  812. #else
  813. jmp noFatal
  814. #endif
  815. }
  816. memCoreLeft = totalCoreLeft();
  817. memTotalLeft = coreLeft();
  818. walkHeap(TRUE,FALSE);
  819. if (memSize)
  820. STOP(("Heap %s is Out Of RAM. HeapSize %d, CoreLeft %d, TotalLeft %d, SizeTried %d",heapName,heapSize,memCoreLeft,memTotalLeft,memSize));
  821. else
  822. STOP(("Heap %s Tried to Malloc Zero Bytes!"));
  823. noFatal:
  824. __asm
  825. {
  826. mov eax,-8
  827. #ifdef _DEBUG
  828. mov eax,-12 //Make that extra room for who made me
  829. #endif
  830. }
  831. Alloc_Done:
  832. __asm
  833. {
  834. add eax,8 //skip over header
  835. #ifdef _DEBUG
  836. add eax,4 //Skip over extra for debugging
  837. #endif
  838. }
  839. #ifdef _DEBUG
  840. __asm
  841. {
  842. //if we allocated memory, store pointer to caller
  843. or eax,eax
  844. je NoAllocation
  845. mov ebx,ebp
  846. mov edx,dword ptr [ebx+4] // get caller
  847. mov [eax-4],edx //Store caller in HeapBlock
  848. }
  849. NoAllocation:
  850. #endif
  851. #ifdef HEAP_CHECK
  852. __asm
  853. {
  854. push eax
  855. }
  856. WalkHeap();
  857. __asm
  858. {
  859. pop eax
  860. }
  861. #endif
  862. __asm
  863. {
  864. mov result,eax
  865. }
  866. firstNearBlock = localFirst;
  867. #ifdef _DEBUG
  868. if (logMallocs)
  869. {
  870. recordCount++;
  871. gosASSERT (recordCount<NUMMEMRECORDS);
  872. recordArray[recordCount].ptr = result;
  873. recordArray[recordCount].size = memSize;
  874. CONTEXT ourContext;
  875. STACKFRAME sf;
  876. GetCurrentContext(&ourContext);
  877. InitStackWalk(&sf,&ourContext);
  878. for (long i=0;i<12;i++)
  879. {
  880. recordArray[recordCount].stack[i] = WalkStack(&sf);
  881. }
  882. }
  883. #endif
  884. return(result);
  885. }
  886. //---------------------------------------------------------------------------
  887. long UserHeap::Free (void *memBlock)
  888. {
  889. if (gosHeap)
  890. {
  891. gos_PushCurrentHeap( gosHeap );
  892. gos_Free(memBlock);
  893. gos_PopCurrentHeap();
  894. return 0;
  895. }
  896. HeapBlockPtr blockOffs = (HeapBlockPtr)memBlock;
  897. long result = 0;
  898. HeapBlockPtr sortBlock = NULL;
  899. //------------------------------------------
  900. // If freeing a NULL, we do nothing
  901. //------------------------------------------
  902. if (memBlock == NULL)
  903. return(NO_ERR);
  904. //-------------------------------------------------------------------
  905. // this is bad. However, for release, just let it go on the really
  906. // remote chance it happens.
  907. if ((memBlock < getHeapPtr()) || (memBlock >= (getHeapPtr() + totalSize)))
  908. {
  909. #ifdef _DEBUG
  910. PAUSE(("Tried to delete a bad pointer."));
  911. #endif
  912. return (NO_ERR);
  913. }
  914. __asm
  915. {
  916. cmp blockOffs,0
  917. je Dealloc_Done
  918. sub blockOffs,8 //compensate for heading
  919. #ifdef _DEBUG
  920. sub blockOffs,4 //extra return pointer
  921. #endif
  922. }
  923. //merge this block with lower one if possible
  924. long mergeResult = mergeWithLower(blockOffs);
  925. __asm
  926. {
  927. mov eax,mergeResult
  928. #ifdef SAFE_HEAP
  929. or eax,eax //return 0 on error
  930. je Dealloc_Done
  931. #endif
  932. //if block above is "free", add our size to it. no relinking is needed
  933. mov ebx,[blockOffs]
  934. mov edi,[ebx].upperBlock
  935. or edi,edi
  936. je short Relink_needed //no block above this one
  937. test [edi].blockSize,1
  938. jne short Relink_needed //block above is allocated
  939. //else just add size
  940. mov eax,[ebx].blockSize
  941. and eax,0xfffffffe //NOT 1
  942. add [edi].blockSize,eax //add to size of above block
  943. //inform new lower neighbor about the change
  944. mov ebx,edi
  945. add ebx,[edi].blockSize
  946. mov [ebx].upperBlock,edi
  947. #ifdef USE_BEST_FIT
  948. mov ebx,edi
  949. }
  950. //-------------------------------------------------------------------------------------
  951. //SORT Routine
  952. __asm
  953. {
  954. pushad
  955. }
  956. //-------------------------------------
  957. //see if we have to do any work at all
  958. HeapBlockPtr localFirstSort = firstNearBlock;
  959. __asm
  960. {
  961. mov edx,localFirstSort
  962. mov ecx,[ebx].blockSize
  963. mov edi,[ebx].next
  964. cmp edi,[ebx].previous
  965. jne short __Line1 //either 1 or two members in list
  966. cmp edi,ebx
  967. je __Done //only one member in list
  968. //else there are only two
  969. mov localFirstSort,ebx //assume we are the smaller block
  970. cmp ecx,[edi].blockSize
  971. jbe __Done //we were right
  972. mov localFirstSort,edi //else other guy is smaller
  973. jmp __Done
  974. }
  975. __Line1: // else see if we are not in the correct order
  976. __asm
  977. {
  978. cmp ecx,[edi].blockSize
  979. jbe short __Line2
  980. //else see if next guy in line is the localFirst
  981. cmp edi,edx //did we just compare with Beginning of list?
  982. jne short __Line3 //no
  983. }
  984. __Line2:
  985. __asm
  986. {
  987. mov edi,[ebx].previous
  988. cmp ecx,[edi].blockSize
  989. jae short __Done
  990. //else we are less than guy to our left
  991. cmp ebx,edx //are we the first block in list?
  992. je short __Done
  993. __Line3: //else we must unlink our block, saving a pointer to lower neighbor
  994. push edi
  995. push ebx
  996. //Unlink Routine inline here
  997. cmp [ebx].next,ebx
  998. jne short _ULine1
  999. //else list is now empty
  1000. mov localFirstSort,0
  1001. jmp short _ULine3
  1002. }
  1003. _ULine1:
  1004. __asm
  1005. {
  1006. mov edx,localFirstSort
  1007. cmp ebx,edx
  1008. jne short _ULine2 //unlinking first element?
  1009. mov eax,[ebx].next
  1010. mov localFirstSort,eax
  1011. }
  1012. _ULine2:
  1013. __asm
  1014. {
  1015. mov edi,[ebx].next //edi = ebx.next
  1016. mov ebx,[ebx].previous
  1017. mov [edi].previous,ebx //ebx.next.prev = ebx.prev
  1018. mov [ebx].next,edi //ebx.prev.next = ebx.next
  1019. }
  1020. _ULine3:
  1021. __asm
  1022. {
  1023. // ecx = unchanged, the size of our block
  1024. pop ebx // ebx -> our block we have just unlinked.
  1025. pop edi // edi -> block to start our search on.
  1026. mov edx,localFirstSort
  1027. cmp [ebx].previous,edi
  1028. je short __Line4 // search previous nodes
  1029. }
  1030. // stop when guy to the right is higher than us, or is the FirstMemBlock
  1031. __Loop1:
  1032. __asm
  1033. {
  1034. mov esi,edi
  1035. mov edi,[edi].next
  1036. cmp edi,edx //have we wrapped around?
  1037. je short __FoundPlace
  1038. cmp [edi].blockSize,ecx
  1039. jae short __FoundPlace
  1040. jmp __Loop1
  1041. }
  1042. __Line4:
  1043. //stop when guy to the left is lower than us, or we stopped on the FirstMemBlock
  1044. __Loop2:
  1045. __asm
  1046. {
  1047. mov esi,edi
  1048. mov edi,[edi].previous
  1049. cmp esi,edx //have we wrapped around?
  1050. je short __Line5
  1051. cmp [edi].blockSize,ecx
  1052. ja __Loop2
  1053. }
  1054. __Line5:
  1055. __asm
  1056. {
  1057. xchg esi,edi
  1058. }
  1059. __FoundPlace: // esi-> first block, edi->second block, ebx -> us
  1060. //ebx = offset of new block
  1061. __asm
  1062. {
  1063. mov [ebx].previous,esi
  1064. mov [ebx].next,edi
  1065. mov [esi].next,ebx
  1066. mov [edi].previous,ebx
  1067. mov edi,edx
  1068. cmp ecx,[edi].blockSize //see if we are now smallest
  1069. jae short __Done
  1070. mov localFirstSort,ebx //we are smallest
  1071. }
  1072. __Done:
  1073. firstNearBlock = localFirstSort;
  1074. //-------------------------------------------------------------------------------------
  1075. //SORT Routine
  1076. __asm
  1077. {
  1078. POPAD
  1079. }
  1080. __asm
  1081. {
  1082. #endif
  1083. jmp short Dealloc_Done
  1084. }
  1085. Relink_needed:
  1086. __asm
  1087. {
  1088. mov ebx,[blockOffs]
  1089. and [ebx].blockSize,0xfffffffe //NOT 1
  1090. mov sortBlock,ebx
  1091. }
  1092. relink(sortBlock);
  1093. Dealloc_Done:
  1094. #ifdef HEAP_CHECK
  1095. walkHeap(FALSE,FALSE," Free Heap Ck ");
  1096. #endif
  1097. __asm
  1098. {
  1099. mov result,eax
  1100. }
  1101. #ifdef _DEBUG
  1102. if (logMallocs)
  1103. {
  1104. long count = 0;
  1105. while (count<NUMMEMRECORDS && recordArray[count].ptr != memBlock)
  1106. count++;
  1107. //This may be OK? Not logging when allocated!
  1108. //gosASSERT (count < NUMMEMRECORDS);
  1109. recordArray[count].ptr = NULL;
  1110. recordArray[count].size = 0;
  1111. for (int i=0; i<12; i++)
  1112. recordArray[count].stack[i] = 0;
  1113. }
  1114. #endif
  1115. return(result);
  1116. }
  1117. //---------------------------------------------------------------------------
  1118. void * UserHeap::calloc (unsigned long memSize)
  1119. {
  1120. void * result = malloc(memSize);
  1121. memset(result,0,memSize);
  1122. return result;
  1123. }
  1124. //---------------------------------------------------------------------------
  1125. void UserHeap::walkHeap (bool printIt, bool skipAllocated)
  1126. {
  1127. if (gosHeap)
  1128. {
  1129. gos_WalkMemoryHeap(gosHeap);
  1130. return;
  1131. }
  1132. HeapBlockPtr walker = heapStart;
  1133. bool valid, allocated;
  1134. unsigned long bSize;
  1135. if (!walker || (heapState != NO_ERR))
  1136. return;
  1137. #ifdef _DEBUG
  1138. File logFile;
  1139. logFile.create("walkdump.log");
  1140. #endif
  1141. while (walker->blockSize != 1)
  1142. {
  1143. //--------------------
  1144. // check for validity
  1145. //--------------------
  1146. valid = TRUE;
  1147. if (walker->upperBlock)
  1148. {
  1149. bSize = (walker->upperBlock->blockSize & ~1);
  1150. bSize += (unsigned long)walker->upperBlock;
  1151. valid = (bSize == (unsigned long)walker);
  1152. }
  1153. if (valid)
  1154. {
  1155. bSize = (unsigned long)walker + (walker->blockSize & ~1);
  1156. valid = (HeapBlockPtr(bSize)->upperBlock == walker);
  1157. }
  1158. else
  1159. {
  1160. //--------------------------
  1161. // Failed upper block check
  1162. //--------------------------
  1163. heapState = HEAP_CORRUPTED;
  1164. STOP(("Heap %s Upper Block Check Failed",heapName));
  1165. return;
  1166. }
  1167. if (valid && !(walker->blockSize & 1)) // if free block
  1168. {
  1169. valid = ((walker->previous->next == walker) &&
  1170. (walker->next->previous == walker));
  1171. }
  1172. else if (!valid)
  1173. {
  1174. //--------------------------
  1175. // Failed lower block check
  1176. //--------------------------
  1177. heapState = HEAP_CORRUPTED;
  1178. STOP(("Heap %s Lower Block Check Failed",heapName));
  1179. return;
  1180. }
  1181. if (!valid)
  1182. {
  1183. //--------------------------
  1184. // Failed linked list check
  1185. //--------------------------
  1186. heapState = HEAP_CORRUPTED;
  1187. STOP(("Heap %s LinkedList Check Failed",heapName));
  1188. return;
  1189. }
  1190. allocated = walker->blockSize & 1;
  1191. if ((printIt && !allocated) || (printIt && !skipAllocated))
  1192. {
  1193. char errMessage[256];
  1194. #ifdef _DEBUG
  1195. if (allocated)
  1196. {
  1197. sprintf(errMessage, "Allocated block at DS:%08X, size = %u, owner at CS:%08X\n",
  1198. walker,(walker->blockSize & ~1),walker->previous);
  1199. //--------------------------------------------------------------------------------------------
  1200. // A size and/or address check can be put here to inspect the block and determine other info
  1201. long magicNumber = 0x6726FB;
  1202. if ((walker->previous) == (void*)magicNumber)
  1203. printf("magicNumber");
  1204. //--------------------------------------------------------------------------------------------
  1205. }
  1206. else
  1207. {
  1208. sprintf(errMessage, "Free block at DS:%08X, size = %u \n", walker,(walker->blockSize & ~1));
  1209. }
  1210. #ifndef _CONSOLE
  1211. logFile.writeLine(errMessage);
  1212. #else
  1213. printf(errMessage);
  1214. #endif
  1215. #else
  1216. sprintf(errMessage, "%s block at DS:%08X, size = %u \n",
  1217. (allocated)?"Allocated":"Free",walker,(walker->blockSize & ~1));
  1218. #ifndef _CONSOLE
  1219. OutputDebugString(errMessage);
  1220. #else
  1221. printf(errMessage);
  1222. #endif
  1223. #endif
  1224. }
  1225. walker = HeapBlockPtr((unsigned long)walker + (walker->blockSize & ~1));
  1226. }
  1227. }
  1228. //---------------------------------------------------------------------------
  1229. long UserHeap::getLastError (void)
  1230. {
  1231. return heapState;
  1232. }
  1233. //---------------------------------------------------------------------------
  1234. void UserHeap::relink (HeapBlockPtr newBlock)
  1235. {
  1236. HeapBlockPtr localFirst = firstNearBlock;
  1237. //empty list?
  1238. __asm
  1239. {
  1240. mov ebx, newBlock
  1241. cmp localFirst,0
  1242. jne short Line1
  1243. //else this is the only block in the list
  1244. mov localFirst,ebx
  1245. mov [ebx].previous,ebx
  1246. mov [ebx].next,ebx
  1247. jmp short Line2
  1248. }
  1249. Line1:
  1250. __asm
  1251. {
  1252. //ebx = address of new block
  1253. mov edi,localFirst
  1254. #ifdef USE_BEST_FIT
  1255. mov edx,edi
  1256. mov ecx,[ebx].blockSize
  1257. cmp ecx,[edi].blockSize
  1258. jae short Line3
  1259. mov localFirst,ebx
  1260. jmp short Line4
  1261. }
  1262. Line3:
  1263. __asm
  1264. {
  1265. mov edi,[edi].next
  1266. cmp edi,edx
  1267. je short Line4
  1268. cmp ecx,[edi].blockSize
  1269. ja Line3
  1270. }
  1271. Line4:
  1272. __asm
  1273. {
  1274. mov edi,[edi].previous
  1275. #endif
  1276. mov eax,[edi].next
  1277. mov [ebx].next,eax
  1278. mov [ebx].previous,edi
  1279. mov [edi].next,ebx
  1280. mov edi,[ebx].next
  1281. mov [edi].previous,ebx
  1282. }
  1283. Line2:
  1284. firstNearBlock = localFirst;
  1285. }
  1286. //---------------------------------------------------------------------------
  1287. void UserHeap::unlink (HeapBlockPtr oldBlock)
  1288. {
  1289. HeapBlockPtr localFirst = firstNearBlock;
  1290. __asm
  1291. {
  1292. mov ebx,oldBlock
  1293. cmp [ebx].next,ebx
  1294. jne short ULine1
  1295. //else list is now empty
  1296. mov localFirst,0
  1297. jmp short ULine3
  1298. }
  1299. ULine1:
  1300. __asm
  1301. {
  1302. mov edx,localFirst
  1303. cmp ebx,edx
  1304. jne short ULine2 //unlinking first element?
  1305. mov eax,[ebx].next
  1306. mov localFirst,eax
  1307. }
  1308. ULine2:
  1309. __asm
  1310. {
  1311. mov edi,[ebx].next //edi = ebx.next
  1312. mov ebx,[ebx].previous
  1313. mov [edi].previous,ebx //ebx.next.prev = ebx.prev
  1314. mov [ebx].next,edi //ebx.prev.next = ebx.next
  1315. }
  1316. ULine3:
  1317. firstNearBlock = localFirst;
  1318. }
  1319. //---------------------------------------------------------------------------
  1320. bool UserHeap::mergeWithLower (HeapBlockPtr block)
  1321. {
  1322. HeapBlockPtr localFirst = firstNearBlock;
  1323. bool result = FALSE;
  1324. __asm
  1325. {
  1326. mov edi,block
  1327. mov ebx,[edi].blockSize
  1328. }
  1329. #ifdef SAFE_HEAP
  1330. __asm
  1331. {
  1332. test ebx,1
  1333. je short Fatal1 //else failed alloc check
  1334. cmp [edi+ebx-1].upperBlock,edi
  1335. jne short Fatal1 //else failed lower check
  1336. mov esi,[edi].upperBlock
  1337. or esi,esi
  1338. je short check_ok
  1339. add esi,[esi].blockSize
  1340. and esi,0xfffffffe //NOT 1
  1341. cmp esi,edi
  1342. je short check_ok
  1343. }
  1344. Fatal1:
  1345. walkHeap(FALSE,FALSE);
  1346. //Fatal(HEAP_CORRUPTED);
  1347. __asm
  1348. {
  1349. xor eax,eax //In theory, this will never execute since the Fatal Exits
  1350. jmp DoneML //Maybe if Fatal is not operating?
  1351. }
  1352. check_ok:
  1353. #endif
  1354. __asm
  1355. {
  1356. and ebx,0xfffffffe //NOT 1 //make size be acurate
  1357. mov esi,ebx
  1358. add esi,edi //esi = offset of lower neighbor
  1359. mov ecx,[esi].blockSize
  1360. test ecx,1
  1361. jne short NoMerge //lower block is allocated
  1362. add ebx,ecx //ebx = new size of block
  1363. mov [edi].blockSize,ebx
  1364. or [edi].blockSize,1 //dealloc() expects allocated block
  1365. mov eax,edi
  1366. add ebx,eax //ebx -> new lower neigbor
  1367. mov [ebx].upperBlock,edi //inform new neighbor about the change
  1368. mov ebx,esi //ebx = offset of old lower neighbor
  1369. }
  1370. //This is the UNLINK routine directly.
  1371. __asm
  1372. {
  1373. cmp [ebx].next,ebx
  1374. jne short ULine1
  1375. //else list is now empty
  1376. mov localFirst,0
  1377. jmp short ULine3
  1378. }
  1379. ULine1:
  1380. __asm
  1381. {
  1382. mov edx,localFirst
  1383. cmp ebx,edx
  1384. jne short ULine2 //unlinking first element?
  1385. mov eax,[ebx].next
  1386. mov localFirst,eax
  1387. }
  1388. ULine2:
  1389. __asm
  1390. {
  1391. mov edi,[ebx].next //edi = bx.next
  1392. mov ebx,[ebx].previous
  1393. mov [edi].previous,ebx //ebx.next.prev = ebx.prev
  1394. mov [ebx].next,edi //ebx.prev.next = bx.next
  1395. }
  1396. ULine3:
  1397. NoMerge:
  1398. __asm
  1399. {
  1400. mov eax,1 //Return TRUE
  1401. }
  1402. #ifdef SAFE_HEAP
  1403. DoneML:
  1404. #endif
  1405. __asm
  1406. {
  1407. mov result,al //Move eax into result
  1408. }
  1409. firstNearBlock = localFirst;
  1410. return(result);
  1411. }
  1412. //---------------------------------------------------------------------------
  1413. void HeapList::addHeap (HeapManagerPtr newHeap)
  1414. {
  1415. for (long i=0;i<MAX_HEAPS;i++)
  1416. {
  1417. if (heapRecords[i].thisHeap == NULL)
  1418. {
  1419. heapRecords[i].thisHeap = newHeap;
  1420. heapRecords[i].heapSize = newHeap->tSize();
  1421. return;
  1422. }
  1423. }
  1424. }
  1425. //---------------------------------------------------------------------------
  1426. void HeapList::removeHeap (HeapManagerPtr oldHeap)
  1427. {
  1428. for (long i=0;i<MAX_HEAPS;i++)
  1429. {
  1430. if (heapRecords[i].thisHeap == oldHeap)
  1431. {
  1432. heapRecords[i].thisHeap = NULL;
  1433. heapRecords[i].heapSize = 0;
  1434. return;
  1435. }
  1436. }
  1437. }
  1438. void HeapList::initializeStatistics()
  1439. {
  1440. if (heapInstrumented == 0)
  1441. {
  1442. StatisticFormat( "" );
  1443. StatisticFormat( "MechCommander 2 Heaps" );
  1444. StatisticFormat( "======================" );
  1445. StatisticFormat( "" );
  1446. AddStatistic("Total Memory","bytes",gos_DWORD, &(totalSize), Stat_AutoReset | Stat_Total);
  1447. AddStatistic("Total Memory Core Left","bytes",gos_DWORD, &(totalCoreLeft), Stat_AutoReset | Stat_Total);
  1448. AddStatistic("Total Memory Left","bytes",gos_DWORD, &(totalLeft), Stat_AutoReset | Stat_Total);
  1449. StatisticFormat( "" );
  1450. StatisticFormat( "" );
  1451. for (long i=0;i<50;i++)
  1452. {
  1453. char heapString[255];
  1454. sprintf(heapString,"Heap %d - HeapSize",i);
  1455. AddStatistic(heapString,"bytes",gos_DWORD, &(heapRecords[i].heapSize), Stat_AutoReset | Stat_Total);
  1456. sprintf(heapString,"Heap %d - TotalLeft",i);
  1457. AddStatistic(heapString,"bytes",gos_DWORD, &(heapRecords[i].totalCoreLeft), Stat_AutoReset | Stat_Total);
  1458. sprintf(heapString,"Heap %d - CoreLeft",i);
  1459. AddStatistic(heapString,"bytes",gos_DWORD, &(heapRecords[i].coreLeft), Stat_AutoReset | Stat_Total);
  1460. StatisticFormat( "" );
  1461. }
  1462. heapInstrumented = true;
  1463. }
  1464. }
  1465. //---------------------------------------------------------------------------
  1466. void HeapList::update (void)
  1467. {
  1468. totalSize = totalCoreLeft = totalLeft = 0;
  1469. for (long i=0;i<50;i++)
  1470. {
  1471. if (heapRecords[i].thisHeap && (heapRecords[i].thisHeap->heapType() == USER_HEAP))
  1472. {
  1473. heapRecords[i].heapSize = ((UserHeapPtr)heapRecords[i].thisHeap)->tSize();
  1474. totalSize += heapRecords[i].heapSize;
  1475. heapRecords[i].coreLeft = ((UserHeapPtr)heapRecords[i].thisHeap)->coreLeft();
  1476. totalLeft += heapRecords[i].coreLeft;
  1477. heapRecords[i].totalCoreLeft = ((UserHeapPtr)heapRecords[i].thisHeap)->totalCoreLeft();
  1478. totalCoreLeft += heapRecords[i].totalCoreLeft;
  1479. }
  1480. else if (heapRecords[i].thisHeap)
  1481. {
  1482. heapRecords[i].heapSize = heapRecords[i].thisHeap->tSize();
  1483. totalSize += heapRecords[i].heapSize;
  1484. heapRecords[i].coreLeft = 0;
  1485. heapRecords[i].totalCoreLeft = 0;
  1486. }
  1487. }
  1488. }
  1489. //---------------------------------------------------------------------------
  1490. unsigned long textToLong (char *num)
  1491. {
  1492. long result = 0;
  1493. char *hexOffset = num;
  1494. hexOffset += 2;
  1495. long numDigits = strlen(hexOffset)-1;
  1496. long power = 0;
  1497. for (long count = numDigits;count >= 0;count--,power++)
  1498. {
  1499. unsigned char currentDigit = toupper(hexOffset[count]);
  1500. if (currentDigit >= 'A' && currentDigit <= 'F')
  1501. {
  1502. result += (currentDigit - 'A' + 10)<<(4*power);
  1503. }
  1504. else if (currentDigit >= '0' && currentDigit <= '9')
  1505. {
  1506. result += (currentDigit - '0')<<(4*power);
  1507. }
  1508. else
  1509. {
  1510. //---------------------------------------------------------
  1511. // There is a digit in here I don't understand. Return 0.
  1512. result = 0;
  1513. break;
  1514. }
  1515. }
  1516. return(result);
  1517. }
  1518. //-----------------------------------------------------------
  1519. long longToText (char *result, long num, unsigned long bufLen)
  1520. {
  1521. char temp[250];
  1522. sprintf(temp,"%08X",num);
  1523. unsigned long numLength = strlen(temp);
  1524. if (numLength >= bufLen)
  1525. return(0);
  1526. strncpy(result,temp,numLength);
  1527. result[numLength] = '\0';
  1528. return(NO_ERR);
  1529. }
  1530. //--------------------------------------------------------------------------
  1531. long getStringFromMap (File &mapFile, unsigned long addr, char *result)
  1532. {
  1533. //----------------------------------------
  1534. // Convert function address to raw offset
  1535. #ifdef TERRAINEDIT
  1536. unsigned long offsetAdd = 0x00601000;
  1537. #else
  1538. unsigned long offsetAdd = 0x00601000;
  1539. #endif
  1540. unsigned long function = addr;
  1541. function -= offsetAdd;
  1542. char actualAddr[10];
  1543. longToText(actualAddr,function,9);
  1544. //------------------------------------
  1545. // Find the first code entry address.
  1546. // This is the first line encountered with " Address" as the first nine characters.
  1547. char mapFileLine[512];
  1548. mapFile.seek(0);
  1549. mapFile.readLine((MemoryPtr)mapFileLine,511);
  1550. while (strstr(mapFileLine," Address") == NULL)
  1551. {
  1552. mapFile.readLine((MemoryPtr)mapFileLine,511);
  1553. }
  1554. mapFile.readLine((MemoryPtr)mapFileLine,511);
  1555. mapFile.readLine((MemoryPtr)mapFileLine,511);
  1556. //-------------------------------------------------------------
  1557. // We've found the first code entry. Now, scan until
  1558. // the current address is greater than the address asked for.
  1559. // The previous function name is the function in question.
  1560. char *currentAddress = &(mapFileLine[6]);
  1561. char previousAddress[511];
  1562. strncpy(previousAddress,&(mapFileLine[6]),510);
  1563. while (strstr(mapFileLine,"0001:") != NULL)
  1564. {
  1565. if (strnicmp(currentAddress,actualAddr,8) > 0)
  1566. {
  1567. //-----------------------------------------------
  1568. // We've found it, print the previous address.
  1569. strncpy(result,previousAddress,510);
  1570. return(strlen(result));
  1571. }
  1572. strncpy(previousAddress,&(mapFileLine[6]),510);
  1573. mapFile.readLine((MemoryPtr)mapFileLine,511);
  1574. }
  1575. return(0);
  1576. }
  1577. //---------------------------------------------------------------------------
  1578. void HeapList::dumpLog (void)
  1579. {
  1580. //----------------------------------------------
  1581. // This function dumps information on each heap
  1582. // to a log file.
  1583. File logFile;
  1584. logFile.create("heap.dump.log");
  1585. File mapFile;
  1586. long mapResult = 0;
  1587. #ifdef _DEBUG
  1588. #ifdef TERRAINEDIT
  1589. mapResult = mapFile.open("teditor.map");
  1590. #else
  1591. mapResult = mapFile.open("mechcmdrdbg.map");
  1592. #endif
  1593. #endif
  1594. HeapManagerPtr currentHeap = NULL;
  1595. unsigned long heapNumber = 1;
  1596. unsigned long mapStringSize = 0;
  1597. char msg[1024];
  1598. char mapInfo[513];
  1599. unsigned long totalCommit = 0;
  1600. unsigned long totalFree = 0;
  1601. for (long i=0;i<MAX_HEAPS;i++)
  1602. {
  1603. currentHeap = heapRecords[i].thisHeap;
  1604. if (currentHeap)
  1605. {
  1606. sprintf(msg,"ListNo: %d Heap: %d Type: %d Made by: %08X",i,heapNumber,currentHeap->heapType(),currentHeap->owner());
  1607. logFile.writeLine(msg);
  1608. if (mapResult == NO_ERR)
  1609. {
  1610. mapStringSize = getStringFromMap(mapFile,currentHeap->owner(),mapInfo);
  1611. if (mapStringSize)
  1612. {
  1613. sprintf(msg,"Made in Function : %s",mapInfo);
  1614. logFile.writeLine(msg);
  1615. }
  1616. }
  1617. sprintf(msg,"HeapSize: %d HeapStart: %08X",currentHeap->tSize(),currentHeap->getHeapPtr());
  1618. logFile.writeLine(msg);
  1619. totalCommit += currentHeap->tSize();
  1620. if (currentHeap->heapType() == 1)
  1621. {
  1622. UserHeapPtr userHeap = (UserHeapPtr)currentHeap;
  1623. sprintf(msg,"TotalCoreLeft: %d CoreLeft: %d",userHeap->totalCoreLeft(),userHeap->coreLeft());
  1624. logFile.writeLine(msg);
  1625. sprintf(msg,"Frag Level: %f PercentFree: %f",(float(userHeap->coreLeft())/float(userHeap->totalCoreLeft())),1.0 - (float(currentHeap->tSize()-userHeap->coreLeft())/float(currentHeap->tSize())) );
  1626. logFile.writeLine(msg);
  1627. totalFree += userHeap->coreLeft();
  1628. }
  1629. currentHeap = currentHeap->nxt;
  1630. heapNumber++;
  1631. }
  1632. else
  1633. {
  1634. sprintf(msg,"ListNo: %d is Freed",i);
  1635. logFile.writeLine(msg);
  1636. }
  1637. sprintf(msg,"---------------------------");
  1638. logFile.writeLine(msg);
  1639. }
  1640. sprintf(msg,"Total Committed Memory: %d Total Free in Commit: %d",totalCommit,totalFree);
  1641. logFile.writeLine(msg);
  1642. sprintf(msg,"---------------------------");
  1643. logFile.writeLine(msg);
  1644. logFile.close();
  1645. }
  1646. bool UserHeap::pointerOnHeap (void *ptr)
  1647. {
  1648. if (IsBadReadPtr(getHeapPtr(),totalSize))
  1649. return false;
  1650. if ((ptr < getHeapPtr()) || (ptr >= (getHeapPtr() + totalSize)))
  1651. return false;
  1652. return true;
  1653. }
  1654. //---------------------------------------------------------------------------
  1655. //
  1656. // Edit Log
  1657. //
  1658. //---------------------------------------------------------------------------