PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/polyml.5.4.1/libpolyml/memmgr.cpp

#
C++ | 449 lines | 335 code | 39 blank | 75 comment | 70 complexity | 0c34435b4aa992f8320c693739132636 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0
  1. /*
  2. Title: memmgr.cpp Memory segment manager
  3. Copyright (c) 2006-7 David C. J. Matthews
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #elif defined(WIN32)
  19. #include "winconfig.h"
  20. #else
  21. #error "No configuration file"
  22. #endif
  23. #ifdef HAVE_ASSERT_H
  24. #include <assert.h>
  25. #define ASSERT(x) assert(x)
  26. #else
  27. #define ASSERT(x)
  28. #endif
  29. #include "globals.h"
  30. #include "memmgr.h"
  31. #include "osmem.h"
  32. #include "scanaddrs.h"
  33. #include "bitmap.h"
  34. MemSpace::MemSpace()
  35. {
  36. spaceType = ST_PERMANENT;
  37. isMutable = false;
  38. bottom = 0;
  39. top = 0;
  40. isOwnSpace = false;
  41. }
  42. MemSpace::~MemSpace()
  43. {
  44. if (isOwnSpace && bottom != 0)
  45. osMemoryManager->Free(bottom, (char*)top - (char*)bottom);
  46. }
  47. LocalMemSpace::LocalMemSpace()
  48. {
  49. spaceType = ST_LOCAL;
  50. gen_top = 0;
  51. gen_bottom = 0;
  52. highest = 0;
  53. pointer = 0;
  54. for (unsigned i = 0; i < NSTARTS; i++)
  55. start[i] = 0;
  56. start_index = 0;
  57. i_marked = m_marked = copied = updated = 0;
  58. }
  59. bool LocalMemSpace::InitSpace(POLYUNSIGNED size, bool mut)
  60. {
  61. isMutable = mut;
  62. // Allocate the heap itself.
  63. size_t iSpace = size*sizeof(PolyWord);
  64. bottom =
  65. (PolyWord*)osMemoryManager->Allocate(iSpace, PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC);
  66. if (bottom == 0)
  67. return false;
  68. isOwnSpace = true; // Deallocate when we're finished.
  69. // The size may have been rounded up to a block boundary.
  70. size = iSpace/sizeof(PolyWord);
  71. top = bottom + size;
  72. gen_top = top;
  73. pointer = top;
  74. gen_bottom = top;
  75. // Bitmap for the space.
  76. return bitmap.Create(size);
  77. }
  78. MemMgr::MemMgr()
  79. {
  80. npSpaces = nlSpaces = 0;
  81. minLocal = maxLocal = 0;
  82. pSpaces = 0;
  83. lSpaces = 0;
  84. eSpaces = 0;
  85. nextIndex = 0;
  86. }
  87. MemMgr::~MemMgr()
  88. {
  89. unsigned i;
  90. for (i = 0; i < npSpaces; i++)
  91. delete(pSpaces[i]);
  92. for (i = 0; i < nlSpaces; i++)
  93. delete(lSpaces[i]);
  94. for (i = 0; i < neSpaces; i++)
  95. delete(eSpaces[i]);
  96. }
  97. // Create and initialise a new local space and add it to the table.
  98. LocalMemSpace* MemMgr::NewLocalSpace(POLYUNSIGNED size, bool mut)
  99. {
  100. LocalMemSpace *space = new LocalMemSpace;
  101. if (space->InitSpace(size, mut) && AddLocalSpace(space))
  102. return space;
  103. // If something went wrong.
  104. delete space;
  105. return 0;
  106. }
  107. // Add a local memory space to the table.
  108. bool MemMgr::AddLocalSpace(LocalMemSpace *space)
  109. {
  110. // Compute the maximum and minimum local addresses. The idea
  111. // is to speed up LocalSpaceForAddress which is likely to be a hot-spot
  112. // in the GC.
  113. if (nlSpaces == 0)
  114. {
  115. // First space
  116. minLocal = space->bottom;
  117. maxLocal = space->top;
  118. }
  119. else
  120. {
  121. if (space->bottom < minLocal)
  122. minLocal = space->bottom;
  123. if (space->top > maxLocal)
  124. maxLocal = space->top;
  125. }
  126. // Add to the table.
  127. LocalMemSpace **table = (LocalMemSpace **)realloc(lSpaces, (nlSpaces+1) * sizeof(LocalMemSpace *));
  128. if (table == 0) return false;
  129. lSpaces = table;
  130. lSpaces[nlSpaces++] = space;
  131. return true;
  132. }
  133. // Create an entry for a permanent space.
  134. PermanentMemSpace* MemMgr::NewPermanentSpace(PolyWord *base, POLYUNSIGNED words,
  135. bool mut, bool noOv, unsigned index, unsigned hierarchy /*= 0*/)
  136. {
  137. PermanentMemSpace *space = new PermanentMemSpace;
  138. space->bottom = base;
  139. space->topPointer = space->top = space->bottom + words;
  140. space->spaceType = ST_PERMANENT;
  141. space->isMutable = mut;
  142. space->noOverwrite = noOv;
  143. space->index = index;
  144. space->hierarchy = hierarchy;
  145. if (index >= nextIndex) nextIndex = index+1;
  146. // Extend the permanent memory table and add this space to it.
  147. PermanentMemSpace **table =
  148. (PermanentMemSpace **)realloc(pSpaces, (npSpaces+1) * sizeof(PermanentMemSpace *));
  149. if (table == 0)
  150. {
  151. delete space;
  152. return 0;
  153. }
  154. pSpaces = table;
  155. pSpaces[npSpaces++] = space;
  156. return space;
  157. }
  158. // Delete a local space and remove it from the table.
  159. bool MemMgr::DeleteLocalSpace(LocalMemSpace *sp)
  160. {
  161. for (unsigned i = 0; i < nlSpaces; i++)
  162. {
  163. if (lSpaces[i] == sp)
  164. {
  165. delete sp;
  166. nlSpaces--;
  167. while (i < nlSpaces)
  168. {
  169. lSpaces[i] = lSpaces[i+1];
  170. i++;
  171. }
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. // Create an entry for the IO space.
  178. MemSpace* MemMgr::InitIOSpace(PolyWord *base, POLYUNSIGNED words)
  179. {
  180. ioSpace.bottom = base;
  181. ioSpace.top = ioSpace.bottom + words;
  182. ioSpace.spaceType = ST_IO;
  183. ioSpace.isMutable = false;
  184. return &ioSpace;
  185. }
  186. // Create and initialise a new export space and add it to the table.
  187. PermanentMemSpace* MemMgr::NewExportSpace(POLYUNSIGNED size, bool mut, bool noOv)
  188. {
  189. PermanentMemSpace *space = new PermanentMemSpace;
  190. space->spaceType = ST_EXPORT;
  191. space->isMutable = mut;
  192. space->noOverwrite = noOv;
  193. space->index = nextIndex++;
  194. // Allocate the memory itself.
  195. size_t iSpace = size*sizeof(PolyWord);
  196. space->bottom =
  197. (PolyWord*)osMemoryManager->Allocate(iSpace, PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC);
  198. if (space->bottom == 0)
  199. {
  200. delete space;
  201. return 0;
  202. }
  203. space->isOwnSpace = true;
  204. // The size may have been rounded up to a block boundary.
  205. size = iSpace/sizeof(PolyWord);
  206. space->top = space->bottom + size;
  207. space->topPointer = space->bottom;
  208. // Add to the table.
  209. PermanentMemSpace **table = (PermanentMemSpace **)realloc(eSpaces, (neSpaces+1) * sizeof(PermanentMemSpace *));
  210. if (table == 0)
  211. {
  212. delete space;
  213. return 0;
  214. }
  215. eSpaces = table;
  216. eSpaces[neSpaces++] = space;
  217. return space;
  218. }
  219. void MemMgr::DeleteExportSpaces(void)
  220. {
  221. while (neSpaces > 0)
  222. delete(eSpaces[--neSpaces]);
  223. }
  224. // If we have saved the state rather than exported a function we turn the exported
  225. // spaces into permanent ones, removing existing permanent spaces at the same or
  226. // lower level.
  227. bool MemMgr::PromoteExportSpaces(unsigned hierarchy)
  228. {
  229. // Create a new table big enough to hold all the permanent and export spaces
  230. PermanentMemSpace **pTable =
  231. (PermanentMemSpace **)calloc(npSpaces+neSpaces, sizeof(PermanentMemSpace *));
  232. if (pTable == 0) return false;
  233. unsigned newSpaces = 0;
  234. // Save permanent spaces at a lower hierarchy. Others are converted into
  235. // local spaces. Most or all items will have been copied from these spaces
  236. // into an export space but there could be items reachable only from the stack.
  237. for (unsigned i = 0; i < npSpaces; i++)
  238. {
  239. PermanentMemSpace *pSpace = pSpaces[i];
  240. if (pSpace->hierarchy < hierarchy)
  241. pTable[newSpaces++] = pSpace;
  242. else
  243. {
  244. // Turn this into a local space.
  245. LocalMemSpace *space = new LocalMemSpace;
  246. space->top = space->gen_top = space->gen_bottom = pSpace->top;
  247. space->bottom = space->pointer = pSpace->bottom;
  248. space->isMutable = pSpace->isMutable;
  249. space->isOwnSpace = true;
  250. if (! space->bitmap.Create(space->top-space->bottom) || ! AddLocalSpace(space))
  251. return false;
  252. }
  253. }
  254. // Save newly exported spaces.
  255. for (unsigned j = 0; j < neSpaces; j++)
  256. {
  257. PermanentMemSpace *space = eSpaces[j];
  258. space->hierarchy = hierarchy; // Set the hierarchy of the new spaces.
  259. space->spaceType = ST_PERMANENT;
  260. // Put a dummy object to fill up the unused space.
  261. if (space->topPointer != space->top)
  262. FillUnusedSpace(space->topPointer, space->top - space->topPointer);
  263. // Put in a dummy object to fill the rest of the space.
  264. pTable[newSpaces++] = space;
  265. }
  266. neSpaces = 0;
  267. npSpaces = newSpaces;
  268. free(pSpaces);
  269. pSpaces = pTable;
  270. return true;
  271. }
  272. // Before we import a hierarchical saved state we need to turn any previously imported
  273. // spaces into local spaces.
  274. bool MemMgr::DemoteImportSpaces()
  275. {
  276. // Create a new permanent space table.
  277. PermanentMemSpace **table =
  278. (PermanentMemSpace **)calloc(npSpaces, sizeof(PermanentMemSpace *));
  279. if (table == NULL) return false;
  280. unsigned newSpaces = 0;
  281. for (unsigned i = 0; i < npSpaces; i++)
  282. {
  283. PermanentMemSpace *pSpace = pSpaces[i];
  284. if (pSpace->hierarchy == 0) // Leave truly permanent spaces
  285. table[newSpaces++] = pSpace;
  286. else
  287. {
  288. // Turn this into a local space.
  289. LocalMemSpace *space = new LocalMemSpace;
  290. space->top = pSpace->top;
  291. // Space is allocated in local areas from the top down. This area is full and
  292. // all data is in the old generation. The area can be recovered by a full GC.
  293. space->bottom = space->pointer = space->gen_top = space->gen_bottom = pSpace->bottom;
  294. space->isMutable = pSpace->isMutable;
  295. space->isOwnSpace = true;
  296. if (! space->bitmap.Create(space->top-space->bottom) || ! AddLocalSpace(space))
  297. return false;
  298. }
  299. }
  300. npSpaces = newSpaces;
  301. free(pSpaces);
  302. pSpaces = table;
  303. return true;
  304. }
  305. // Return the space the address is in or NULL if none.
  306. // We have to check here against the bottom of the area rather
  307. // than the allocation because, when called from CopyObject,
  308. // the "pointer" field points to the top of the area.
  309. // N.B. By checking for pt < space->top we are assuming that we don't have
  310. // zero length objects. A zero length object at the top of the space would
  311. // have its length word as the last word in the space and the address of the
  312. // object would be == space->top.
  313. MemSpace *MemMgr::SpaceForAddress(const void *pt)
  314. {
  315. unsigned i;
  316. for (i = 0; i < nlSpaces; i++)
  317. {
  318. MemSpace *space = lSpaces[i];
  319. if (pt >= space->bottom && pt < space->top)
  320. return space;
  321. }
  322. for (i = 0; i < npSpaces; i++)
  323. {
  324. MemSpace *space = pSpaces[i];
  325. if (pt >= space->bottom && pt < space->top)
  326. return space;
  327. }
  328. for (i = 0; i < neSpaces; i++)
  329. {
  330. MemSpace *space = eSpaces[i];
  331. if (pt >= space->bottom && pt < space->top)
  332. return space;
  333. }
  334. if (pt >= ioSpace.bottom && pt < ioSpace.top)
  335. return &ioSpace;
  336. return 0; // Not in any space
  337. }
  338. bool MemMgr::IsPermanentMemoryPointer(const void *pt)
  339. {
  340. for (unsigned i = 0; i < npSpaces; i++)
  341. {
  342. MemSpace *space = pSpaces[i];
  343. if (pt >= space->bottom && pt < space->top)
  344. return true;
  345. }
  346. return false;
  347. }
  348. // Return the space for a given index
  349. PermanentMemSpace *MemMgr::SpaceForIndex(unsigned index)
  350. {
  351. for (unsigned i = 0; i < npSpaces; i++)
  352. {
  353. PermanentMemSpace *space = pSpaces[i];
  354. if (space->index == index)
  355. return space;
  356. }
  357. return NULL;
  358. }
  359. // In several places we assume that segments are filled with valid
  360. // objects. This fills unused memory with one or more "byte" objects.
  361. void MemMgr::FillUnusedSpace(PolyWord *base, POLYUNSIGNED words)
  362. {
  363. PolyWord *pDummy = base+1;
  364. while (words > 0)
  365. {
  366. POLYUNSIGNED oSize = words;
  367. // If the space is larger than the maximum object size
  368. // we will need several objects.
  369. if (words > MAX_OBJECT_SIZE) oSize = MAX_OBJECT_SIZE;
  370. else oSize = words-1;
  371. // Make this a byte object so it's always skipped.
  372. ((PolyObject*)pDummy)->SetLengthWord(oSize, F_BYTE_OBJ);
  373. words -= oSize+1;
  374. pDummy += oSize+1;
  375. }
  376. }
  377. // Allocate an area of the heap of at least minWords and at most maxWords.
  378. // This is used both when allocating single objects (when minWords and maxWords
  379. // are the same) and when allocating heap segments. If there is insufficient
  380. // space to satisfy the minimum it will return 0.
  381. PolyWord *MemMgr::AllocHeapSpace(POLYUNSIGNED minWords, POLYUNSIGNED &maxWords)
  382. {
  383. allocLock.Lock();
  384. for (unsigned j = 0; j < gMem.nlSpaces; j++)
  385. {
  386. LocalMemSpace *space = gMem.lSpaces[j];
  387. if (space->isMutable)
  388. {
  389. POLYUNSIGNED available = space->pointer - space->bottom;
  390. if (available > 0 && available >= minWords)
  391. {
  392. // Reduce the maximum value if we had less than that.
  393. if (available < maxWords)
  394. maxWords = available;
  395. space->pointer -= maxWords; // Allocate it.
  396. PolyWord *result = space->pointer; // Return the address.
  397. allocLock.Unlock();
  398. return result;
  399. }
  400. }
  401. }
  402. allocLock.Unlock();
  403. return 0; // There isn't space even for the minimum.
  404. }
  405. MemMgr gMem; // The one and only memory manager object