

// Object.h -- Squeak object format and common classes
//
// Author: Ian.Piumarta@INRIA.Fr
//
// last edited: 2000-11-28 14:59:31 by piumarta on emilia.rd.wdi.disney.com
//
// BUGS
//	A significant portion of this file is no longer used (being left
//	over from J[12]) and should be identified then excised.


#ifndef _j_Object_h
#define _j_Object_h


#include "debug.h"


#undef	MARK_OLD


// well-known classes


class Array;
class Association;
class BlockContext;
class Class;
class CompiledMethod;
class Context;
class ContextPart;
class Frame;
class Link;
class Message;
class Metaclass;
class MethodContext;
class NativeMethod;
class Object;
class Process;
class ProcessorScheduler;
class PseudoContext;
class Semaphore;
class SmallInteger;
class Symbol;


// types


typedef Object	     *oop;
typedef unsigned char byte;
typedef unsigned int  word;


// constants


#define NilContext	(Context *)1
#define OneRel		1

#define SmallFrame		 16
#define LargeFrame		 56

#define SmallContextSize	((1+6+SmallFrame)*4)
#define LargeContextSize	((1+6+LargeFrame)*4)

#define SymbolCCI		 2
#define PseudoContextCCI	 4
#define LargePositiveIntegerCCI	 5
#define FloatCCI		 6
#define PointCCI		 9
#define BlockContextCCI		13
#define MethodContextCCI	14


// functions imported from C


extern "C" {
  oop	  accessibleObjectAfter(const oop obj);
  void    activateNewMethod(void);
  void	 *allocateChunk(int lbs);
  void	  beRootIfOld(const oop object);
  oop	  clone(oop object);
  void	  executeNewMethod(void);
  Class	 *findClassOfMethodforReceiver(CompiledMethod *m, oop r);
  void	  findNewMethodInClass(Class *cls);
  Symbol *findSelectorOfMethodforReceiver(CompiledMethod *m, oop r);
  oop	  firstAccessibleObject(void);
  oop  	  instantiateClassindexableSize(const Class *cls, const int size);
  oop  	  instantiateSmallClasssizeInBytesfill(const Class *cls, const int lbs, const oop flr);
  bool	  isPointers(const oop obj);
  int     lastPointerOf(const oop obj);
  void	  markAndTrace(const oop obj);
  void	  noteAsRootheaderLoc(const oop obj, const oop hdr);
  void	  okayFields(const oop obj);
  void	  okayOop(const oop obj);
  void	  oopHasOkayClass(const oop obj);
  void	  possibleRootStoreIntovalue(const oop dst, const oop src);
  int	  primitiveResponse(void);
  void	  printNameOfClasscount(Class *cls, int cnt);
  void	  printStringOf(oop object);
  void	  quickCheckForInterrupts(void);
  oop     remap(const oop obj);
  void	  storeContextRegisters(Context *context);
  int	  stSizeOf(const oop obj);
};


// inline imported functions


#define pushRemappableOop(obj)	(remapBuffer[++remapBufferCount]= (obj))
#define popRemappableOop()	(remapBuffer[remapBufferCount--])
#define popRemappable(Cls)	((remapBuffer[remapBufferCount--])->as##Cls())


// Interpreter objects


extern oop		 nilObj;
extern oop		 trueObj;
extern oop		 falseObj;

extern CompiledMethod	*method;
extern Class		*methodClass;
extern CompiledMethod	*newMethod;
extern NativeMethod	*newNativeMethod;
extern Context		*activeContext;

extern int		 currentBytecode;

extern oop		 receiver;
extern MethodContext	*theHomeContext;
 
extern oop		*stackPointer;
extern int		 instructionPointer;
 
extern Symbol		*messageSelector;
extern Class		*lkupClass;
extern Class		*receiverClass;
extern int		 argumentCount;
extern int		 primitiveIndex;
extern int		 reclaimableContextCount;
extern int		 lastHash;
extern int		 interruptCheckCounter;
extern int		 nextWakeupTick;
extern int		 lastTick;
extern int		 nextPollTick;
extern int		 signalLowSpace;
extern int		 interruptPending;
extern int		 semaphoresToSignalCount;
extern int		 semaphoresToSignal[];
extern int		 successFlag;

