[Vm-dev] mmap, changes to co-ordinate mapping to particular address to avoid oops address remapping at startup time.

John M McIntosh johnmci at smalltalkconsulting.com
Sat Oct 11 04:36:51 UTC 2008

In the past year or so there has been discussion of using mmap to set  
a start address for the offset of object memory so that memory address  
swizzling does not occur.
Also various operating systems vendors say using mmap to page in large  
files is faster than using fread, this in fact is true and noticeable  
on the iPhone.

This requires a change to VMMaker so that sqAllocateMemory can pass  
the file pointer and the header size, since in the
sqAllocateMemory we need to figure out the file (image size) and also  
understand the headersize of the image file to return a proper address  
to work with.

#define sqAllocateMemory(x,y,f,headersize)

(a) map in the image file as MAP_PRIVATE (copy on write) at a set  
	 noting that on os-x mmap (file offset) does not allow for non- 
multiples of page size, so we return the offset into the file as the  
(b) map in the free space at the page boundary rounded up based on the  
file size, plus the set location. This should give two mmap memory  
regions side by side.

Obvious issues, if any mmap fails we exit. We cannot be sure what will  
happen for memory mapping in the future, should we attempt recover at  
some other start location?

Source code below for comment.

?bug memory refers to (startOfAnonymousMemory+headersize) yet  
calculation in sqGrowMemoryBy uses memory and gMaxHeapSize.
lazy adding of extra page size to freeSpaceRoundedUpToPageSize is  
preventing disaster, proper fix is exercise for the reader...

  extern usqInt  gMaxHeapSize;
  static usqInt	gHeapSize;
  static  void *startOfmmapForANONMemory,*startOfmmapForImageFile;
  static 	 size_t fileRoundedUpToPageSize,freeSpaceRoundedUpToPageSize;

  /* compute the desired memory allocation */

  extern unsigned char *memory;

  usqInt	sqGetAvailableMemory() {
	 return gMaxHeapSize;

  usqInt sqAllocateMemoryMac(sqInt minHeapSize, sqInt  
*desiredHeapSize, FILE * f,usqInt headersize) {
	 void  *possibleLocation,*startOfAnonymousMemory;
	 off_t fileSize;
	 struct stat sb;
	 size_t pageSize= getpagesize();
	 size_t pageMask= ~(pageSize - 1);
	#define valign(x)	((x) & pageMask)
	#pragma unused(minHeapSize,desiredHeapSize)
	 possibleLocation = 500*1024*1024;
	 gHeapSize = gMaxHeapSize;

	 /* Lets see about mmap the image file into a chunk of memory at the  
500MB boundary rounding up to the page size
	  Then we on the next page anonymously allocate the required free  
space for young space*/
	 /* Thanks to David Pennell for suggesting this */
	 fstat(fileno((FILE *)f), &sb);
	 fileSize = sb.st_size;
	 fileRoundedUpToPageSize = valign(fileSize+pageSize-1);
	 startOfAnonymousMemory = (void *) ((size_t) fileRoundedUpToPageSize  
+ (size_t) possibleLocation);
	 startOfmmapForImageFile = mmap(possibleLocation,  
MAP_PRIVATE,fileno((FILE *)f), 0);
	 if (startOfmmapForImageFile != possibleLocation) {
		 fprintf(stderr, "errno %d\n", errno);
		 perror("startOfmmapForImageFile failed");
	 freeSpaceRoundedUpToPageSize = valign(gMaxHeapSize)- 
	 startOfmmapForANONMemory = mmap(startOfAnonymousMemory,  
freeSpaceRoundedUpToPageSize, PROT_READ|PROT_WRITE, MAP_ANON| 
	 if (startOfmmapForANONMemory != startOfAnonymousMemory) {
		 fprintf(stderr, "errno %d\n", errno);
		 perror("startOfmmapForANONMemory failed");
	 return (usqInt) startOfmmapForImageFile+headersize;

sqInt sqGrowMemoryBy(sqInt memoryLimit, sqInt delta) {
	if ((usqInt) memoryLimit + (usqInt) delta - (usqInt) memory >  
			return memoryLimit;

	gHeapSize += delta;
	return memoryLimit + delta;

sqInt sqShrinkMemoryBy(sqInt memoryLimit, sqInt delta) {

sqInt sqMemoryExtraBytesLeft(sqInt flag) {
	return gMaxHeapSize - gHeapSize;

void sqMacMemoryFree() {
	if (memory == NULL)
	memory = NULL;

More information about the Vm-dev mailing list