From: "Tim Van Holder" To: Subject: RE: Interest in Smalltalk and/or Python? Date: Wed, 17 Jan 2001 18:52:45 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0000_01C080B6.ADFE47E0" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0) In-Reply-To: Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 Reply-To: djgpp-workers AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk This is a multi-part message in MIME format. ------=_NextPart_000_0000_01C080B6.ADFE47E0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Okay - this is the reply I got from Paolo Bonzini (the maintainer and pretty much sole coder of GNU smalltalk) regarding the mmap stuff. > I don't know what to do for mmap instead. GNU Smalltalk requires mmap = in > order to reserve address space for the OOP table or the object heap > without actually requiring the space to be allocated. In other terms, = I > need something like *multiple* regions with sbrk-like behavior -- = that's > what VirtualAlloc provides under Windows if you're familiar with it. >=20 > I don't think it should be difficult to provide support for anonymous > mmaps only under DJGPP, without caring for protection or copy-on-write > behavior for example -- just being able to allocate at some known = linear > address so that it will not interfere with other allocations. If you = want > to give a try to it, you could emulate the Win32 API for this which is > more logical and not layered on top of memory-mapped files. >=20 > For more information, look at heap.c and feel free to contact me. I've attached the heap.c file, as well as oop.c (the only file using the heap routines) and the relevant headers. If anyone can suggest a clean way to implement DJGPP substitutes for the heap routines, I'd be very grateful. ------=_NextPart_000_0000_01C080B6.ADFE47E0 Content-Type: text/plain; name="heap.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="heap.c" /******************************** -*- C -*- ****************************=0A= *=0A= * sbrk-like behavior for separate mmap'ed regions=0A= *=0A= * $Revision: 1.8.5$=0A= * $Date: 2000/12/27 10:45:49$=0A= * $Author: pb$=0A= *=0A= ***********************************************************************/=0A= =0A= /***********************************************************************=0A= *=0A= * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.=0A= * Written by Paolo Bonzini (redisorganization of GNU mmalloc).=0A= *=0A= * This file is part of GNU Smalltalk.=0A= *=0A= * GNU Smalltalk is free software; you can redistribute it and/or modify = it=0A= * under the terms of the GNU General Public License as published by the = Free=0A= * Software Foundation; either version 2, or (at your option) any later =0A= * version.=0A= * =0A= * GNU Smalltalk is distributed in the hope that it will be useful, but = WITHOUT=0A= * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or =0A= * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License = for=0A= * more details.=0A= * =0A= * You should have received a copy of the GNU General Public License = along with=0A= * GNU Smalltalk; see the file COPYING. If not, write to the Free = Software=0A= * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =0A= ***********************************************************************/=0A= =0A= =0A= #include "gst.h"=0A= =0A= #if HAVE_MMAP=0A= =0A= #include "heap.h"=0A= #include "memzero.h"=0A= #include "lex.h"=0A= #include "sysdep.h"=0A= =0A= #include =0A= #include =0A= #include =0A= #include =0A= #include /* dpx/2 needs this after sys/types.h */=0A= #include =0A= =0A= #ifdef _WIN32=0A= #include =0A= #else=0A= #include =0A= #endif=0A= =0A= #ifdef HAVE_UNISTD_H=0A= # include =0A= #endif=0A= =0A= #ifdef HAVE_STDDEF_H=0A= # include =0A= #endif=0A= =0A= #ifdef HAVE_LIMITS_H=0A= # include =0A= #else=0A= # ifndef CHAR_BIT=0A= # define CHAR_BIT 8=0A= # endif=0A= #endif=0A= =0A= #ifndef MIN=0A= # define MIN(A, B) ((A) < (B) ? (A) : (B))=0A= #endif=0A= =0A= /* Internal structure that defines the format of the heap descriptor.=0A= * This gets written to the base address of the region that we are=0A= * managing. */=0A= =0A= struct heap=0A= {=0A= size_t areasize;=0A= =0A= /* The base address of the memory region for this malloc heap. This=0A= * is the location where the bookkeeping data for mmap and for malloc=0A= * begins. */=0A= =0A= char *base;=0A= =0A= /* The current location in the memory region for this malloc heap = which=0A= * represents the end of memory in use. */=0A= =0A= char *breakval;=0A= =0A= /* The end of the current memory region for this malloc heap. This = is=0A= * the first location past the end of mapped memory. */=0A= =0A= char *top;=0A= };=0A= =0A= /* Prototypes for local functions */=0A= =0A= static voidPtr heap_sbrk_internal ();=0A= =0A= /* Cache pagesize-1 for the current host machine. Note that if the host=0A= * does not readily provide a getpagesize() function, we need to emulate = it=0A= * elsewhere, not clutter up this file with lots of kluges to try to = figure=0A= * it out.=0A= */=0A= =0A= static size_t pageround, pagesize;=0A= #ifndef HAVE_GETPAGESIZE=0A= extern int getpagesize ();=0A= #endif=0A= =0A= #define PAGE_ALIGN(addr) ((caddr_t) (((long)(addr) + pageround) & = ~pageround))=0A= =0A= /* We allocate extra pages for the heap descriptor and answer an address=0A= * that is HEAP_DELTA bytes past the actual beginning of the allocation.=0A= */=0A= #define HEAP_DELTA ((long) PAGE_ALIGN(sizeof (struct heap)))=0A= =0A= /* Wrappers for Windows and POSIX */=0A= #ifdef _WIN32=0A= =0A= #define _heap_reserve(hdp, size) \=0A= ((hdp) -> base =3D VirtualAlloc(NULL, (size), MEM_RESERVE, = PAGE_NOACCESS))=0A= =0A= #define _heap_release(hdp) \=0A= VirtualFree((hdp) -> base, (hdp) -> areasize, MEM_RELEASE)=0A= =0A= #define _heap_map_in(hdp, size) \=0A= VirtualAlloc ((hdp) -> top, (size), MEM_COMMIT, PAGE_EXECUTE_READWRITE)=0A= =0A= #define _heap_map_out(hdp, size) \=0A= VirtualFree(PAGE_ALIGN ((hdp) -> breakval), (size), MEM_DECOMMIT)=0A= =0A= #else /* _WIN32 */=0A= =0A= static voidPtr findHeapBase ();=0A= =0A= #ifndef MAP_FAILED=0A= #define MAP_FAILED ((char *) -1)=0A= #endif=0A= =0A= static char *baseaddr;=0A= =0A= #define _heap_reserve(hdp, size) \=0A= ( ((hdp) -> base =3D baseaddr, baseaddr +=3D (size), 1) )=0A= =0A= #define _heap_release(hdp) \=0A= ( ((baseaddr =3D=3D (hdp) -> base + (hdp) -> areasize) \=0A= ? baseaddr =3D (hdp) -> base : 0))=0A= =0A= #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)=0A= #define MAP_ANON MAP_ANONYMOUS=0A= #endif=0A= =0A= #ifdef MAP_ANON=0A= #define anon_mmap(where, size, flags) \=0A= mmap ((where), (size), PROT_READ | PROT_WRITE | PROT_EXEC, \=0A= (flags) | MAP_PRIVATE | MAP_ANON, -1, 0)=0A= =0A= #else /* !MAP_ANON */=0A= =0A= /* Open file descriptor for the file to which malloc heaps is mapped=0A= * (/dev/zero). */=0A= static int fd;=0A= =0A= #define anon_mmap(where, size, flags) \=0A= mmap ((where), (size), PROT_READ | PROT_WRITE | PROT_EXEC, \=0A= (flags) | MAP_PRIVATE, fd, 0)=0A= =0A= #endif /* !MAP_ANON */=0A= =0A= /* Map in enough more memory to satisfy the request. */=0A= #define _heap_map_in(hdp, size) \=0A= anon_mmap ((hdp) -> top, (size), MAP_FIXED)=0A= =0A= #define _heap_map_out(hdp, size) \=0A= munmap (PAGE_ALIGN ((hdp) -> breakval), (size))=0A= =0A= #endif /* !_WIN32 */=0A= =0A= =0A= /* Initialize access to a heap managed region.=0A= =0A= The heap managed region is mapped to "/dev/zero", and the data=0A= will not exist in any filesystem object.=0A= =0A= On success, returns a "heap descriptor" which is used in subsequent=0A= calls to other heap package functions. It is explicitly "void *"=0A= ("char *" for systems that don't fully support void) so that users=0A= of the package don't have to worry about the actual implementation=0A= details.=0A= =0A= On failure returns NULL. */=0A= =0A= heap=0A= heap_create (size)=0A= int size;=0A= {=0A= struct heap mtemp;=0A= struct heap *hdp;=0A= char *mbase;=0A= =0A= if (!pageround) {=0A= pagesize =3D getpagesize ();=0A= pageround =3D pagesize - 1;=0A= =0A= #ifndef _WIN32=0A= #ifndef MAP_ANON=0A= /* Open the file descriptor we need for anonymous mmaps */=0A= fd =3D open ("/dev/zero", O_RDWR);=0A= #endif=0A= baseaddr =3D findHeapBase();=0A= #endif=0A= }=0A= =0A= /* We start off with the heap descriptor allocated on the stack, until=0A= * we build it up enough to call heap_sbrk_internal() to allocate the=0A= * first page of the region and copy it there. Ensure that it is = zero'd and=0A= * then initialize the fields that we know values for. */=0A= =0A= hdp =3D &mtemp;=0A= memzero ((char *) hdp, sizeof (mtemp));=0A= hdp -> areasize =3D size;=0A= =0A= if (!_heap_reserve(hdp, size))=0A= {=0A= errno =3D ENOMEM;=0A= return (NULL);=0A= }=0A= =0A= hdp -> breakval =3D hdp -> top =3D hdp -> base;=0A= =0A= /* Now try to map in the first page, copy the heap descriptor structure=0A= * there, and arrange to return a pointer to this new copy. If the = mapping=0A= * fails, then close the file descriptor if it was opened by us, and = arrange=0A= * to return a NULL. */=0A= =0A= if ((mbase =3D heap_sbrk_internal (hdp, sizeof (mtemp))) !=3D NULL)=0A= {=0A= memcpy (mbase, hdp, sizeof (mtemp));=0A= hdp =3D (struct heap *) (mbase + HEAP_DELTA);=0A= }=0A= else=0A= {=0A= _heap_release (hdp);=0A= hdp =3D NULL;=0A= }=0A= =0A= return ((heap) hdp);=0A= }=0A= =0A= /* Terminate access to a heap managed region by unmapping all memory = pages=0A= * associated with the region, and closing the file descriptor if it is = one=0A= * that we opened.=0A= *=0A= * Returns NULL on success.=0A= *=0A= * Returns the heap descriptor on failure, which can subsequently be used=0A= * for further action, such as obtaining more information about the = nature of=0A= * the failure by examining the preserved errno value.=0A= *=0A= * Note that the heap descriptor that we are using is currently located = in=0A= * region we are about to unmap, so we first make a local copy of it on = the=0A= * stack and use the copy. */=0A= =0A= heap=0A= heap_destroy (hd)=0A= heap hd;=0A= {=0A= struct heap mtemp;=0A= =0A= if (hd !=3D NULL)=0A= {=0A= =0A= mtemp =3D *(struct heap *) (hd - HEAP_DELTA);=0A= =0A= /* Now unmap all the pages associated with this region by asking = for a=0A= * negative increment equal to the current size of the region. */=0A= =0A= if ((heap_sbrk_internal (&mtemp, mtemp.base - mtemp.top)) =3D=3D = NULL)=0A= {=0A= /* Update the original heap descriptor with any changes */=0A= *(struct heap *) (hd - HEAP_DELTA) =3D mtemp;=0A= }=0A= else=0A= {=0A= _heap_release (&mtemp);=0A= hd =3D NULL;=0A= }=0A= }=0A= =0A= return (hd);=0A= }=0A= =0A= /* Get core for the memory region specified by MDP, using SIZE as the=0A= * amount to either add to or subtract from the existing region. Works=0A= * like sbrk(), but using mmap(). */=0A= =0A= voidPtr=0A= heap_sbrk (hd, size)=0A= heap hd;=0A= size_t size;=0A= {=0A= struct heap *hdp;=0A= =0A= hdp =3D (struct heap *) (hd - HEAP_DELTA);=0A= return heap_sbrk_internal (hdp, size);=0A= }=0A= =0A= voidPtr=0A= heap_sbrk_internal (hdp, size)=0A= struct heap *hdp;=0A= int size;=0A= {=0A= char *result =3D NULL;=0A= size_t mapbytes; /* Number of bytes to map */=0A= caddr_t moveto; /* Address where we wish to move "break value" to */=0A= caddr_t mapto; /* Address we actually mapped to */=0A= =0A= if (size =3D=3D 0)=0A= /* Just return the current "break" value. */=0A= result =3D hdp -> breakval;=0A= =0A= else if (size < 0)=0A= {=0A= /* We are deallocating memory. If the amount requested would cause=0A= * us to try to deallocate back past the base of the mmap'd region=0A= * then do nothing, and return NULL. Otherwise, deallocate the=0A= * memory and return the old break value. */=0A= if (hdp -> breakval + size >=3D hdp -> base)=0A= {=0A= result =3D (voidPtr) hdp -> breakval;=0A= hdp -> breakval +=3D size;=0A= moveto =3D PAGE_ALIGN (hdp -> breakval);=0A= _heap_map_out(hdp, (size_t) (hdp -> top - moveto));=0A= hdp -> top =3D moveto;=0A= }=0A= }=0A= else if (hdp -> breakval + size > hdp -> top)=0A= {=0A= moveto =3D PAGE_ALIGN (hdp -> breakval + size);=0A= mapbytes =3D moveto - hdp -> top;=0A= mapto =3D _heap_map_in(hdp, mapbytes);=0A= if (mapto =3D=3D hdp -> top)=0A= {=0A= hdp -> top =3D moveto;=0A= result =3D (voidPtr) hdp -> breakval;=0A= hdp -> breakval +=3D size;=0A= }=0A= else=0A= errno =3D ENOMEM;=0A= }=0A= else=0A= {=0A= result =3D (voidPtr) hdp -> breakval;=0A= hdp -> breakval +=3D size;=0A= }=0A= =0A= return (result);=0A= }=0A= =0A= /* This is hairy and a hack. We have to find a place for our heaps... */=0A= =0A= #ifndef _WIN32=0A= =0A= /* This signal handler is used if it is the only means to decide if=0A= * a page is mapped into memory. We intercept SIGSEGV and SIGBUS=0A= * and we decide that the heap can be allocated at a given location=0A= * only if we receive one of the signals.=0A= * The reason why msync is used if available, is that it makes=0A= * debugging more painful to have SIGSEGV's as part of the normal=0A= * initialization sequence. */=0A= =0A= #ifndef HAVE_MSYNC=0A= static RETSIGTYPE notMapped(SIG_ARG_TYPE);=0A= static jmp_buf alreadyMapped;=0A= =0A= RETSIGTYPE=0A= notMapped(sig)=0A= int sig;=0A= {=0A= setSignalHandler(sig, notMapped);=0A= longjmp(alreadyMapped, 1);=0A= }=0A= #endif=0A= =0A= voidPtr=0A= findHeapBase()=0A= {=0A= volatile char *mmapGuess, *higher, *lower; /* reference addresses */=0A= volatile char *first, *second; /* probed addresses */=0A= volatile int *step;=0A= =0A= static int steps[] =3D {=0A= true, 256, 256, 0, /* try 256 Mb after the higher address */=0A= true, 128, 256, 0, /* try 128 Mb after the higher address */=0A= true, 64, 256, 0, /* try 64 Mb after the higher address */=0A= true, -256, -256, 640, /* try 256 Mb before the higher address */=0A= true, -128, -256, 512, /* try 128 Mb before the higher address */=0A= true, -64, -256, 448, /* try 64 Mb before the higher address */=0A= false, 256, 256, 512, /* try 256 Mb after the lower address */=0A= false, 128, 256, 384, /* try 128 Mb after the lower address */=0A= false, 64, 256, 320, /* try 64 Mb after the lower address */=0A= true, 32, 256, 0, /* try 32 Mb after the higher address */=0A= true, 32, 128, 0, /* again, for a smaller heap */=0A= true, -32, -256, 416, /* try 32 Mb before the higher address */=0A= true, -32, -128, 288, /* again, for a smaller heap */=0A= false, 64, 128, 192, /* this has a smaller heap too */=0A= -1=0A= };=0A= =0A= #ifndef HAVE_MSYNC=0A= volatile int test, *testPtr =3D &test;=0A= volatile SigHandler oldSegvHandler, oldBusHandler;=0A= =0A= /* Placate GNU C's warnings about clobbered variables */=0A= testPtr =3D (volatile int *) &higher;=0A= testPtr =3D (volatile int *) &lower;=0A= testPtr =3D (volatile int *) &first;=0A= testPtr =3D (volatile int *) &step;=0A= testPtr =3D (volatile int *) &test;=0A= =0A= /* Install custom signal handlers to detect failed memory accesses */=0A= #ifdef SIGBUS=0A= oldBusHandler =3D setSignalHandler(SIGBUS, notMapped);=0A= #endif=0A= oldSegvHandler =3D setSignalHandler(SIGSEGV, notMapped);=0A= #endif /* !HAVE_MSYNC */=0A= =0A= /* Get two reference addresses which we will base ourselves on */=0A= mmapGuess =3D higher =3D anon_mmap(NULL, pagesize, 0);=0A= lower =3D sbrk(0);=0A= =0A= if (higher < lower) {=0A= higher =3D lower;=0A= lower =3D mmapGuess;=0A= }=0A= =0A= /* Now try each of the possibilities... */=0A= for (step =3D steps; *step > -1; step +=3D 4) {=0A= if ((higher - lower) > (steps[3] << 20)) {=0A= first =3D (steps[0] ? higher : lower) + (steps[1] << 20);=0A= second =3D first + (steps[2] << 20);=0A= =0A= /* Try reading the two locations */=0A= #ifdef HAVE_MSYNC=0A= if (msync((char *) first, pagesize, MS_SYNC) =3D=3D 0) {=0A= continue;=0A= }=0A= if (msync((char *) second, pagesize, MS_SYNC) =3D=3D 0) {=0A= continue;=0A= }=0A= #else=0A= if (setjmp(alreadyMapped) =3D=3D 0) {=0A= *testPtr =3D *first;=0A= continue;=0A= }=0A= if (setjmp(alreadyMapped) =3D=3D 0) {=0A= *testPtr =3D *second;=0A= continue;=0A= }=0A= #endif=0A= =0A= /* Try mmap-ing them */=0A= if (anon_mmap((char *) first, pagesize, MAP_FIXED) =3D=3D = MAP_FAILED) {=0A= continue;=0A= }=0A= munmap((char *) first, pagesize);=0A= if (anon_mmap((char *) second, pagesize, MAP_FIXED) =3D=3D = MAP_FAILED) {=0A= continue;=0A= }=0A= =0A= /* Were not readable and could be mmap-ed. We're done. */=0A= munmap((char *) second, pagesize);=0A= break;=0A= }=0A= }=0A= =0A= /* Restore things... */=0A= #ifndef HAVE_MSYNC=0A= #ifdef SIGBUS=0A= setSignalHandler(SIGBUS, oldBusHandler);=0A= #endif=0A= setSignalHandler(SIGSEGV, oldSegvHandler);=0A= #endif /* !HAVE_MSYNC */=0A= =0A= munmap((char *)mmapGuess, pagesize);=0A= =0A= if (*step =3D=3D -1) {=0A= errorf("Could not find a place for the Smalltalk heaps.");=0A= return (NULL);=0A= } else {=0A= return (voidPtr) (first);=0A= }=0A= }=0A= #endif=0A= =0A= #endif=0A= ------=_NextPart_000_0000_01C080B6.ADFE47E0 Content-Type: text/plain; name="oop.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="oop.c" /******************************** -*- C -*- ****************************=0A= *=0A= * Object Table maintenance module.=0A= *=0A= * $Revision: 1.8.5$=0A= * $Date: 2000/12/27 10:45:49$=0A= * $Author: pb$=0A= *=0A= ***********************************************************************/=0A= =0A= /***********************************************************************=0A= *=0A= * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.=0A= * Written by Steve Byrne.=0A= *=0A= * This file is part of GNU Smalltalk.=0A= *=0A= * GNU Smalltalk is free software; you can redistribute it and/or modify = it=0A= * under the terms of the GNU General Public License as published by the = Free=0A= * Software Foundation; either version 2, or (at your option) any later =0A= * version.=0A= * =0A= * GNU Smalltalk is distributed in the hope that it will be useful, but = WITHOUT=0A= * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or =0A= * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License = for=0A= * more details.=0A= * =0A= * You should have received a copy of the GNU General Public License = along with=0A= * GNU Smalltalk; see the file COPYING. If not, write to the Free = Software=0A= * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =0A= *=0A= ***********************************************************************/=0A= =0A= =0A= #include =0A= #include "gst.h"=0A= #include "alloc.h"=0A= #include "oop.h"=0A= #include "dict.h"=0A= #if HAVE_MMAP=0A= #include "heap.h"=0A= #endif=0A= #include "save.h"=0A= #include "comp.h"=0A= #include "callin.h"=0A= #include "lex.h"=0A= #include "lib.h"=0A= #include "str.h"=0A= #include "sym.h"=0A= #include "sysdep.h"=0A= =0A= #if STDC_HEADERS=0A= #include =0A= #include =0A= #endif /* STDC_HEADERS */=0A= =0A= /* Size of the object semi spaces, in bytes */=0A= #define K 1024=0A= =0A= /* you can increase this value if you need more space, and it won't hurt=0A= * performance *if* your machine has enough physical memory (otherwise, = you=0A= * thrash the pager) */=0A= #define INIT_MEM_SPACE_SIZE (1 * K * K) =0A= #define NEW_GENERATION_SIZE (128 * K) =0A= =0A= =0A= #define INIT_NUM_INCUBATOR_OOPS 50 /* SWAG */=0A= #define INCUBATOR_CHUNK_SIZE 20 /* SWAG */=0A= =0A= =0A= /* Define this flag to turn on debugging code for OOP table management */=0A= /* #define OOP_DEBUGGING */=0A= =0A= /* Define this flag to force a GC on every object allocation. */=0A= /* #define GC_TORTURE */=0A= =0A= =0A= #define alignSize(size) \=0A= ( ((size) + sizeof(OOP) - 1) & ~(sizeof(OOP) - 1) )=0A= =0A= /* Turn on the mark bit in OBJ */=0A= #define markObject(obj) \=0A= (voidPtr)(((long)(obj)) | 1)=0A= =0A= #define unmarkObject(obj) \=0A= (voidPtr)(((long)(obj)) & ~1)=0A= =0A= #define isMarked(obj) \=0A= isObjMarked((obj)->objClass)=0A= =0A= #define isObjMarked(obj) \=0A= ((long)(obj) & 1)=0A= =0A= =0A= =0C=0A= #if HAVE_MMAP=0A= /* These are the secondary heaps within which we mantain object data. */=0A= heap oopHeap, objectHeap;=0A= #endif=0A= =0A= /* These are the real OOPS for nil, true, and false */=0A= OOP nilOOP, trueOOP, falseOOP;=0A= =0A= /* The OOP table. This contains a pointer to the object, and some flag=0A= bits indicating whether the object is read-only, reachable and/or = pooled.=0A= Some of the bits indicate the difference between the allocated length=0A= (stored in the object itself), and the real length, because variable=0A= byte objects may not be an even multiple of sizeof(voidPtr). */=0A= struct OOPStruct *oopTable =3D nil, *allOopsTable;=0A= OOP firstFreeOOP, lastUsedOOP;=0A= =0A= int numFreeOOPs, oopTableSize;=0A= =0A= mst_Boolean gcState =3D true, gcMessage =3D true;=0A= static mst_Boolean gcFlipping =3D false;=0A= =0A= #ifdef GC_TORTURE=0A= unsigned long gcWaitFlipCount =3D 0, allocCounter =3D 0;=0A= unsigned long doTortureCounter =3D 0;=0A= mst_Boolean doGCTorture =3D false;=0A= #endif=0A= =0A= =0A= /* If there is this much space used after a gcFlip, we need to grow the=0A= * object heap by spaceGrowRate % next time we gcFlip, so that the = storage=0A= * gets copied into the new, larger area.=0A= */=0A= int growThresholdPercent =3D 80;=0A= =0A= /* Grow the object heap by this percentage when the amount of space used=0A= * exceeds growThresholdPercent.=0A= */=0A= int spaceGrowRate =3D 30;=0A= =0A= /* This vector holds the storage for all the Character objects in the = system.=0A= Since all character objects are unique, we pre-allocate space for 256 = of=0A= them, and treat them as special built-ins when doing garbage = collection.*/=0A= CharObject charObjectTable[NUM_CHAR_OBJECTS];=0A= =0A= /* This is "nil" object in the system. That is, the single instance of = the=0A= UndefinedObject class, which is called "nil". */=0A= struct NilObjectStruct nilObject;=0A= =0A= /* These represent the two boolean objects in the system, true and false.=0A= This is the object storage for those two objects. =0A= false =3D=3D &booleanObjects[0], true =3D=3D &booleanObjects[1] */=0A= struct BooleanObjectStruct booleanObjects[2];=0A= =0A= #if !HAVE_MMAP=0A= /* This contains the maximum size of the heap. It is checked at every=0A= * allocObj; if the space is too small, it is brought up to spec before=0A= * being used=0A= */=0A= unsigned long maxSpaceSize;=0A= #endif=0A= =0A= /* This variable represents information about the memory space. memSpace=0A= holds the required information: basically the pointer to the base and=0A= top of the space, and the pointers into it for allocation and copying.=0A= */=0A= struct memorySpaceStruct memSpace;=0A= =0A= /* These variables hold onto the object incubator's state */=0A= OOP *incOOPBasePtr, *incOOPPtr, *incOOPEndPtr;=0A= =0A= =0C=0A= =0A= /* static mst_Object moveObject(); */=0A= #if !HAVE_MMAP=0A= static mst_Boolean growMemory();=0A= static void initSpace();=0A= #endif=0A= static void displayObject(), allocOOPTable(), displayOOP();=0A= =0A= static inline void markOOPs(), sweepOOPs(), /* markGlobalOOPs(), */=0A= markIncubatorOOPs(), markFinalizableOOPReferences(),=0A= checkObjectsAfterSweep(),=0A= checkWeakRefs(), sweepPooledContexts();=0A= =0A= static unsigned long prepareForSweep();=0A= =0C=0A= =0A= /*=0A= * void initOOPTable(size)=0A= *=0A= * Description=0A= *=0A= * Initialize the OOP table. Initially, all the OOPs are on the OOP free=0A= * list so that's just how we initialize them. We do as much=0A= * initialization as we can, but we're called before classses are=0A= * defined, so things that have definite classes must wait until=0A= * the classes are defined.=0A= *=0A= * Input=0A= *=0A= * size of the table to be created=0A= */=0A= void=0A= initOOPTable(size)=0A= long size;=0A= {=0A= int i;=0A= =0A= #if HAVE_MMAP=0A= oopHeap =3D NULL;=0A= for(i =3D MAX_OOP_TABLE_SIZE; i && !oopHeap; i >>=3D 1) {=0A= oopHeap =3D heap_create(i * sizeof(struct OOPStruct));=0A= }=0A= if (!oopHeap) nomemory(true);=0A= #endif=0A= =0A= allocOOPTable(size);=0A= =0A= nilOOP->flags =3D F_READONLY | F_REACHABLE;=0A= nilOOP->object =3D (mst_Object)&nilObject;=0A= nilObject.objSize =3D ROUNDED_WORDS(sizeof(struct NilObjectStruct));=0A= =0A= trueOOP->flags =3D F_READONLY | F_REACHABLE;=0A= trueOOP->object =3D (mst_Object)&booleanObjects[0];=0A= falseOOP->flags =3D F_READONLY | F_REACHABLE;=0A= falseOOP->object =3D (mst_Object)&booleanObjects[1];=0A= booleanObjects[0].objSize =3D ROUNDED_WORDS(sizeof(struct = BooleanObjectStruct));=0A= booleanObjects[1].objSize =3D ROUNDED_WORDS(sizeof(struct = BooleanObjectStruct));=0A= booleanObjects[0].booleanValue=3D trueOOP;=0A= booleanObjects[1].booleanValue=3D falseOOP;=0A= =0A= for (i =3D 0; i < NUM_CHAR_OBJECTS; i++) {=0A= charObjectTable[i].objSize =3D = ROUNDED_WORDS(sizeof(charObjectTable[i]));=0A= charObjectTable[i].charVal =3D (char) i;=0A= oopTable[i + CHAR_OBJECT_BASE].object =3D = (mst_Object)&charObjectTable[i];=0A= oopTable[i + CHAR_OBJECT_BASE].flags =3D F_READONLY | F_REACHABLE;=0A= }=0A= }=0A= =0A= =0A= void=0A= allocOOPTable(size)=0A= long size;=0A= {=0A= register long i;=0A= long bytes;=0A= =0A= oopTableSize =3D size;=0A= bytes =3D (size - FIRST_OOP_INDEX) * sizeof(struct OOPStruct);=0A= #if HAVE_MMAP=0A= allOopsTable =3D (struct OOPStruct *)heap_sbrk(oopHeap, bytes);=0A= if (!allOopsTable) nomemory(true);=0A= #else=0A= allOopsTable =3D (struct OOPStruct *)xmalloc(bytes);=0A= #endif=0A= =0A= oopTable =3D &allOopsTable[-FIRST_OOP_INDEX];=0A= nilOOP =3D &oopTable[nilOOPIndex];=0A= trueOOP =3D &oopTable[trueOOPIndex];=0A= falseOOP =3D &oopTable[falseOOPIndex];=0A= =0A= firstFreeOOP =3D &oopTable[size - 1];=0A= lastUsedOOP =3D oopTable;=0A= numFreeOOPs =3D size;=0A= firstFreeOOP->object =3D NULL;=0A= firstFreeOOP->flags =3D F_FREE;=0A= =0A= i =3D size - 1;=0A= while(firstFreeOOP !=3D &oopTable[0]) {=0A= firstFreeOOP =3D &oopTable[--i];=0A= firstFreeOOP->object =3D (mst_Object) &oopTable[i + 1];=0A= firstFreeOOP->flags =3D F_FREE;=0A= }=0A= }=0A= =0A= mst_Boolean=0A= reallocOOPTable(newSize)=0A= long newSize;=0A= {=0A= long bytes;=0A= OOP oop;=0A= #if !HAVE_MMAP=0A= struct OOPStruct *newOopTable, *oldOopTable;=0A= int numFixed;=0A= mst_Object object;=0A= =0A= bytes =3D (newSize - FIRST_OOP_INDEX) * sizeof(struct OOPStruct);=0A= oldOopTable =3D allOopsTable;=0A= allOopsTable =3D (struct OOPStruct *)xrealloc(allOopsTable, bytes);=0A= newOopTable =3D allOopsTable;=0A= =0A= if (newOopTable !=3D oldOopTable) {=0A= for (oop =3D newOopTable; oop < &oopTable[oopTableSize]; oop++) {=0A= if (oopValid(oop)) {=0A= object =3D oopToObj(oop);=0A= numFixed =3D numOOPs(object);=0A= allOopsTable =3D oldOopTable;=0A= fixupObject(object, numFixed);=0A= allOopsTable =3D newOopTable;=0A= restoreObject(object, numFixed);=0A= }=0A= }=0A= }=0A= =0A= lastUsedOOP +=3D (newOopTable - oldOopTable);=0A= oopTable +=3D (newOopTable - oldOopTable);=0A= nilOOP +=3D (newOopTable - oldOopTable);=0A= trueOOP +=3D (newOopTable - oldOopTable);=0A= falseOOP +=3D (newOopTable - oldOopTable);=0A= =0A= #else /* HAVE_MMAP */=0A= =0A= bytes =3D (newSize - oopTableSize) * sizeof(struct OOPStruct);=0A= if (bytes < 0) {=0A= return (true);=0A= }=0A= =0A= if (!heap_sbrk(oopHeap, bytes)) {=0A= /* try to recover. Note that we cannot move the OOP table like=0A= * we do with the object data. */=0A= nomemory(false);=0A= return (false);=0A= }=0A= =0A= #endif=0A= =0A= /* mark the new OOPs as available */=0A= for (oop =3D &oopTable[oopTableSize]; oop < &oopTable[newSize]; oop++) = {=0A= oop->flags =3D F_FREE;=0A= }=0A= =0A= firstFreeOOP =3D &oopTable[newSize - 1];=0A= =0A= oopTableSize =3D newSize;=0A= refreshOOPFreeList();=0A= return (true);=0A= }=0A= =0A= /*=0A= * void initBuiltinObjectsClasses()=0A= *=0A= * Description=0A= *=0A= * Initialize the builtin objects after the respective classes=0A= * have been created.=0A= *=0A= */=0A= void=0A= initBuiltinObjectsClasses()=0A= {=0A= int i;=0A= =0A= nilObject.objClass =3D undefinedObjectClass;=0A= booleanObjects[0].objClass =3D trueClass;=0A= booleanObjects[1].objClass =3D falseClass;=0A= =0A= for (i =3D 0; i < NUM_CHAR_OBJECTS; i++) {=0A= charObjectTable[i].objClass =3D charClass;=0A= }=0A= }=0A= =0A= /*=0A= * void fixupMetaclassObjects()=0A= *=0A= * Description=0A= *=0A= * Called after the fundamental class hierarchy has been defined, this=0A= * function goes through and fixes up all the objects in the oop table=0A= * that don't have a objClass (objClass =3D=3D nilOOP). It's a=0A= * chicken-and-egg problem: the metaclassClass doesn't yet exist when the=0A= * hierarchy is put together, so after it's created, we have to go back=0A= * and fix all the metaclasses that we created.=0A= *=0A= */=0A= void=0A= fixupMetaclassObjects()=0A= {=0A= OOP oop;=0A= mst_Object object;=0A= =0A= for (oop =3D oopTable; oop <=3D lastUsedOOP; oop++) {=0A= object =3D oopToObj(oop);=0A= if (!(oop->flags & F_FREE) && isNil(object->objClass)) {=0A= object->objClass =3D metaclassClass;=0A= }=0A= }=0A= }=0A= =0C=0A= =0A= /*=0A= * OOP findAnInstance(classOOP)=0A= *=0A= * Description=0A= *=0A= * Finds and returns an instance of the class CLASSOOP. Returns "nil" if=0A= * there are no instances present.=0A= *=0A= * Inputs=0A= *=0A= * classOOP: =0A= * OOP for a class for which to find an instance=0A= *=0A= * Outputs=0A= *=0A= * The first instance of the given class in the OOP table.=0A= */=0A= OOP=0A= findAnInstance(classOOP)=0A= OOP classOOP;=0A= {=0A= register OOP oop;=0A= =0A= for (oop =3D oopTable; oop <=3D lastUsedOOP; oop++) {=0A= if (!(oop->flags & F_FREE) && (oopClass(oop) =3D=3D classOOP)) {=0A= return (oop);=0A= }=0A= }=0A= =0A= return (nilOOP);=0A= }=0A= =0C=0A= =0A= void=0A= swapObjects(oop1, oop2)=0A= OOP oop1, oop2;=0A= {=0A= struct OOPStruct tempOOP;=0A= =0A= tempOOP =3D *oop2; /* note structure assignment going on here */=0A= *oop2 =3D *oop1;=0A= *oop1 =3D tempOOP;=0A= }=0A= =0A= OOP=0A= charOOPAt(c)=0A= Byte c;=0A= {=0A= return (&oopTable[c + CHAR_OBJECT_BASE]);=0A= }=0A= =0A= Byte=0A= charOOPValue(charOOP)=0A= OOP charOOP;=0A= {=0A= return (charOOP - &oopTable[CHAR_OBJECT_BASE]);=0A= }=0A= =0A= /*=0A= * mst_Boolean oopIndexValid(index)=0A= *=0A= * Description=0A= *=0A= * Checks to see if index represents a valid OOP.=0A= *=0A= * Inputs=0A= *=0A= * index : a long index into the OOP table, apparently 1 based due to=0A= * being called from Smalltalk via a primitive.=0A= *=0A= * Outputs=0A= *=0A= * True if the index represents a valid OOP table element, false=0A= * otherwise.=0A= */=0A= mst_Boolean=0A= oopIndexValid(index)=0A= long index;=0A= {=0A= return (index >=3D FIRST_OOP_INDEX && index <=3D oopTableSize);=0A= }=0A= =0C=0A= =0A= void=0A= printObject(oop)=0A= OOP oop;=0A= {=0A= if (isInt(oop)) {=0A= printf("%ld", toInt(oop));=0A= } else if (isNil(oop)) {=0A= printf("nil");=0A= } else if (oop =3D=3D trueOOP) {=0A= printf("true");=0A= } else if (oop =3D=3D falseOOP) {=0A= printf("false");=0A= } else if (oopClass(oop) =3D=3D charClass) {=0A= printf("$%c", charOOPValue(oop));=0A= } else if (oopClass(oop) =3D=3D floatClass) {=0A= printf("%#g", floatOOPValue(oop));=0A= } else if (oopClass(oop) =3D=3D symbolClass) {=0A= printf("#"); printSymbol(oop);=0A= } else if (oopClass(oop) =3D=3D stringClass) {=0A= /* ### have to quote embedded quote chars */=0A= printf("'");=0A= printString(oop);=0A= printf("'");=0A= } else {=0A= printOOPConstructor(oop);=0A= }=0A= fflush(stdout);=0A= }=0A= =0A= void =0A= classifyAddr(addr)=0A= void *addr;=0A= {=0A= if (isOOPAddr(addr)) {=0A= displayOOP(addr);=0A= } else if (isObjAddr(addr)) {=0A= displayObject(addr);=0A= } else if isInt(addr) {=0A= printf("Smalltalk SmallInteger %ld\n", toInt(addr));=0A= } else {=0A= printf("Address %p is not a Smalltalk entity\n", addr);=0A= }=0A= fflush(stdout);=0A= }=0A= =0A= void=0A= displayOOP(oop)=0A= OOP oop;=0A= {=0A= mst_Boolean isBuiltin;=0A= =0A= if (!isOOPAddr(oop)) {=0A= printf("Parameter %p does not appear to be an OOP!\n", oop);=0A= return;=0A= }=0A= =0A= isBuiltin =3D (oop < oopTable);=0A= =0A= if (!isBuiltin) {=0A= printf ("OOP %p [%ld]\n", oop, (unsigned long) (oop - oopTable));=0A= }=0A= =0A= if (oop->flags & F_FREE) {=0A= printf("Free ");=0A= }=0A= =0A= if (oop->flags & F_REACHABLE) {=0A= printf("Reachable ");=0A= }=0A= =0A= printf(" Empty bytes =3D %ld\n", (oop->flags & EMPTY_BYTES));=0A= if (!(oop->flags & F_FREE)) {=0A= printObject(oop);=0A= }=0A= printf("\n");=0A= }=0A= =0A= =0A= void =0A= displayObject(obj)=0A= mst_Object obj;=0A= {=0A= if (!isObjAddr(obj)) {=0A= printf("Parameter %p does not appear to be an object!\n", obj);=0A= return;=0A= }=0A= =0A= printf("Object at %p, ", obj);=0A= printf("Size %ld\n", numOOPs(obj));=0A= printf("Class ");=0A= printObject(obj->objClass);=0A= printf("\n");=0A= }=0A= =0C=0A= =0A= /*=0A= * Object allocObj(size)=0A= *=0A= * Description=0A= *=0A= * Allocate and return space for an object of SIZE bytes. This basically=0A= * means moving the allocation pointer for the current space up by SIZE=0A= * bytes, and, if there isn't enough space left, flipping the garbage=0A= * collector after memory is compacted. The space is merely allocated;=0A= * it is not initialized.=0A= *=0A= * Inputs=0A= *=0A= * size : size in bytes of the object to allocate. This will be rounded=0A= * by this routine up to a suitable boundary, typically to a 4=0A= * byte boundary.=0A= *=0A= * Outputs=0A= *=0A= * Address of the newly allocated object.=0A= */=0A= mst_Object=0A= allocObj(size)=0A= unsigned long size;=0A= {=0A= register char *newAllocPtr, *oldAllocPtr;=0A= =0A= #ifdef GC_TORTURE=0A= if (gcState && doGCTorture) {=0A= minorGCFlip();=0A= }=0A= #endif =0A= =0A= size =3D alignSize(size);=0A= =0A= /* We don't want to have allocPtr pointing to the wrong thing during = GC, so=0A= * we use a local var to hold its new value=0A= */=0A= newAllocPtr =3D memSpace.allocPtr + size;=0A= if (newAllocPtr >=3D memSpace.maxPtr) {=0A= if (!gcFlipping) {=0A= /* not enough room currently, try to make some more */=0A= int percent;=0A= percent =3D (memSpace.newAllocPtr - memSpace.space)=0A= * 100 / memSpace.totalSize;=0A= =0A= if (percent >=3D growThresholdPercent) {=0A= gcFlip();=0A= } else {=0A= minorGCFlip();=0A= }=0A= =0A= newAllocPtr =3D memSpace.allocPtr + size;=0A= }=0A= if (newAllocPtr >=3D memSpace.maxPtr) {=0A= /* uh oh, still too big -- we need to grow memory */=0A= unsigned long spaceInUse;=0A= unsigned long spaceNeeded;=0A= =0A= spaceInUse =3D memSpace.allocPtr - memSpace.space;=0A= =0A= /* we need what we already are using, plus some breathing room */=0A= spaceNeeded =3D size + spaceInUse;=0A= if (spaceGrowRate > 0) {=0A= spaceNeeded +=3D spaceNeeded / 100 * spaceGrowRate;=0A= }=0A= if (!growMemoryTo(spaceNeeded)) {=0A= /* !!! do something more reasonable in the future */=0A= errorf("Cannot recover, exiting...");=0A= exit(1);=0A= }=0A= newAllocPtr =3D memSpace.allocPtr + size;=0A= }=0A= }=0A= =0A= oldAllocPtr =3D memSpace.allocPtr;=0A= memSpace.allocPtr =3D newAllocPtr;=0A= return ((mst_Object)oldAllocPtr);=0A= }=0A= =0A= =0C=0A= =0A= /*=0A= * mst_Boolean gcOff()=0A= *=0A= * Description=0A= *=0A= * Turns off the garbage collector. Returns the previous on/off state.=0A= *=0A= * Outputs=0A= *=0A= * Previous state of the garbage collector (on or off).=0A= */=0A= mst_Boolean=0A= gcOff()=0A= {=0A= mst_Boolean oldGCState;=0A= =0A= oldGCState =3D gcState;=0A= gcState =3D false;=0A= return (oldGCState);=0A= }=0A= =0A= /*=0A= * void gcOn()=0A= *=0A= * Description=0A= *=0A= * Turns on the garbage collector.=0A= *=0A= */=0A= mst_Boolean=0A= gcOn()=0A= {=0A= mst_Boolean oldGCState;=0A= =0A= oldGCState =3D gcState;=0A= gcState =3D true;=0A= return (oldGCState);=0A= }=0A= =0A= /*=0A= * void setGCState(state)=0A= *=0A= * Description=0A= *=0A= * Set the garbage collector flag to the specified state (either on or=0A= * off).=0A= *=0A= * Inputs=0A= *=0A= * state : mst_Boolean, true =3D> gc on.=0A= *=0A= */=0A= mst_Boolean=0A= setGCState(state)=0A= mst_Boolean state;=0A= {=0A= if(state) {=0A= return(gcOn());=0A= } else {=0A= return(gcOff());=0A= }=0A= }=0A= =0A= =0A= =0A= /*=0A= * void initMem()=0A= *=0A= * Description=0A= *=0A= * Initialize the memory allocator. The memory space is allocated, and=0A= * the various garbage collection flags are set to their initial values.=0A= *=0A= */=0A= void=0A= initMem()=0A= {=0A= #if HAVE_MMAP=0A= int i;=0A= =0A= objectHeap =3D NULL;=0A= for(i =3D MAX_OBJECT_DATA_SIZE; i && !objectHeap; i >>=3D 1) {=0A= objectHeap =3D heap_create(i);=0A= }=0A= if (!objectHeap) nomemory(true);=0A= =0A= memSpace.totalSize =3D INIT_MEM_SPACE_SIZE;=0A= memSpace.space =3D (char *)heap_sbrk(objectHeap,=0A= memSpace.totalSize + NEW_GENERATION_SIZE);=0A= =0A= if (!memSpace.space) nomemory(true);=0A= =0A= memSpace.allocPtr =3D memSpace.space;=0A= memSpace.newAllocPtr =3D memSpace.space;=0A= memSpace.maxPtr =3D memSpace.space + memSpace.totalSize;=0A= =0A= #else=0A= maxSpaceSize =3D INIT_MEM_SPACE_SIZE;=0A= initSpace(&memSpace);=0A= #endif=0A= =0A= gcOff();=0A= incInitRegistry();=0A= }=0A= =0A= =0A= mst_Object=0A= curSpaceAddr()=0A= {=0A= return ((mst_Object)memSpace.space);=0A= }=0A= =0A= void=0A= setSpaceInfo(size)=0A= long size;=0A= {=0A= memSpace.newAllocPtr =3D memSpace.allocPtr =3D memSpace.space + size;=0A= }=0A= =0A= =0A= /*=0A= * mst_Boolean growTo(spaceSize)=0A= *=0A= * Description=0A= *=0A= * Grows the allocated memory to the given size in bytes, if it's not=0A= * there already.=0A= *=0A= * Inputs=0A= *=0A= * spaceSize: =0A= * Size in bytes to grow the memory space to.=0A= *=0A= * Outputs=0A= *=0A= * True if the operation was successful, False if the memory could not be=0A= * allocated.=0A= */=0A= mst_Boolean=0A= growTo(spaceSize)=0A= unsigned long spaceSize;=0A= {=0A= #if HAVE_MMAP=0A= gcFlip();=0A= return growMemoryTo(spaceSize);=0A= #else=0A= if (spaceSize > maxSpaceSize) {=0A= maxSpaceSize =3D spaceSize;=0A= gcFlip();=0A= }=0A= return (true);=0A= #endif=0A= }=0A= =0A= =0A= /*=0A= * mst_Boolean growMemoryTo(spaceSize)=0A= *=0A= * Description=0A= *=0A= * Grows the memory segment to sapceSize. Should be called after the=0A= * sweep has occurred so that things are contiguous. Ensures that the = OOP=0A= * table pointers are fixed up to point to the new objects.=0A= *=0A= * Inputs=0A= *=0A= * spaceSize: =0A= * The size of memory to grow to. If it's not larger than the=0A= * current allocation, nothing happens.=0A= *=0A= * Outputs=0A= *=0A= * True if the operation succeeded, false of the memory could not be=0A= * grown. =0A= */=0A= mst_Boolean=0A= growMemoryTo(spaceSize)=0A= unsigned long spaceSize;=0A= {=0A= #if HAVE_MMAP=0A= long spaceDelta;=0A= long bytes;=0A= char *newSpacePtr;=0A= OOP oop;=0A= heap newHeap;=0A= =0A= if (spaceSize <=3D memSpace.totalSize) {=0A= return (true);=0A= }=0A= =0A= if (spaceSize > MAX_OBJECT_DATA_SIZE - NEW_GENERATION_SIZE) {=0A= if (memSpace.totalSize >=3D MAX_OBJECT_DATA_SIZE - = NEW_GENERATION_SIZE) {=0A= return (false);=0A= } else {=0A= spaceSize =3D MAX_OBJECT_DATA_SIZE - NEW_GENERATION_SIZE;=0A= }=0A= }=0A= =0A= /* Do the real work... */=0A= bytes =3D spaceSize + NEW_GENERATION_SIZE;=0A= if (heap_sbrk(objectHeap, spaceSize - memSpace.totalSize)) {=0A= newSpacePtr =3D memSpace.space;=0A= newHeap =3D objectHeap;=0A= } else {=0A= int i;=0A= =0A= /* Try to move to a newly allocated heap */ =0A= newHeap =3D NULL;=0A= for(i =3D MAX_OBJECT_DATA_SIZE; i > bytes && !newHeap; i >>=3D 1) {=0A= newHeap =3D heap_create(i);=0A= }=0A= =0A= if (!newHeap ||=0A= !(newSpacePtr =3D heap_sbrk(newHeap, bytes))) {=0A= nomemory(false);=0A= spaceSize =3D memSpace.totalSize;=0A= if (newHeap) {=0A= heap_destroy(newHeap);=0A= }=0A= return (false);=0A= }=0A= }=0A= =0A= #ifdef GROW_DEBUG=0A= printf("old =3D %8x, new =3D %8x, delta =3D %8x\n", memSpace.space, = newSpacePtr, spaceDelta);=0A= #endif=0A= =0A= fixupObjectPointers();=0A= =0A= spaceDelta =3D newSpacePtr - memSpace.space;=0A= if (spaceDelta) {=0A= memcpy(newSpacePtr, memSpace.space, spaceSize + NEW_GENERATION_SIZE);=0A= heap_destroy(objectHeap);=0A= objectHeap =3D newHeap;=0A= }=0A= =0A= memSpace.space =3D newSpacePtr;=0A= memSpace.totalSize =3D spaceSize;=0A= memSpace.allocPtr +=3D spaceDelta;=0A= memSpace.newAllocPtr +=3D spaceDelta;=0A= memSpace.maxPtr =3D memSpace.space + memSpace.totalSize;=0A= =0A= if (spaceDelta && oopTable) {=0A= /* Fix up the OOP table pointers to objects */=0A= for (oop =3D oopTable; oop <=3D lastUsedOOP; oop++) {=0A= if (!(oop->flags & (F_FREE | F_POOLED))) {=0A= #ifdef GROW_DEBUG=0A= voidPtr obj;=0A= printf("old =3D %8x, ", obj =3D (voidPtr) oop->object);=0A= #endif=0A= oop->object =3D (mst_Object)(((char *)oop->object) + spaceDelta);=0A= #ifdef GROW_DEBUG=0A= printf("new =3D %x, delta =3D %x\n", oop->object, = ((voidPtr)oop->object) - obj);=0A= #endif=0A= }=0A= }=0A= }=0A= =0A= restoreObjectPointers();=0A= return (true);=0A= #else=0A= if (spaceSize > maxSpaceSize) {=0A= maxSpaceSize =3D spaceSize;=0A= return growMemory();=0A= }=0A= =0A= return (true);=0A= #endif=0A= }=0A= =0A= #if !HAVE_MMAP=0A= /*=0A= * static mst_Boolean growMemory()=0A= *=0A= * Description=0A= *=0A= * Grows the memory segment to maxSpaceSize. Should be called after the=0A= * sweep has occurred so that things are contiguous. Ensures that the = OOP=0A= * table pointers (the live ones) are fixed up to point to the new=0A= * objects. =0A= *=0A= */=0A= mst_Boolean=0A= growMemory()=0A= {=0A= unsigned long spaceDelta;=0A= char *oldSpacePtr;=0A= OOP oop;=0A= =0A= fixupObjectPointers();=0A= oldSpacePtr =3D memSpace.space;=0A= memSpace.space =3D (char *)xrealloc(memSpace.space, maxSpaceSize + = NEW_GENERATION_SIZE);=0A= if (!memSpace.space) {=0A= nomemory (0);=0A= /* try to recover */=0A= maxSpaceSize =3D memSpace.totalSize;=0A= memSpace.space =3D oldSpacePtr;=0A= return (false);=0A= }=0A= spaceDelta =3D memSpace.space - oldSpacePtr;=0A= memSpace.totalSize =3D maxSpaceSize;=0A= memSpace.allocPtr +=3D spaceDelta;=0A= memSpace.newAllocPtr +=3D spaceDelta;=0A= memSpace.maxPtr =3D memSpace.space + memSpace.totalSize;=0A= #ifdef GROW_DEBUG=0A= printf("old =3D %8x, new =3D %8x, delta =3D %8x\n", oldSpacePtr, = memSpace.space, spaceDelta);=0A= #endif=0A= =0A= if (oopTable) {=0A= /* Fix up the OOP table pointers to objects */=0A= for (oop =3D oopTable; oop <=3D lastUsedOOP; oop++) {=0A= if (!(oop->flags & (F_FREE | F_POOLED))) {=0A= #ifdef GROW_DEBUG=0A= voidPtr obj;=0A= printf("old =3D %8x, ", obj =3D (voidPtr) oop->object);=0A= #endif=0A= oop->object =3D (mst_Object)(((char *)oop->object) + spaceDelta);=0A= #ifdef GROW_DEBUG=0A= printf("new =3D %x, delta =3D %x\n", oop->object, = ((voidPtr)oop->object) - obj);=0A= #endif=0A= }=0A= }=0A= }=0A= restoreObjectPointers();=0A= =0A= return true;=0A= }=0A= #endif=0A= =0A= =0C=0A= =0A= /*=0A= * void gcFlip()=0A= *=0A= * Description=0A= *=0A= * Mark & sweep the objects. Starting from the root set, recursively = mark=0A= * objects as reachable, then compact memory, thus eliminating objects=0A= * that are not reachable (sweeping them). Then, check if the space has=0A= * to be grown and, if so, readjust the collector's parameters.=0A= *=0A= */=0A= void=0A= gcFlip()=0A= {=0A= int lastPercent;=0A= =0A= #ifdef PROFBLOCK=0A= ps.numMajorGCs++;=0A= #endif=0A= =0A= if (gcMessage && !regressionTesting) {=0A= /* print the first part of this message before we finish scanning =0A= * oop table for live ones, so that the delay caused by this scanning=0A= * is apparent.=0A= * note the use of stderr for the printed message. The idea here was=0A= * that generated output could be treated as Smalltalk code, HTML or=0A= * whatever else you want without harm.=0A= */=0A= fflush(stdout);=0A= fprintf(stderr, "\"Major GC flip... ");=0A= fflush(stderr);=0A= }=0A= =0A= /*#if HAVE_MMAP*/=0A= /* In allocOOP, we don't want to worry about going below the low-water=0A= * threshold, so we massage numFreeOOPs. The real number of free OOPs=0A= * will be computed in prepareForSweep. */=0A= numFreeOOPs +=3D LOW_WATER_OOP_THRESHOLD;=0A= /*#endif*/=0A= =0A= gcFlipping =3D true;=0A= fixupObjectPointers();=0A= markOOPs();=0A= sweepOOPs(memSpace.space);=0A= restoreObjectPointers();=0A= gcFlipping =3D false;=0A= =0A= /* At this point, storage in memory is compacted and contiguous, so we = can=0A= * examine how much memory we have left, and decide if we need to = increase=0A= * memory some more.=0A= */=0A= lastPercent =3D (memSpace.allocPtr - memSpace.space) * 100=0A= / memSpace.totalSize; =0A= =0A= if (lastPercent > growThresholdPercent) {=0A= /* with bad grow rates, can undergrow. Takes care of it */=0A= #if HAVE_MMAP=0A= unsigned long newSpaceSize;=0A= =0A= debug();=0A= newSpaceSize =3D memSpace.totalSize / 100 * (100 + spaceGrowRate);=0A= newSpaceSize &=3D ~(sizeof(long)-1); /* round to word boundary */=0A= if (newSpaceSize > memSpace.totalSize) {=0A= growMemoryTo(newSpaceSize);=0A= }=0A= #else=0A= maxSpaceSize +=3D maxSpaceSize / 100 * spaceGrowRate;=0A= maxSpaceSize &=3D ~(sizeof(long)-1); /* round to word boundary */=0A= if (maxSpaceSize > memSpace.totalSize) {=0A= growMemory();=0A= }=0A= maxSpaceSize =3D memSpace.totalSize;=0A= #endif=0A= }=0A= =0A= if (gcMessage && !regressionTesting) {=0A= fprintf(stderr, "done, used space =3D %i%%\"\n", lastPercent);=0A= fflush(stderr);=0A= }=0A= =0A= checkObjectsAfterSweep();=0A= }=0A= =0A= /*=0A= * void minorGCFlip()=0A= *=0A= * Description=0A= *=0A= * Mark & sweep the new objects. Starting from the root set, recursively=0A= * mark objects as reachable, then include the actually reachable ones to=0A= * the old generation.=0A= *=0A= */=0A= void=0A= minorGCFlip()=0A= {=0A= int lastPercent;=0A= =0A= #ifdef PROFBLOCK=0A= ps.numMinorGCs++;=0A= #endif=0A= =0A= if (gcMessage && !regressionTesting) {=0A= /* print the first part of this message before we finish scanning =0A= * oop table for live ones, so that the delay caused by this scanning=0A= * is apparent.=0A= * note the use of stderr for the printed message. The idea here was=0A= * that generated output could be treated as Smalltalk code, HTML or=0A= * whatever else you want without harm.=0A= */=0A= fflush(stdout);=0A= fprintf(stderr, "\"Minor GC flip...");=0A= fflush(stderr);=0A= }=0A= =0A= /*#if HAVE_MMAP*/=0A= /* In allocOOP, we don't want to worry about going below the low-water=0A= * threshold, so we massage numFreeOOPs. The real number of free OOPs=0A= * will be computed in prepareForSweep. */=0A= numFreeOOPs +=3D LOW_WATER_OOP_THRESHOLD;=0A= /*#endif*/=0A= =0A= gcFlipping =3D true;=0A= fixupObjectPointers();=0A= markOOPs();=0A= sweepOOPs(memSpace.newAllocPtr);=0A= restoreObjectPointers();=0A= gcFlipping =3D false;=0A= =0A= lastPercent =3D (memSpace.allocPtr - memSpace.space) * 100=0A= / memSpace.totalSize;=0A= =0A= if (gcMessage && !regressionTesting) {=0A= fprintf(stderr, " done, used space =3D %i%%\"\n", lastPercent);=0A= fflush(stderr);=0A= }=0A= =0A= checkObjectsAfterSweep();=0A= }=0A= =0C=0A= =0A= /*=0A= * static void checkObjectsAfterSweep()=0A= *=0A= * Description=0A= *=0A= * Performs special checks on weak and finalizable objects.=0A= * When one of the objects pointed to by a weak object have no=0A= * other references, the slot of the weak object is replaced by=0A= * a nil.=0A= * When a finalizable object has no references outside weak objects,=0A= * prepareForSweep() marks it in a buffer. This routine (which=0A= * is executed after the sweep) calls back the finalize method.=0A= *=0A= */=0A= void=0A= checkObjectsAfterSweep()=0A= {=0A= register OOP *pOOP;=0A= register long size;=0A= =0A= /* Make a local copy of the buffer */=0A= size =3D bufferSize();=0A= pOOP =3D alloca(size);=0A= copyBuffer(pOOP);=0A= size /=3D SIZEOF_CHAR_P;=0A= =0A= while (size--) {=0A= msgSend(*pOOP++, finalizeSymbol, nil);=0A= }=0A= }=0A= =0A= void=0A= checkWeakRefs(oop)=0A= register OOP oop;=0A= {=0A= mst_Object object;=0A= register OOP *field;=0A= register int numFields;=0A= =0A= object =3D oopToObj(oop);=0A= for (field =3D object->data, numFields =3D numOOPs(object); numFields;=0A= field++, numFields--) {=0A= if (isInt(*field)) {=0A= continue;=0A= }=0A= if (*field <=3D oop) {=0A= /* Not yet scanned by prepareForSweep */=0A= if (!isOOPMarked(*field)) {=0A= *field =3D nilOOP;=0A= }=0A= } else {=0A= /* Already scanned by prepareForSweep */=0A= if (isOOPFree(*field)) {=0A= *field =3D nilOOP;=0A= }=0A= }=0A= }=0A= }=0A= =0A= void markOOPs()=0A= {=0A= markAnOOPInternal(smalltalkDictionary, nil, nil);=0A= markProcessorRegisters();=0A= markRegisteredOOPs();=0A= markIncubatorOOPs();=0A= markCompileContext();=0A= markFinalizableOOPReferences();=0A= =0A= #ifdef DEBUG_FREED /* Mon Jul 3 00:38:46 1995 */=0A= /**/ {=0A= /**/ OOP oop; int i;=0A= /**/ for (i =3D 0, oop =3D oopTable; oop < = &oopTable[oldOopTableIndex]; oop++, i++) {=0A= /**/ if (!(oop->flags & F_REACHABLE)) {=0A= /**/ printf("[%4d]: "); fflush(stdout);=0A= /**/ printObject(oop);=0A= /**/ printf("\n");=0A= /**/ fflush(stdout);=0A= /**/ }=0A= /**/ }=0A= /**/ }=0A= #endif /* DEBUG_FREED Mon Jul 3 00:38:46 1995 */=0A= }=0A= =0A= #define tailMarkOOP(newOOP) { \=0A= oop =3D (newOOP); \=0A= continue; /* tail recurse!!! */ \=0A= }=0A= =0A= #define tailMarkOOPRange(firstOOP, oopAtEnd) { \=0A= curOOP =3D (OOP *)(firstOOP); \=0A= atEndOOP =3D (OOP *)(oopAtEnd); \=0A= oop =3D nil; \=0A= continue; \=0A= }=0A= =0A= /*=0A= * static void markAnOOPInternal(oop, curOOP, atEndOOP)=0A= *=0A= * Description=0A= *=0A= * The transitive marker. This function works in two ways:=0A= * a) when oop is nil, it walks the list of pointers to OOPs=0A= * starting at curOOP (included) and finishing at atEndOOP=0A= * (excluded). Each object in the list is then marked.=0A= * b) when oop is not nil, it tail recurses telling itself to=0A= * mark the pointers referred to by the object pointed to by oop.=0A= * Note that a single function does both these jobs to allow a=0A= * fast, tail-recursive implementation of single-object marking.=0A= *=0A= * It is called a transitive marker because the recursive approach=0A= * is an algorithmic representation of the transitive property: if=0A= * A (in the root set) refers to B, and B refers to C, then A indi-=0A= * rectly refers to C and C is to be considered reachable.=0A= * This function does not mark weak objects, for obvious reasons.=0A= *=0A= * Input=0A= * see above=0A= */=0A= void=0A= markAnOOPInternal(oop, curOOP, atEndOOP)=0A= register OOP oop;=0A= register OOP *curOOP;=0A= OOP *atEndOOP;=0A= {=0A= for (;;) {=0A= if (!oop) { /* in the loop! */=0A= #ifndef OPTIMIZE=0A= mst_Object obj =3D (mst_Object) (curOOP - 1); /* for debugging */=0A= #endif=0A= iterationLoop:=0A= /* in a loop, do next iteration */=0A= oop =3D *curOOP;=0A= curOOP++;=0A= if (isOOP(oop)) {=0A= #ifndef OPTIMIZE=0A= if (!isOOPAddr(oop)) {=0A= printf("Error! Invalid OOP %p was found inside %p!\n", oop, obj);=0A= debug();=0A= } else=0A= #endif=0A= if (!isOOPMarked(oop)) {=0A= if (curOOP < atEndOOP) {=0A= markAnOOPInternal(oop, nil, nil);=0A= goto iterationLoop;=0A= } else {=0A= /* On the last object in the set, reuse the current invocation.=0A= * oop is valid, so we go to the single-object case */=0A= continue;=0A= }=0A= }=0A= }=0A= /* We reach this point if the object isn't to be marked. The code = above=0A= contains a continue to tail recurse, so we cannot put the loop = in a=0A= do...while and a goto is necessary here. Speed is a = requirement, so=0A= I'm doing it. */=0A= if (curOOP < atEndOOP) {=0A= goto iterationLoop;=0A= }=0A= } else { /* just starting with this oop */=0A= OOP objClass;=0A= mst_Object object;=0A= unsigned long size;=0A= =0A= #ifndef OPTIMIZE=0A= if (isOOPFree(oop)) {=0A= printf("Error! Free OOP %p is being marked!\n", oop);=0A= debug();=0A= break;=0A= }=0A= if (!isPooled(oop) && !isObjAddr(oopToObj(oop))) {=0A= printf("Error! OOP at %p points to invalid object data at = %p!\n", oop, oop->object);=0A= debug();=0A= break;=0A= }=0A= #endif=0A= /* see if the object has pointers, set up to copy them if so. */=0A= oop->flags |=3D F_REACHABLE;=0A= object =3D oopToObj(oop);=0A= objClass =3D object->objClass;=0A= if (oop->flags & F_CONTEXT) {=0A= MethodContext ctx;=0A= long methodSP;=0A= ctx =3D (MethodContext) object;=0A= methodSP =3D toInt(ctx->spOffset);=0A= /* printf("setting up for loop on context %x, sp =3D %d\n", ctx, = methodSP); */=0A= tailMarkOOPRange(&ctx->objClass, ctx->contextStack + methodSP + = 1);=0A= =0A= } else if (oop->flags & F_WEAK) {=0A= if (!isOOPMarked(objClass)) {=0A= tailMarkOOP(objClass);=0A= }=0A= =0A= } else {=0A= size =3D numOOPs(object);=0A= if (size) {=0A= tailMarkOOPRange(&object->objClass, object->data + size);=0A= } else if (!isOOPMarked(objClass)) {=0A= tailMarkOOP(objClass);=0A= }=0A= }=0A= }=0A= /* This point is reached if and only if nothing has to be marked = anymore in=0A= the current iteration. So exit. */=0A= break;=0A= } /* for(;;) */=0A= }=0A= =0A= /*=0A= * void refreshOOPFreeList()=0A= *=0A= * Description=0A= *=0A= * Iterate through the OOP table. Rebuild the free OOP list.=0A= *=0A= */=0A= void=0A= refreshOOPFreeList()=0A= {=0A= register OOP newFirstFree, oop;=0A= =0A= /* The free list will be reconstructed */=0A= newFirstFree =3D NULL;=0A= numFreeOOPs =3D oopTableSize;=0A= =0A= /* Proceed backwards so that the first free OOPs are at the head of the=0A= free list. This minimizes the amount of space used by the OOP = table in=0A= a saved image. */=0A= =0A= for (oop =3D &oopTable[oopTableSize - 1]; oop >=3D oopTable; oop--) {=0A= if (oop->flags & F_FREE) {=0A= oop->object =3D (mst_Object) newFirstFree;=0A= newFirstFree =3D oop;=0A= } else {=0A= lastUsedOOP =3D oop;=0A= numFreeOOPs--;=0A= break;=0A= }=0A= }=0A= while(--oop >=3D oopTable) {=0A= if (oop->flags & F_FREE) {=0A= oop->object =3D (mst_Object) newFirstFree;=0A= newFirstFree =3D oop;=0A= } else {=0A= numFreeOOPs--;=0A= }=0A= }=0A= firstFreeOOP =3D newFirstFree;=0A= }=0A= =0A= /*=0A= * static unsigned long prepareForSweep(bottom) [was: = reverseOOPPointers]=0A= *=0A= * Description=0A= *=0A= * Iterate through the OOP table. On marked OOPs, store=0A= * the pointer to the object's class into the OOP and the OOP pointer=0A= * where the object class usually is. This allows the sweep phase to=0A= * change the OOPs as it moves objects in memory. Also mark specially=0A= * objects to be finalized.=0A= *=0A= * Inputs=0A= *=0A= * bottom: The base address over which we can start to reverse pointers=0A= *=0A= * Outputs=0A= *=0A= * The number of bytes to be allocated for reachable pooled objects.=0A= */=0A= unsigned long=0A= prepareForSweep(bottom)=0A= voidPtr bottom;=0A= {=0A= register OOP newFirstFree, oop;=0A= register mst_Object object;=0A= register unsigned long pooledSize;=0A= =0A= /* The free list will be reconstructed, but the unused OOPs are = unchanged */=0A= newFirstFree =3D firstFreeOOP;=0A= numFreeOOPs =3D oopTableSize;=0A= pooledSize =3D 0;=0A= =0A= resetBuffer();=0A= =0A= /* Proceed backwards so that the first free OOPs are at the head of the=0A= free list. This minimizes the amount of space used by the OOP = table in=0A= a saved image. */=0A= =0A= for (oop =3D lastUsedOOP; oop >=3D oopTable; oop--) {=0A= if (oop->flags & F_WEAK) {=0A= checkWeakRefs(oop);=0A= }=0A= =0A= if (oop->flags & (F_FINALIZE | F_REACHABLE)) {=0A= if (oop->flags & F_POOLED) {=0A= /* Reachable pooled object. Get it to the heap. */=0A= pooledSize +=3D size2Bytes(oopToObj(oop)->objSize);=0A= =0A= } else if (((voidPtr) oop->object) >=3D bottom) {=0A= /* Object reachable after mark phase. Reverse the pointer */=0A= object =3D oopToObj(oop);=0A= oop->object =3D (mst_Object)object->objClass;=0A= object->objClass =3D markObject(oop);=0A= }=0A= =0A= if (!(oop->flags & F_REACHABLE)) {=0A= /* Object is *going* to be finalized, but it was not yet. We = found a=0A= * weak reference to it, so we mark it so that finalization will = occur=0A= * soon after the end of the sweep pass. In the meanwhile, we = let it=0A= * survive and decide the object's fate at the next GC pass */=0A= oop->flags ^=3D F_FINALIZE;=0A= addBufPointer(oop);=0A= }=0A= oop->flags &=3D ~F_REACHABLE;=0A= numFreeOOPs--;=0A= =0A= } else if (!(oop->flags & F_FREE)) {=0A= /* Object not marked and not already freed. Add to OOP free list = */=0A= oop->flags =3D F_FREE;=0A= oop->object =3D (mst_Object) newFirstFree;=0A= newFirstFree =3D oop;=0A= if (oop =3D=3D lastUsedOOP) {=0A= lastUsedOOP--;=0A= }=0A= }=0A= }=0A= =0A= firstFreeOOP =3D newFirstFree;=0A= =0A= #ifdef USE_JIT_TRANSLATION=0A= /* Go and really free the blocks associated to garbage collected=0A= * native code. */=0A= freeNativeCode();=0A= #endif=0A= =0A= return (pooledSize);=0A= }=0A= =0A= /*=0A= * static void sweepPooledContexts(dest)=0A= *=0A= * Description=0A= *=0A= * Iterate through the OOP table. Copy pooled, marked objects=0A= * to the main heap space (starting at address dest), free the=0A= * others.=0A= *=0A= */=0A= void=0A= sweepPooledContexts(dest)=0A= register char *dest;=0A= {=0A= register OOP oop;=0A= register unsigned long size;=0A= =0A= for (oop =3D lastUsedOOP; oop >=3D oopTable; oop--) {=0A= if (oop->flags & F_POOLED) {=0A= size =3D size2Bytes(oopToObj(oop)->objSize);=0A= memcpy(dest, oop->object, size);=0A= oop->object =3D (mst_Object) dest;=0A= oop->flags &=3D ~(F_POOLED | F_REACHABLE);=0A= dest +=3D size;=0A= }=0A= }=0A= emptyContextPool();=0A= }=0A= =0A= /* #define SWEEP_DEBUG */=0A= static inline void=0A= sweepOOPs(bottom)=0A= char *bottom;=0A= {=0A= register char *from, *fromStart, *to;=0A= unsigned long chunkSize, pooledSize;=0A= register mst_Object object;=0A= OOP curClass, oop;=0A= =0A= pooledSize =3D prepareForSweep(bottom);=0A= =0A= /* Algorithm:=0A= initialize:=0A= * Start at beginning of allocated space.=0A= * Skip over the initial contiguous range of marked object, unmarking=0A= as you go.=0A= =0A= loop:=0A= * skip over the contiguous range of unmarked objects, leaving "to"=0A= where it is and advancing "from".=0A= * if "to" passes the end of allocated storage, we are done.=0A= * set "fromStart" to "from", and skip over the next contiguous = range of=0A= marked objects, advancing "from".=0A= * copy the range ["fromStart".."from") to "to". advance "to" to = right=0A= after the newly copied area.=0A= */=0A= =0A= from =3D to =3D bottom;=0A= =0A= while (to < memSpace.allocPtr) {=0A= object =3D (mst_Object)to;=0A= if (!isMarked(object)) {=0A= /* found the end of the contiguous range */=0A= break;=0A= }=0A= /* unmark this dude */=0A= oop =3D unmarkObject(object->objClass);=0A= curClass =3D (OOP)oop->object;=0A= oop->object =3D object;=0A= object->objClass =3D curClass;=0A= =0A= to +=3D size2Bytes(object->objSize);=0A= }=0A= =0A= #ifdef SWEEP_DEBUG=0A= printf("skipped %d bytes of contig alloc %x space %x max %x\n",=0A= to - memSpace.space, memSpace.allocPtr, memSpace.space,=0A= memSpace.maxPtr);=0A= #endif /* SWEEP_DEBUG */=0A= =0A= /* we've skipped over the marked initial set of objects, for which=0A= * no move is necessary. Now begin the main execution loop=0A= */=0A= =0A= from =3D to;=0A= while (from < memSpace.allocPtr) {=0A= fromStart =3D from; /* debugging only */=0A= while (from < memSpace.allocPtr) {=0A= object =3D (mst_Object)from;=0A= if (isMarked(object)) {=0A= /* found a non-free chunk */=0A= break;=0A= }=0A= =0A= /* skip over the free memory */=0A= from +=3D size2Bytes(object->objSize);=0A= }=0A= =0A= #ifdef SWEEP_DEBUG=0A= printf("skipped free range %x .. %x %d bytes\n", fromStart, from, = from - fromStart);=0A= #endif /* SWEEP_DEBUG */=0A= =0A= if (from >=3D memSpace.allocPtr) {=0A= #ifdef SWEEP_DEBUG=0A= printf("hit end of memory\n");=0A= #endif /* SWEEP_DEBUG */=0A= break; /* we've hit the end of active memory */=0A= }=0A= =0A= fromStart =3D from;=0A= /* span the next in-use contiguous chunk of objects */=0A= while (from < memSpace.allocPtr) {=0A= object =3D (mst_Object)from;=0A= if (!isMarked(object)) {=0A= /* found a free chunk */=0A= break;=0A= }=0A= =0A= /* unmark this dude & tell the oop where the object *will be* */=0A= oop =3D unmarkObject(object->objClass);=0A= curClass =3D (OOP)oop->object;=0A= oop->object =3D (mst_Object)(to + ((char *)object - fromStart));=0A= object->objClass =3D curClass;=0A= =0A= /* skip over the object */=0A= from +=3D size2Bytes(object->objSize);=0A= }=0A= =0A= =0A= /* copy the bytes down */=0A= chunkSize =3D from - fromStart;=0A= #ifdef SWEEP_DEBUG=0A= printf("copying range %x .. %x to %x, %d bytes\n",=0A= fromStart, from, to, chunkSize);=0A= #endif /* SWEEP_DEBUG */=0A= =0A= memcpy(to, fromStart, chunkSize);=0A= to +=3D chunkSize;=0A= }=0A= =0A= memSpace.allocPtr =3D to;=0A= =0A= object =3D allocObj(pooledSize);=0A= sweepPooledContexts((char *) object);=0A= memSpace.newAllocPtr =3D memSpace.allocPtr;=0A= }=0A= =0A= void=0A= markFinalizableOOPReferences()=0A= {=0A= register OOP oop;=0A= =0A= for (oop =3D oopTable; oop <=3D lastUsedOOP; oop++) {=0A= /* A finalizable object will always survive this GC flip, even if it = is=0A= not reachable. We mark the objects that they refer to, so they = survive=0A= too, keeping the finalizable object marked as unreachable. */=0A= =0A= if ((oop->flags & (F_FINALIZE | F_REACHABLE)) =3D=3D F_FINALIZE) {=0A= markAnOOPInternal(oop, nil, nil);=0A= oop->flags ^=3D F_REACHABLE;=0A= }=0A= }=0A= }=0A= =0A= #if !HAVE_MMAP=0A= /*=0A= * static void initSpace(space)=0A= *=0A= * Description=0A= *=0A= * Initializes the allocation and copying pointers for space SPACE.=0A= *=0A= * Inputs=0A= *=0A= * space : Pointer to the struct memorySpaceStruct to be initialized.=0A= *=0A= */=0A= void=0A= initSpace(space)=0A= struct memorySpaceStruct *space;=0A= {=0A= space->space =3D (char *)xmalloc(maxSpaceSize + NEW_GENERATION_SIZE);=0A= space->totalSize =3D maxSpaceSize;=0A= space->allocPtr =3D space->space;=0A= space->newAllocPtr =3D space->space;=0A= space->maxPtr =3D space->space + space->totalSize;=0A= }=0A= #endif=0A= =0A= =0C=0A= =0A= #ifdef GC_TORTURE=0A= =0A= /*=0A= * void startGCTorture()=0A= *=0A= * Description=0A= *=0A= * User level debugging routine to verify correct operation in a range of=0A= * code. Invoking this function ensures that the GC torturing is on.=0A= * Calls to this function and stopGCTorture nest, so only the outermost=0A= * call really has an effect.=0A= *=0A= * GC torturing means that the garbage collector is run on every=0A= * allocation. This means that objects which are not reachable from the=0A= * root set will be immediately freed.=0A= *=0A= */=0A= void=0A= startGCTorture()=0A= {=0A= doGCTorture =3D true;=0A= doTortureCounter++;=0A= }=0A= =0A= =0A= /*=0A= * void stopGCTorture()=0A= *=0A= * Description=0A= *=0A= * User level debugging routine associated with startGCTorture. Turns = off=0A= * the GC torturing if it's the outermost (in an invocation-stacking=0A= * order) one, otherwise, just decrements the torture count.=0A= *=0A= */=0A= void=0A= stopGCTorture()=0A= {=0A= if (doTortureCounter > 0) {=0A= if (--doTortureCounter =3D=3D 0) { /* on the transition to 0... */=0A= doGCTorture =3D false;=0A= }=0A= }=0A= }=0A= =0A= #endif=0A= =0A= =0C=0A= =0A= /***********************************************************************=0A= *=0A= * Incubator support routines=0A= *=0A= ***********************************************************************/=0A= =0A= void=0A= incInitRegistry()=0A= {=0A= incOOPBasePtr =3D (OOP*)xmalloc(INIT_NUM_INCUBATOR_OOPS * sizeof(OOP = *));=0A= incOOPPtr =3D incOOPBasePtr;=0A= incOOPEndPtr =3D incOOPBasePtr + INIT_NUM_INCUBATOR_OOPS;=0A= }=0A= =0A= void=0A= incGrowRegistry()=0A= {=0A= OOP* oldBase;=0A= unsigned long oldPtrOffset;=0A= unsigned long oldRegistrySize, newRegistrySize;=0A= =0A= oldBase =3D incOOPBasePtr;=0A= oldPtrOffset =3D incOOPPtr - incOOPBasePtr;=0A= oldRegistrySize =3D incOOPEndPtr - incOOPBasePtr;=0A= =0A= newRegistrySize =3D oldRegistrySize + INCUBATOR_CHUNK_SIZE;=0A= =0A= incOOPBasePtr =3D (OOP *)xrealloc(incOOPBasePtr, newRegistrySize * = sizeof(OOP *));=0A= incOOPPtr =3D incOOPBasePtr + oldPtrOffset;=0A= incOOPEndPtr =3D incOOPBasePtr + newRegistrySize;=0A= }=0A= =0A= void=0A= markIncubatorOOPs()=0A= {=0A= markOOPRange(incOOPBasePtr, incOOPPtr);=0A= }=0A= ------=_NextPart_000_0000_01C080B6.ADFE47E0 Content-Type: text/plain; name="oop.h" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="oop.h" /******************************** -*- C -*- ****************************=0A= *=0A= * Object Table declarations.=0A= *=0A= * $Revision: 1.8.5$=0A= * $Date: 2000/12/27 10:45:49$=0A= * $Author: pb$=0A= *=0A= ***********************************************************************/=0A= =0A= /***********************************************************************=0A= *=0A= * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.=0A= * Written by Steve Byrne.=0A= *=0A= * This file is part of GNU Smalltalk.=0A= *=0A= * GNU Smalltalk is free software; you can redistribute it and/or modify = it=0A= * under the terms of the GNU General Public License as published by the = Free=0A= * Software Foundation; either version 2, or (at your option) any later =0A= * version.=0A= * =0A= * GNU Smalltalk is distributed in the hope that it will be useful, but = WITHOUT=0A= * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or =0A= * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License = for=0A= * more details.=0A= * =0A= * You should have received a copy of the GNU General Public License = along with=0A= * GNU Smalltalk; see the file COPYING. If not, write to the Free = Software=0A= * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =0A= *=0A= ***********************************************************************/=0A= =0A= =0A= =0A= #ifndef __GSTOOP__=0A= #define __GSTOOP__=0A= =0A= #define NUM_CHAR_OBJECTS 256=0A= #define NUM_BUILTIN_OBJECTS 3=0A= #define FIRST_OOP_INDEX (-NUM_CHAR_OBJECTS-NUM_BUILTIN_OBJECTS)=0A= #define CHAR_OBJECT_BASE FIRST_OOP_INDEX=0A= #define BUILTIN_OBJECT_BASE (-NUM_BUILTIN_OBJECTS)=0A= =0A= /* The number of OOPs in the system. This is exclusive of Character, = True,=0A= False, and UndefinedObject (nil) oops, which are built-ins. */=0A= #define INITIAL_OOP_TABLE_SIZE (1024 * 128 + BUILTIN_OBJECT_BASE)=0A= #define MAX_OOP_TABLE_SIZE (1024 * 1024 * 8)=0A= #define MAX_OBJECT_DATA_SIZE (1024 * 1024 * 256)=0A= =0A= /* The number of free OOPs under which we trigger GCs. 0 is not enough=0A= * because gcFlip might still need some oops in emptyContextStack!!! */=0A= #define LOW_WATER_OOP_THRESHOLD (1024 * 2)=0A= =0A= #define smalltalkOOPIndex 0=0A= #define processorOOPIndex 1=0A= #define symbolTableOOPIndex 2=0A= #define nilOOPIndex (BUILTIN_OBJECT_BASE + 0)=0A= #define trueOOPIndex (BUILTIN_OBJECT_BASE + 1)=0A= #define falseOOPIndex (BUILTIN_OBJECT_BASE + 2)=0A= =0A= /*=0A= * Given a number of bytes "x", return the number of 32 bit words=0A= * needed to represent that object, rounded up to the nearest 32 bit=0A= * word boundary.=0A= */=0A= #define ROUNDED_WORDS(x) \=0A= (((x) + sizeof(long) - 1) / sizeof(long))=0A= =0A= =0A= =0A= typedef struct CharObjectStruct {=0A= OBJ_HEADER;=0A= #if defined(WORDS_BIGENDIAN)=0A= Byte dummy[3]; /* filler */=0A= Byte charVal;=0A= #else=0A= Byte charVal;=0A= Byte dummy[3]; /* filler */=0A= #endif=0A= } CharObject;=0A= =0A= struct NilObjectStruct {=0A= OBJ_HEADER;=0A= };=0A= =0A= struct BooleanObjectStruct {=0A= OBJ_HEADER;=0A= OOP booleanValue;=0A= };=0A= =0A= struct memorySpaceStruct {=0A= char *space; /* base of allocated storage */=0A= char *allocPtr; /* new space ptr, starts low, goes up */=0A= char *maxPtr; /* points to highest addr in heap */=0A= char *newAllocPtr; /* new space ptr, starts low, goes up */=0A= unsigned long totalSize; /* current allocated size */=0A= };=0A= =0A= /* numFreeOOPs is only correct after a GC! */=0A= extern int numFreeOOPs, oopTableSize;=0A= extern CharObject charObjectTable[];=0A= extern struct NilObjectStruct nilObject;=0A= extern struct BooleanObjectStruct booleanObjects[];=0A= extern mst_Boolean gcState, gcMessage;=0A= =0A= extern int growThresholdPercent, spaceGrowRate;=0A= =0A= extern OOP /* allocOOP(), */ charOOPAt(), findAnInstance();=0A= extern void initOOP(), setOOPAt(), swapObjects(), =0A= fixupMetaclassObjects(), moveOOP(), gcFlip(),=0A= minorGCFlip(), setSpaceInfo(), growBothSpaces(),=0A= initMem(), initOOPTable(),=0A= markAnOOPInternal(), printObject(),=0A= /* initCharTable(), initNil(), initBooleans(), */=0A= initBuiltinObjectsClasses(),=0A= refreshOOPFreeList(),=0A= incInitRegistry(), incGrowRegistry();=0A= extern Byte charOOPValue();=0A= extern mst_Object allocObj(), curSpaceAddr();=0A= extern mst_Boolean oopIndexValid(), gcOn(), gcOff(), setGCState(),=0A= growTo(), growMemoryTo(), reallocOOPTable();=0A= =0A= extern struct OOPStruct *oopTable, *allOopsTable;=0A= extern OOP lastUsedOOP;=0A= =0A= /* This variable represents information about the memory space. memSpace=0A= holds the required information: basically the pointer to the base and=0A= top of the space, and the pointers into it for allocation and copying.=0A= */=0A= extern struct memorySpaceStruct memSpace;=0A= =0A= #include "oop.inl"=0A= =0A= #endif /* __GSTOOP__ */=0A= ------=_NextPart_000_0000_01C080B6.ADFE47E0 Content-Type: application/octet-stream; name="oop.inl" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="oop.inl" /******************************** -*- C -*- ****************************=0A= *=0A= * Object table module Inlines.=0A= *=0A= * $Revision: 1.8.5$=0A= * $Date: 2000/12/27 10:45:49$=0A= * $Author: pb$=0A= *=0A= ***********************************************************************/=0A= =0A= /***********************************************************************=0A= *=0A= * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.=0A= * Written by Steve Byrne.=0A= *=0A= * This file is part of GNU Smalltalk.=0A= *=0A= * GNU Smalltalk is free software; you can redistribute it and/or modify = it=0A= * under the terms of the GNU General Public License as published by the = Free=0A= * Software Foundation; either version 2, or (at your option) any later =0A= * version.=0A= * =0A= * GNU Smalltalk is distributed in the hope that it will be useful, but = WITHOUT=0A= * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or =0A= * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License = for=0A= * more details.=0A= * =0A= * You should have received a copy of the GNU General Public License = along with=0A= * GNU Smalltalk; see the file COPYING. If not, write to the Free = Software=0A= * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =0A= *=0A= ***********************************************************************/=0A= =0A= =0A= #ifndef __GSTOOP_INLINES__=0A= #define __GSTOOP_INLINES__=0A= =0A= #include "alloc.h"=0A= =0A= static inline OOP allocOOP();=0A= =0A= #define maybeMarkOOP(oop) do { \=0A= if (isOOP(oop) && !isOOPMarked(oop)) { \=0A= markAnOOPInternal(oop, nil, nil); \=0A= } \=0A= } while(0);=0A= =0A= #define markOOPRange(startOOP, endOOP) do { \=0A= if ((startOOP) < (endOOP)) { \=0A= markAnOOPInternal(nil, startOOP, endOOP); \=0A= } \=0A= } while(0);=0A= =0A= /* In the non-incremental GC world, being FREE is all that matters for=0A= * validity.=0A= */=0A= #define oopValid(oop) \=0A= (!(oop->flags & F_FREE))=0A= =0A= #define oopAt(index) \=0A= ( &oopTable[index] )=0A= =0A= #define oopAvailable(index) \=0A= ( oopTable[index].flags & F_FREE )=0A= =0A= #define oopIndex(oop) \=0A= ( (OOP)(oop) - oopTable )=0A= =0A= #define setOOPObject(oop, obj) do { \=0A= (oop)->object =3D (mst_Object) (obj); \=0A= } while(0);=0A= =0A= #define freeOOP(oop) do { \=0A= extern OOP firstFreeOOP; \=0A= register OOP _theOOP =3D (oop); \=0A= _theOOP->flags =3D F_FREE; \=0A= -theOOP->object =3D (mst_Object) firstFreeOOP; \=0A= firstFreeOOP =3D _theOOP; \=0A= } while(0);=0A= =0A= #define isOOPAddr(addr) \=0A= ((OOP)(addr) >=3D allOopsTable && (OOP)(addr) < = &oopTable[oopTableSize] \=0A= && (((long)addr & (SIZEOF_LONG - 1)) =3D=3D 0))=0A= =0A= #define isObjAddr(addr) \=0A= ((char *)(addr) >=3D memSpace.space && (char *)(addr) < = memSpace.maxPtr \=0A= && (((long)(addr) & (SIZEOF_LONG - 1)) =3D=3D 0))=0A= =0A= #include "gst.h"=0A= #include "lex.h"=0A= #include "dict.h"=0A= =0A= =0A= =0C=0A= =0A= /*=0A= * OOP allocOOP(obj)=0A= *=0A= * Description=0A= *=0A= * Given an object OBJ, this routine allocates an OOP table slot for it=0A= * and returns it. It marks the OOP so that it indicates the object is = in=0A= * new space, and that the oop has been referenced on this pass (to keep=0A= * the OOP table reaper from reclaiming this OOP).=0A= *=0A= * Inputs=0A= *=0A= * obj : Object that the new OOP should point to.=0A= *=0A= * Outputs=0A= *=0A= * An OOP, which is the address of an element in the OOP table.=0A= */=0A= static inline OOP allocOOP(obj)=0A= mst_Object obj;=0A= {=0A= REGISTER(1, OOP oop);=0A= extern OOP firstFreeOOP;=0A= =0A= if(numFreeOOPs-- < LOW_WATER_OOP_THRESHOLD) {=0A= int newSize;=0A= gcFlip();=0A= =0A= if(numFreeOOPs < (oopTableSize * growThresholdPercent / 100)) {=0A= newSize =3D oopTableSize * (spaceGrowRate + 100) / 100;=0A= if (newSize - oopTableSize < LOW_WATER_OOP_THRESHOLD) {=0A= newSize =3D oopTableSize + LOW_WATER_OOP_THRESHOLD;=0A= }=0A= reallocOOPTable(newSize);=0A= if(numFreeOOPs < LOW_WATER_OOP_THRESHOLD) {=0A= nomemory(true);=0A= }=0A= }=0A= }=0A= =0A= oop =3D firstFreeOOP;=0A= firstFreeOOP =3D (OOP)oop->object;=0A= if (oop > lastUsedOOP) {=0A= lastUsedOOP =3D oop;=0A= }=0A= =0A= #ifndef OPTIMIZE=0A= if (!(oop->flags & F_FREE)) {=0A= errorf("Non-free OOP in OOP free list!!!");=0A= exit(1);=0A= }=0A= #endif=0A= =0A= oop->object =3D obj;=0A= oop->flags =3D 0; /* no flags on this one */=0A= return (oop);=0A= }=0A= =0A= #endif=0A= ------=_NextPart_000_0000_01C080B6.ADFE47E0 Content-Type: text/plain; name="heap.h" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="heap.h" /******************************** -*- C -*- ****************************=0A= *=0A= * Header for memory allocation within separate mmap'ed regions=0A= *=0A= * $Revision: 1.8.5$=0A= * $Date: 2000/12/27 10:45:49$=0A= * $Author: pb$=0A= *=0A= ***********************************************************************/=0A= =0A= /***********************************************************************=0A= *=0A= * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.=0A= * Written by Paolo Bonzini.=0A= *=0A= * This file is part of GNU Smalltalk.=0A= *=0A= * GNU Smalltalk is free software; you can redistribute it and/or modify = it=0A= * under the terms of the GNU General Public License as published by the = Free=0A= * Software Foundation; either version 2, or (at your option) any later =0A= * version.=0A= * =0A= * GNU Smalltalk is distributed in the hope that it will be useful, but = WITHOUT=0A= * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or =0A= * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License = for=0A= * more details.=0A= * =0A= * You should have received a copy of the GNU General Public License = along with=0A= * GNU Smalltalk; see the file COPYING. If not, write to the Free = Software=0A= * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =0A= ***********************************************************************/=0A= =0A= =0A= #ifndef __GSTHEAP__=0A= #define __GSTHEAP__=0A= =0A= #include "gst.h"=0A= =0A= typedef char *heap;=0A= =0A= extern heap heap_create ();=0A= =0A= extern heap heap_destroy ();=0A= =0A= extern voidPtr heap_sbrk ();=0A= =0A= #endif /* __GSTHEAP__ */=0A= ------=_NextPart_000_0000_01C080B6.ADFE47E0--