extern Array		*specialObjectsOop;

extern oop		 remapBuffer[];
extern int		 remapBufferCount;

extern oop		 youngStart;

extern oop		 rootTable[];
extern int		 rootTableCount;
static const int	 RootTableSize= 2500;


// special objects


#define splObj(index)	(specialObjectsOop->at(index))

#define	NilObject					  splObj( 0)
#define	FalseObject					  splObj( 1)
#define	TrueObject					  splObj( 2)
#define	SchedulerAssociation		((Association	*)splObj( 3))
#define	ClassBitmap			((Class		*)splObj( 4))
#define	ClassSmallInteger		((Class		*)splObj( 5))
#define	ClassString			((Class		*)splObj( 6))
#define	ClassArray			((Class		*)splObj( 7))
#define	SmalltalkDictionary				  splObj( 8)
#define	ClassFloat			((Class		*)splObj( 9))
#define	ClassMethodContext		((Class		*)splObj(10))
#define	ClassBlockContext		((Class		*)splObj(11))
#define	ClassPoint			((Class		*)splObj(12))
#define	ClassLargePositiveInteger	((Class		*)splObj(13))
#define	TheDisplay					  splObj(14)
#define	ClassMessage			((Class		*)splObj(15))
#define	ClassCompiledMethod		((Class		*)splObj(16))
#define	TheLowSpaceSemaphore		((Semaphore	*)splObj(17))
#define	ClassSemaphore			((Class		*)splObj(18))
#define	ClassCharacter			((Class		*)splObj(19))
#define	SelectorDoesNotUnderstand	((Symbol	*)splObj(20))
#define	SelectorCannotReturn		((Symbol	*)splObj(21))
#define	TheInputSemaphore		((Semaphore	*)splObj(22))
#define	SpecialSelectors		((Array		*)splObj(23))
#define	CharacterTable			((Array		*)splObj(24))
#define	SelectorMustBeBoolean		((Symbol	*)splObj(25))
#define	ClassByteArray			((Class		*)splObj(26))
#define	ClassProcess			((Class		*)splObj(27))
#define	CompactClasses			((Array		*)splObj(28))
#define	TheTimerSemaphore		((Semaphore	*)splObj(29))
#define	TheInterruptSemaphore		((Semaphore	*)splObj(30))
#define FloatPrototype					  splObj(31)
#define LargePositiveIntPrototype			  splObj(32)
#define PointPrototype					  splObj(33)
#define	SelectorCannotInterpret		((Symbol	*)splObj(34))
#define LargeMethodContext		((MethodContext	*)splObj(35))
//	UNUSED						  splObj(36)
#define LargeBlockContext		((BlockContext	*)splObj(37))
#define	ExternalObjectsArray		((Array		*)splObj(38))
#define	ClassPseudoContext		((Class		*)splObj(39))
#define	ClassTranslatedMethod		((Class		*)splObj(40))
#define	FinalizationSemaphore		((Semaphore	*)splObj(41))

#define Processor	(SchedulerAssociation->value->asProcessorScheduler())


/// classes


class Object
{
public:
  // extra header words before object
  inline word &_xh(const int index) const
    {
      return ((word *)this)[index];
    }

  inline unsigned int _sizeHeader(void) const { return _xh(-2) & ~0x3U; }
  inline Class *_classHeader(void) const { return (Class *)(_xh(-1) & ~0x3U); }

  unsigned int _bh;		// base header

  static unsigned pseudoContextHeader;
  static unsigned floatHeader;
  static unsigned blockContextHeader;
  static unsigned methodContextHeader;

  static void initialise(void);

  static size_t const BaseHeaderSize= sizeof(unsigned int);

  inline unsigned int _baseHeader(void) const { return _bh; }

  inline unsigned int _type(void) const		{ return (_bh      ) & 0x003; }
  inline unsigned int _size(void) const		{ return (_bh >>  2) & 0x03f; }
  inline unsigned int _format(void) const	{ return (_bh >>  8) & 0x00f; }
  inline unsigned int _ccIndex(void) const	{ return (_bh >> 12) & 0x01f; }
  inline unsigned int _hashBits(void) const	{ return (_bh >> 17) & 0xfff; }

