/* Little Smalltalk, version 2 Written by Tim Budd, Oregon State University, July 1987 */ # define streq(a,b) (strcmp(a,b) == 0) /* The first major decision to be made in the memory manager is what an entity of type object really is. Two obvious choices are a pointer (to the actual object memory) or an index into an object table. We decided to use the latter, although either would work. Similarly, one can either define the token object using a typedef, or using a define statement. Either one will work (check this?) */ typedef short object; /* The memory module itself is defined by over a dozen routines. All of these could be defined by procedures, and indeed this was originally done. However, for efficiency reasons, many of these procedures can be replaced by macros generating in-line code. For the latter approach to work, the structure of the object table must be known. For this reason, it is given here. Note, however, that ONLY the macros described in this file make use of this structure: therefore modifications or even complete replacement is possible as long as the interface remains consistent */ struct objectStruct { object class; short referenceCount; byte size; byte type; object *memory; }; #ifndef A_ST extern struct objectStruct objectTable[]; #else extern struct objectStruct *objectTable; #endif /* types of object memory */ # define objectMemory 0 # define byteMemory 1 # define charMemory 2 # define floatMemory 3 #ifdef A_ST # define isString(x) (((objectTable + (x>>1))->type == charMemory) || ((objectTable + (x>>1))->type == byteMemory)) # define isFloat(x) ((objectTable + (x>>1))->type == floatMemory) #else # define isString(x) ((objectTable[x>>1].type == charMemory) || (objectTable[x>>1].type == byteMemory)) # define isFloat(x) (objectTable[x>>1].type == floatMemory) #endif /* The most basic routines to the memory manager are incr and decr, which increment and decrement reference counts in objects. By separating decrement from memory freeing, we could replace these as procedure calls by using the following macros: */ extern object incrobj; #ifdef A_ST # define incr(x) if ((incrobj=(x))&&!isInteger(incrobj)) (objectTable + (incrobj>>1))->referenceCount++ # define decr(x) if (((incrobj=x)&&!isInteger(incrobj))&&(--(objectTable + (incrobj>>1))->referenceCount<=0)) sysDecr(incrobj); #else # define incr(x) if ((incrobj=(x))&&!isInteger(incrobj)) objectTable[incrobj>>1].referenceCount++ # define decr(x) if (((incrobj=x)&&!isInteger(incrobj))&&(--objectTable[incrobj>>1].referenceCount<=0)) sysDecr(incrobj); #endif /* notice that the argument x is first assigned to a global variable; this is in case evaluation of x results in side effects (such as assignment) which should not be repeated. */ extern noreturn sysDecr(OBJ); # ifndef incr extern void incr(OBJ); # endif # ifndef decr extern void decr(OBJ); # endif /* The next most basic routines in the memory module are those that allocate blocks of storage. There are three routines: allocObject(size) - allocate an array of objects allocByte(size) - allocate an array of bytes allocChar(size) - allocate an array of character values allocSymbol(value) - allocate a string value allocInt(value) - allocate an integer value allocFloat(value) - allocate a floating point object again, these may be macros, or they may be actual procedure calls */ extern object alcObject(INT X INT); /* the actual routine */ # define allocObject(size) alcObject(size, objectMemory) # define allocByte(size) alcObject(((size)+1)/2, byteMemory) # define allocChar(size) alcObject(((size)+1)/2, charMemory) extern object allocSymbol(STR); # define allocInt(value) ((value<0)?value:(value<<1)+1) extern object allocFloat(FLOAT); /* integer objects are (but need not be) treated specially. In this memory manager, negative integers are just left as is, but positive integers are changed to x*2+1. Either a negative or an odd number is therefore an integer, while a nonzero even number is an object pointer (multiplied by two). Zero is reserved for the object ``nil'' Since newInteger does not fill in the class field, it can be given here. If it was required to use the class field, it would have to be deferred until names.h */ extern object intobj; # define isInteger(x) ((x) & 0x8001) # define newInteger(x) ( (intobj = x)<0 ? intobj : (intobj<<1)+1 ) # define intValue(x) ( (intobj = x)<0 ? intobj : (intobj>>1) ) /* in addition to alloc floating point routine given above, another routine must be provided to go the other way. Note that the routine newFloat, which fills in the class field as well, must wait until the global name table is known, in names.h */ extern double floatValue(OBJ); /* there are four routines used to access fields within an object. Again, some of these could be replaced by macros, for efficiency basicAt(x, i) - ith field (start at 1) of object x basicAtPut(x, i, v) - put value v in object x byteAt(x, i) - ith field (start at 0) of object x byteAtPut(x, i, v) - put value v in object x # define basicAt(x,i) (sysMemPtr(x)[i-1]) */ # define byteAt(x, i) (charPtr(x)[i-1]) # ifndef basicAt extern object basicAt(OBJ X INT); # endif # ifndef basicAtPut extern void basicAtPut(OBJ X INT X OBJ); # endif # ifndef byteAt extern int byteAt(OBJ X INT); # endif # ifndef byteAtPut extern void byteAtPut(OBJ X INT X INT); # endif /* Finally, a few routines (or macros) are used to access or set class fields and size fields of objects */ #ifdef A_ST # define classField(x) (objectTable + (x>>1))->class # define setClass(x,y) incr(classField(x)=y) # define objectSize(x) byteToInt((objectTable + (x>>1))->size) # define sysMemPtr(x) (objectTable + (x>>1))->memory #else # define classField(x) objectTable[x>>1].class # define setClass(x,y) incr(classField(x)=y) # define objectSize(x) byteToInt(objectTable[x>>1].size) # define sysMemPtr(x) objectTable[x>>1].memory #endif extern object sysobj; # define memoryPtr(x) (isInteger(sysobj = x)?(object *) 0:sysMemPtr(sysobj)) # define bytePtr(x) ((byte *) memoryPtr(x)) # define charPtr(x) ((char *) memoryPtr(x)) # define nilobj (object) 0 /* these two objects are the source of all objects in the system */ extern object symbols; extern object globalNames; extern noreturn sysError (STR X STR); extern boolean debugging; extern noreturn initMemoryManager(NOARGS); extern noreturn imageRead(FILEP); extern noreturn imageWrite(FILEP); loc