  inline static unsigned int newHash(void)
    {
      // See: ObjectMemory>>newObjectHash
      return lastHash= (13849 + (27181 * lastHash)) & 0xffff;
    }

  static const unsigned ccMask= 0x1f000;

  inline unsigned int _ccBits(void) const	{ return _bh & ccMask; }

  inline void _ccBits(unsigned int cc)
    {
      assert(cc != 0);
      assert((cc & ~ccMask) == 0);
      _bh= (_bh & ~ccMask) | cc;
    }

  inline bool isSymbol(void)	    { return _ccBits() == (SymbolCCI        << 12); }
  inline bool isMethodContext(void) { return _ccBits() == (MethodContextCCI << 12); }
  inline bool isBlockContext(void)  { return _ccBits() == (BlockContextCCI  << 12); }
  inline bool isPseudoContext(void) { return _ccBits() == (PseudoContextCCI << 12); }

  inline bool isPseudoMethodContext(void);
  inline bool isPseudoBlockContext(void);
      
  static const unsigned RootBit= 0x40000000;
  static const unsigned MarkBit= 0x80000000;

  inline void setRootBit(void)		{        _bh|=  RootBit; }
  inline void clearRootBit(void)	{        _bh&= ~RootBit; }
  inline bool isRoot(void) const	{ return _bh  & RootBit; }
  inline bool isForwarded(void) const	{ return _bh  & MarkBit; }
  inline bool isMarked(void) const	{ return _bh  & MarkBit; }

  // variable fields, relative to base header

  inline oop &_oops(const int index) const
    {
      return ((oop *)this)[index + sizeof(_bh)/sizeof(oop)];
    }

  inline word &_words(const int index) const
    {
      return ((word *)this)[index + sizeof(_bh)/sizeof(word)];
    }

  inline byte &_bytes(const int index) const
    {
      return ((byte *)this)[index + sizeof(_bh)/sizeof(byte)];
    }

  inline bool		isInteger(void)	const	 { return (((int)this) & 1) != 0; }
  inline static bool	isIntegerValue(int val)	 { return (val ^ (val << 1)) >= 0; }
  inline int		integerValue(void) const { return ((int)this) >> 1; }
  inline static oop	integer(int value)	 { return (oop)((value << 1) | 1); }

  inline static bool isPositiveIntegerValue(int val)
    {
      return (val >= 0) && isIntegerValue(val);
    }

  inline bool isCompact(void)
    {
      return (!isInteger()) && (_ccBits() != 0);
    }

  inline int _sizeBits(void) const
    {
      return (_type() == 0) ? (_sizeHeader() & 0xfffffffc) : (_baseHeader() & 0xfc);
    }

  inline int wordSize(void) const
    {
      return _sizeBits() >> 2;
    }

  // answer the number of indexable words in the object
  inline size_t wordLength(void) const
    {
      return (_sizeBits() - sizeof(Object)) >> 2;
    }

  static inline oop allocateSmall(Class *cls, size_t lbs, oop fil= nilObj)
    {
      return instantiateSmallClasssizeInBytesfill(cls, lbs, fil);
    }

  static inline oop allocate(Class *cls, size_t lbs)
    {
      return instantiateClassindexableSize(cls, lbs);
    }

  inline void *operator new(size_t ignored)
    {
      return (void *)fatal("subclass responsibility");
    }

  inline oop copy(void)
    {
      return ::clone(this);
    }

  // these must be defined after class Array
  inline Class *fetchClass(void) const;
  inline bool	isMemberOf(Class *cls) const;
  inline bool	isArray(void) const;
  inline bool	isBlockContext(void) const;
  inline bool	isCompiledMethod(void) const;
  inline bool	isMethodContext(void) const;
  inline bool	isSemaphore(void) const;

  // these must be defined after Behavior and its subclasses
  inline bool	isMetaclass(void) const;
  inline bool	isClass(void) const;

  inline static oop firstObject(void) { return firstAccessibleObject(); }
  inline oop	    nextObject(void)  { return accessibleObjectAfter(this); }

  inline void beRoot(void)
    {
      if (this < youngStart)
	beRootIfOld(this);
    }

  inline void checkStore(oop value)
    {
      if ((this < youngStart) && (!isRoot())
	  && (value >= youngStart) && (!value->isInteger()))
	{
	  noteAsRootheaderLoc(this, this);
	  //possibleRootStoreIntovalue(this, value);
	}
    }

  inline void mark(void)
    {
      // old objects that need marking are already in the root set
#     ifndef MARK_OLD
      if (this >= youngStart)
#     endif
      markAndTrace(this);
    }

  inline oop remap(void)
    {
      return isForwarded() ? ::remap(this) : this;
    }

  inline void pushRemappable(void)
    {
      pushRemappableOop(this);
    }

#define defineCast(Cls)	inline Cls *as##Cls(void) const { return (Cls *)this; }

  defineCast(Array);
  defineCast(Association);
  defineCast(BlockContext);
  defineCast(Class);
  defineCast(CompiledMethod);
  defineCast(Context);
  defineCast(Frame);
  defineCast(Link);
  defineCast(Message);
  defineCast(Metaclass);
  defineCast(MethodContext);
  defineCast(Process);
  defineCast(ProcessorScheduler);
  defineCast(PseudoContext);
  defineCast(Semaphore);
  defineCast(SmallInteger);
  defineCast(Symbol);

#undef defineCast

  inline bool isNil(void) const  { return this == nilObj; }
  inline bool notNil(void) const { return this != nilObj; }

  inline oop *lastPointer(void)
    {
      return (oop *)((char *)this + lastPointerOf(this));
    }

  bool okayFields(void);
  static bool allObjectsOkay(void);

  void print(void);
};



class Array : public Object
{
public:
  oop oops[1];	/* should be [0] but some compilers don't like it */

  inline oop at(int index) const { return oops[index]; }
  inline oop atPut(int index, oop value) { return oops[index]= value; }
};



// these must be defined after class Array

inline Class *Object::fetchClass(void) const
{
  if (isInteger()) return ClassSmallInteger;
  int ccIndex= _ccIndex() - 1;
  if (ccIndex < 0) return _classHeader();
  return CompactClasses->at(ccIndex)->asClass();
}

inline bool Object::isMemberOf(Class *cls) const
{
  return fetchClass() == cls;
}

#define defClassTest(CLASS) \
  inline bool Object::is##CLASS(void) const \
  { \
    return isMemberOf(Class##CLASS); \
  }

defClassTest(Array);
defClassTest(BlockContext);
defClassTest(CompiledMethod);
defClassTest(MethodContext);
defClassTest(Semaphore);

#undef defClassTest



class Association : public Object
{
public:
  oop key;
  oop value;
};



class MethodDictionary : public Object
{
public:
  // Set
  oop	 tally;
  Array	*array;
  // MethodDictionary
  oop	 oops[1];	// should be [0] but many compilers barf

  inline oop at(int index) const { return oops[index]; }
};



class Behavior : public Object
{
public:
  Class		   *superclass;
  MethodDictionary *methodDict;
  oop		    format;

  inline unsigned ccBits(void) const
    {
      return (unsigned int)format & ccMask;
    }

  inline unsigned instSpec(void) const
    {
      return ((unsigned)format >> 8) & 0x0f;
    }

  inline unsigned instSize(void) const
    {
      return ((((unsigned)format >> 11) & 0xc0)
	      + (((unsigned)format >>  2) & 0x3f)
	      - 1);
    }

  inline bool hasCompactInstances(void) const
    {
      return ccBits() != 0;
    }

  inline bool hasIndexableInstances(void) const
    {
      return instSpec() > 1;
    }
};


class ClassDescription : public Behavior
{
public:
  Array		   *instanceVariables;
  oop		    organization;
};



class Class : public ClassDescription
{
public:
  Array		   *subclasses;
  Symbol	   *name;
  oop		    classPool;
  oop		    sharedPools;
public:
  inline void print(void)
    {
      printNameOfClasscount(this, 5);
    }

  bool isSubclassOf(Behavior *super);
};



class Metaclass : public ClassDescription
{
public:
  Class		   *thisClass;
};



inline bool Object::isMetaclass(void) const
{
  // heuristic:
  //	- the receiver is not a SmallInteger
  //	- the receiver is the size of a Metaclass
  //	- the receiver's format is fixed fields only
  //	- the Metaclass.thisClass field is an instance of the receiver
  return (!isInteger())
    && (_sizeBits() == sizeof(Metaclass))
    && (_format() == 1)
    && (((Metaclass *)this)->thisClass->fetchClass() == this);
}



inline bool Object::isClass(void) const
{
  // heuristic:
  //	- the receiver is not a SmallInteger
  //	- the receiver's class is a Metaclass
  //	- the receiver's class's Behaviour.thisClass field is the receiver
  return (!isInteger())
    && (fetchClass()->isMetaclass())
    && (((Metaclass *)fetchClass())->thisClass == this);
}



class Character : public Object
{
public:
  oop value;

  inline int asciiValue(void) const { return value->integerValue(); }
  //  inline static oop value(int asciiValue) { return CharacterTable->at(asciiValue); }
};



class CompiledMethod : public Object
{
public:
  static const int MaxTemps= 64;
  static const int LargeFrameBit= 0x40000;

  inline byte &bytes(const int index) const
    {
      return ((byte *)this)[index + sizeof(Object)/sizeof(byte)];
    }

  unsigned int _mh;
  inline unsigned int methodHeader(void) { return _mh; }

  inline oop &literals(const int index) const
    {
      return ((oop *)this)[index + (sizeof(Object)+sizeof(_mh))/sizeof(oop)];
    }

  static inline int primIndexLo(unsigned int mh)  { return (mh >>  1) & 0x1ff; }
  static inline int literalCount(unsigned int mh) { return (mh >> 10) & 0x0ff; }
  static inline int tempCount(unsigned int mh)    { return (mh >> 19) & 0x03f; }
  static inline int argCount(unsigned int mh)     { return (mh >> 25) & 0x00f; }
  static inline int primIndexHi(unsigned int mh)  { return (mh >> 29) & 0x003; }

  static inline unsigned int primitiveIndex(unsigned int mh)
    {
      return primIndexLo(mh) + (primIndexHi(mh) << 9);
    }

  inline int  primIndexLo(void)		const { return primIndexLo(_mh); }
  inline int  literalCount(void)	const { return literalCount(_mh); }
  inline int  tempCount(void)		const { return tempCount(_mh); }
  inline int  argCount(void)		const { return argCount(_mh); }
  inline int  primIndexHi(void)		const { return primIndexHi(_mh); }

  inline unsigned int primitiveIndex(void) const
    {
      return primitiveIndex(_mh);
    }

  static inline size_t frameSize(unsigned int mh)
    {
      return (mh & LargeFrameBit) ? LargeFrame : SmallFrame;
    }

  inline size_t frameSize(void)
    {
      return frameSize(_mh);
    }

  static inline unsigned int initialPC(unsigned int mh)
    {
      return literalCount(mh) * sizeof(oop) + BaseHeaderSize + OneRel;
    }

  inline unsigned int initialPC(void) const { return initialPC(_mh); }

  inline unsigned int returnField(void) const
    {
      const int primIndex= primitiveIndex();
      assert(primIndex < 264);
      return primIndex - 264;
    }

  // answer the 1-based index of the last bytecode (see CompiledMethod>>endPC)
  int endPC(void);

  // accessors in C coordinates!
  inline byte byteAt(size_t index) const	{ return bytes(index); }
  inline oop  literalAt(size_t index) const	{ return literals(index); }

  // accessors in Smalltalk coordinates
  inline byte stByteAt(size_t index) const	{ return bytes(index - 1); }
  inline oop  stLiteralAt(size_t index) const	{ return literals(index - 1); }

  inline NativeMethod *nativeMethod(void);

  inline Symbol *selectorForReceiver(oop rcvr)
    {
      return findSelectorOfMethodforReceiver(this, rcvr);
    }

  inline Class *mclassForReceiver(oop rcvr)
    {
      return findClassOfMethodforReceiver(this, rcvr);
    }

  void printForReceiver(oop rcvr);
};



class ContextPart : public Object
{
public:
  Context *sender;	// InstructionStream
  oop	  pc;
  oop	  stackp;	// ContextPart

public:

  inline int stackIndex(void)
    {
      if (stackp->isNil()) return 0;
      assert(stackp->isInteger());
      return stackp->integerValue();
    }

  inline void stackIndex(int sp)
    {
      assert((sp >= 0) && (sp <= LargeFrame));	// FIX THIS
      stackp= Object::integer(sp);
    }
};



class MethodContext : public ContextPart
{
public:
  CompiledMethod *method;
  oop		  receiverMap;
  oop		  receiver;
  oop		  stack[LargeFrame];

  inline void *operator new(size_t lbs)
    {
      return (void *)allocateSmall(ClassMethodContext, lbs);
    }

  inline const oop *temporaryPointer(void) const { return stack; }

  inline Context *asContext(void) const { return (Context *)this; }

  inline Symbol *selector(void)
    {
      return method->selectorForReceiver(receiver);
    }

  inline void printMethod(void)
    {
      method->printForReceiver(receiver);
    }

  inline void print(void)
    {
      printf("MethodContext(");
      printMethod();
      printf(")");
    }
};



class BlockContext : public ContextPart
{
public:
  oop		  nargs;
  oop		  startpc;
  MethodContext	 *home;
  oop		  stack[LargeFrame];

  inline void *operator new(size_t lbs)
    {
      return (void *)allocateSmall(ClassBlockContext, lbs);
    }

  // ultra-fast allocator for BlockClosures
  inline static BlockContext *allocateEmpty(void)
    {
      //fatal("this is currently broken");
      register BlockContext *bx=(BlockContext *)allocateChunk(sizeof(BlockContext));
      // ASSMUE: header type short
      bx->_bh= blockContextHeader | ((Object::newHash() & 0xfff) << 17);
      return bx;
    }

  inline int argumentCount(void) const { return nargs->integerValue(); }

  inline const oop *temporaryPointer(void) const { return home->temporaryPointer(); }

  inline Context *asContext(void) const { return (Context *)this; }

  inline void printMethod(void)
    {
      printf("[] in ");
      home->method->printForReceiver(home->receiver);
    }

  inline void print(void)
    {
      printf("BlockContext(");
      printMethod();
      printf(")");
    }
};



// this class does not exist: it is an amalgam of method and block contexts

class Context : public ContextPart
{
public:
  oop		  nArgsOrMethod;	// {Method,Block}Context
  oop		  startPcOrReceiverMap;
  oop		  homeOrReceiver;
  oop		  stack[LargeFrame];

  inline bool isBlock(void)  const { return nArgsOrMethod->isInteger(); }
  inline bool isMethod(void) const { return !isBlock(); }

  inline BlockContext  *asBlockContext(void)  const
    {
      assert(isBlock());
      return (BlockContext *)this;
    }

  inline MethodContext *asMethodContext(void) const
    {
      assert(isMethod());
      return (MethodContext *)this;
    }

  inline PseudoContext *bePseudoContext(Frame *frame)
    {
      _ccBits(PseudoContextCCI << 12);
      this->stackp= Object::integer(0);
      stack[0]= (oop)frame;
      return asPseudoContext();
    }

  inline MethodContext *home(void) const
    {
      return isBlock() ? homeOrReceiver->asMethodContext() : asMethodContext();
    }

  inline CompiledMethod *method(void) const
    {
      return home()->method;
    }

  inline oop *stackPointer(void)
    {
      return stack + (stackp->integerValue() - OneRel);
    }

  inline int stackIndexOf(oop *sp) const
    {
      return (sp - stack) + OneRel;
    }

  inline void stackPointer(oop *sp)
    {
      stackp= Object::integer(stackIndexOf(sp));
    }

  inline const oop *temporaryPointer(void) const { return home()->temporaryPointer(); }

  inline void unlink(oop nilOop= nilObj)
    {
      sender= (pc= nilOop)->asContext();
    }

  inline oop push(oop obj)
    {
      int oldIndex= stackIndex();
      stackIndex(oldIndex + 1);
      return stack[oldIndex]= obj;
    }

  // NOTE: idx is in C coordinates

  inline oop at(int idx)
    {
      if ((idx < 0) || (idx >= stackIndex()))
	return 0;	// FAIL
      return stack[idx];
    }

  inline oop _atPut(int idx, oop obj)
    {
      if ((idx < 0) || (idx >= stackIndex()))
	return 0;	// FAIL
      return stack[idx]= obj;
    }

  inline oop atPut(int idx, oop obj)
    {
      if ((idx < 0) || (idx >= stackIndex()))
	return 0;	// FAIL
      checkStore(stack[idx]= obj);
      return obj;
    }

  // NOTE: idx is in **Smalltalk** coordinates

  inline bool storeStackp(int idx)
    {
      if ((idx < 1) || (idx > LargeFrame))	// FIX THIS
	return false;	// FAIL
      while (stackIndex() < idx)
	push(nilObj);
      stackIndex(idx);
      return true;
    }

};


class PseudoContext : public Context
{
public:
  inline void *operator new(size_t lbs)
    {
      return (void *)allocateSmall(ClassPseudoContext, lbs);
    }

  // ultra-fast allocator for frame volatilisation
  inline static PseudoContext *allocateEmpty(void)
    {
      //fatal("this is currently broken");
      register PseudoContext *px=(PseudoContext *)allocateChunk(sizeof(PseudoContext));
      // ASSMUE: header type short
      px->_bh= pseudoContextHeader | ((Object::newHash() & 0xfff) << 17);
      return px;
    }

  inline PseudoContext(Frame *f)
    {
      stack[0]= (oop)f;
    }

  inline BlockContext *beBlockContext(void)
    {
      _ccBits(BlockContextCCI << 12);
      return asBlockContext();
    }

  inline MethodContext *beMethodContext(void)
    {
      _ccBits(MethodContextCCI << 12);
      return asMethodContext();
    }

  inline Frame *frame(void)
    {
      return (Frame *)stack[0];
    }

  inline void print(void)
    {
      // can assume that receiver/method/home are correct!
      printf("PseudoContext(");
      if (isPseudoMethodContext())
	((MethodContext *)this)->printMethod();
      else
	((BlockContext *)this)->printMethod();
      putchar(')');
    }
};


inline bool Object::isPseudoMethodContext(void)
{
  return isPseudoContext() && !asPseudoContext()->nArgsOrMethod->isInteger();
}
      
inline bool Object::isPseudoBlockContext(void)
{
  return isPseudoContext() && asPseudoContext()->nArgsOrMethod->isInteger();
}



class String : public Object {};


class Symbol : public String
{
public:
  inline void print(void)
    {
      printStringOf(this);
    }
};



class Link : public Object
{
public:
  Link *nextLink;
};



class LinkedList : public Object
{
public:
  Link *firstLink;
  Link *lastLink;

  inline bool isEmpty(void) const
    {
      return firstLink == nilObj;
    }

  inline Link *addLast(Link *aLink)
    {
      assert(aLink != nilObj);
      if (isEmpty())
	firstLink= aLink;	// checkStore done below, before return
      else
	lastLink->checkStore(lastLink->nextLink= aLink);
      checkStore(lastLink= aLink);
      return aLink;
    }

  inline Link *removeFirst(void)
    {
      // assume: the list is not empty
      Link *first= firstLink;
      Link *last= lastLink;
      assert(first != nilObj);
      assert(last != nilObj);
      if (first == last)
	{
	  // checkStore(nil) is never really necessary...
	  checkStore(firstLink= lastLink= nilObj->asLink());
	}
      else
	{
	  Link *next= first->nextLink;
	  checkStore(firstLink= next);
	}
      // checkStore(nil) is never really necessary...
      first->checkStore(first->nextLink= nilObj->asLink());
      return first;
    }
};



class Semaphore : public LinkedList
{
public:
  oop excessSignals;
};


class SmallInteger : public Object
{
public:
  inline void print(void)
    {
      printf("%p(=%d)", this, integerValue());
    }
};


class Process : public Link
{
public:
  Context	*suspendedContext;
  oop		 priority;	// SmallInteger
  LinkedList	*myList;
  oop		 errorHandler;

  inline void addToList(LinkedList *list)
    {
      list->addLast(this);
      checkStore(myList= list);
    }

  void print(void);
};



class j_Point : public Object
{
public:
  oop		 x;
  oop		 y;
};



class ProcessorScheduler : public Object
{
public:
  Array		*quiescentProcessLists;
  Process	*activeProcess;
};



class Message : public Object
{
public:
  oop	 selector;
  Array	*args;
};


#endif // _j_Object_h
