/******************************** -*- C -*- ****************************
 *
 *	GNU Smalltalk generic inclusions.
 *
 *	$Revision: 1.7.5$
 *	$Date: 2000/05/28 16:56:52$
 *	$Author: pb$
 *
 ***********************************************************************/

/***********************************************************************
 *
 * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
 * Written by Steve Byrne.
 *
 * This file is part of GNU Smalltalk.
 *
 * GNU Smalltalk is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later 
 * version.
 * 
 * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
 *
 ***********************************************************************/

#ifndef __GST__

#ifndef __GST__PUBLIC__
#define __GST__PUBLIC__

#include "gstconf.h"

/* AIX is so broken that requires this to be the first thing in the file.  */
#if defined(_AIX)
#pragma alloca
#else
# if !defined(alloca)    /* predefined by HP cc +Olibcalls */
#  ifdef __GNUC__
#   define alloca __builtin_alloca
#  else
#   if HAVE_ALLOCA_H
#    include <alloca.h>
#   else
#    if defined(__hpux)
      void *alloca ();
#    else
#     if !defined(__OS2__) && !defined(WIN32)
       char *alloca ();
#     else
#      include <malloc.h> /* OS/2 defines alloca in here */
#     endif
#    endif
#   endif
#  endif
# endif
#endif

#if defined(_WIN32) || defined(Win32) || defined(__WIN32)
#ifndef WIN32
  /* Some compilers use different win32 definitions.
   * Define WIN32 so we have only to check for one symbol. */
#define WIN32 1
#endif
#endif

#if defined (__DJGPP__)
/* We can handle longer names (sometimes) */
#undef NAMES83
/* While we have these, we don't want them used */
#undef HAVE_PIPE
#undef HAVE_FORK
#endif

#if SIZEOF_CHAR_P != SIZEOF_LONG
#error longs and pointer have different sizes
#endif

#if SIZEOF_INT < 4
#error 16-bits platform are not supported.
#endif

#if SIZEOF_LONG != 4
#warning 64-bit targets are not fully supported
#warning please write to bonzini@gnu.org
#endif

/*#if !defined(__STDC__) && (defined(AIX) | defined(mips) | defined(ibm032) || (defined(sun) && !defined(SUNOS40))) */
#if !defined(__STDC__) && defined(OLDCC)
/* for older compilers that don't understand void * */
typedef char *voidPtr;
#else 
typedef void *voidPtr;
#endif

typedef enum booleanType {
  false,
  true
} mst_Boolean;


#define F_FREE		((unsigned long) 0x80000000)
#define F_POOLED	((unsigned long) 0x40000000)
#define F_WEAK		((unsigned long) 0x20000000)
#define F_REACHABLE	((unsigned long) 0x10000000)
#define F_FINALIZE	((unsigned long) 0x08000000)
#define F_BYTE	 	((unsigned long) 0x04000000)
#define F_READONLY 	((unsigned long) 0x02000000)
#define F_CONTEXT 	((unsigned long) 0x01000000)
#define EMPTY_BYTES	((unsigned long) (SIZEOF_LONG - 1))


typedef struct OOPStruct	*OOP;
typedef struct ObjectStruct	*mst_Object;

struct OOPStruct {
  mst_Object	object;
  unsigned long flags;
};

/* some useful constants */
extern	OOP		nilOOP, trueOOP, falseOOP;

/* The header of all objects in the system.
 * Note how structural inheritance is achieved without adding extra levels of 
 * nested structures. */
#define OBJ_HEADER \
  long		objSize; /* for now, this is object size in 32bit words*/ \
  OOP		objClass


/* just for symbolic use in sizeof's */
typedef struct ObjectHeaderStruct {
  OBJ_HEADER;
} ObjectHeader;

#define OBJ_HEADER_SIZE_WORDS	(sizeof(ObjectHeader) / sizeof(long))

/* A bare-knuckles accessor for real objects */
struct ObjectStruct {
  OBJ_HEADER;
  OOP		data[1];	/* variable length, may not be objects, but
				   will always be at least this big. */
};

#define oopToObj(oop) \
  ((oop)->object)

#define oopIsReadOnly(oop) \
  (((oop)->flags & F_READONLY) != 0)

#define makeOOPReadOnly(oop, ro) \
  if (ro) { (oop)->flags |= F_READONLY; } \
  else { (oop)->flags &= ~F_READONLY; }

#define markOOPToFinalize(oop, fin) \
  if (fin) { (oop)->flags |= F_FINALIZE; } \
  else { (oop)->flags &= ~F_FINALIZE; }

#define makeOOPWeak(oop) \
  (oop)->flags |= F_WEAK;

#define oopClass(oop) \
  (oopToObj(oop)->objClass)

#define isClass(oop, class) \
  (isInt(oop) ? class == smallIntegerClass : class == oopClass(oop))


/* general functions */

#define isInt(oop) \
  ((long)(oop) & 1)

#define areInts(oop1, oop2) \
  ((long)(oop1) & (long)(oop2) & 1)

#define isOOP(oop) \
  (! isInt(oop) )

#define isNil(oop) \
  ((OOP)(oop) == nilOOP)


/************ incubator support **************/  
  
extern OOP			*incOOPBasePtr, *incOOPPtr, *incOOPEndPtr;

#define incAddOOP(oop) \
  { if (incOOPPtr >= incOOPEndPtr) \
      incGrowRegistry(); \
    *incOOPPtr++ = (oop); \
  }

#define incSavePointer() \
  (incOOPPtr - incOOPBasePtr)

#define incRestorePointer(ptr) \
  incOOPPtr = (ptr) + incOOPBasePtr;

typedef unsigned long	IncPtr;

#endif /* __GST__PUBLIC__ */



/**************************** BEGINNING OF PRIVATE STUFF **********/
/* This is skipped when gstpub.h includes this file               */

#ifndef __GST_FROM_GSTPUB_H__

/* OPTIMIZE disables many checks, including consistency checks at GC time and
 * bounds checking on instance variable accesses (not on #at: and #at:put:
 * which would violate language semantics).  It can a) greatly speed up
 * code by simplifying the interpreter's code b) make debugging painful
 * because you know of a bug only when it's too late.  It is undefined
 * because the Makefiles take care of defining it for optimized builds.
 * Bounds-checking and other errors will call the debug() function, where
 * you can set a breakpoint and which acts a generic entry point for
 * assertion failures. */
/* #define OPTIMIZE */

#define nil			0L
#define ENUM_INT(x)		((int)(x))

typedef unsigned char Byte;

#ifdef NO_INLINES
  #define inline
#else
#  if defined (__GNUC__)
#    undef inline
#    define inline __inline__	/* let's not lose when --ansi is specified */
#  endif
#endif

/* If they have no const, they're likely to have no volatile, either. */
#ifdef const
#define volatile
#endif

#ifndef HAVE_STRDUP
extern char *strdup();
/* else it is in string.h */
#endif

/* Implementation note: on 64 bit architectures, bit-encoded 32 bit words
 * are made to live in the low order 32 bits -- the high 32 bits are ignored,
 * and are padded if necessary to achieve the useful stuff in the lower 32.
 * This simplifies the current implementation, as most bit fields, both in C
 * and in Smalltalk do not have to be modified when on a 64 bit architecture.
 * Smalltalk Integers will be able to represent up to 62 bits + 1 sign bit.
 */

#if SIZEOF_LONG == 8
#define LONG_SHIFT 3		/* bits to shift for a long or pointer */
#else
#define LONG_SHIFT 2		/* bits to shift for a long or pointer */
#endif


#ifdef _MSC_VER
/* Under Visual C++, the forward declaration of semIntHandler() & friends is
 * interpreted as semIntHandler(void), not semIntHandler(I'm K&R C compatible)
 * so we use this trick (hack) to shut the retentive compiler up 
 */
#define SIG_ARG_TYPE	int

/* Visual C++ does not define STDC */
#define __STDC__ 1

#else
#define SIG_ARG_TYPE	/* empty */
#endif


#ifndef HAVE_MEMCPY
#define memcpy(s1, s2, n) bcopy((s2), (s1), (n))
#define memcmp(s1, s2, n) bcmp ((s1), (s2), (n))
#endif /* HAVE_MEMCPY */

/*
   3                   2                   1 
 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    # fixed fields             |      unused         |p|w|F|0|1|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

pb 1/11/1999: since the new non-bitfield approach makes code easier
and faster if there is nothing to the left of the "fixed fields"
field, I'm moving it to bits 13-30 (it used to stay at bits 5-30),
allocating space for more flags in case they're needed.
If you change ISP_NUMFIXEDFIELDS you should modify Behavior too.
Remember to shift by ISP_NUMFIXEDFIELDS-1 there, since Smalltalk does
not see ISP_INTMARK!!
*/

#define ISP_NUMFIXEDFIELDS      13	/* This is a shift count */
#define ISP_INDEXEDVARS		28
#define ISP_ISPOINTERS          16
#define ISP_ISWORDS             8
#define ISP_ISINDEXABLE         4
#define ISP_INTMARK             1


/* the current execution stack pointer */
extern	OOP		*outerSP;
#define sp		outerSP

#ifdef PROFBLOCK
struct profStruct {
  int numMinorGCs;		/* #times minorGC called */
  int numMajorGCs;		/* #times majorGC called */
  int numThisContexts;
  int numMethodAllocs;
  int numMethodFrees;
  int numMessageSends;
  int numValues;		/* number of times a block was evaluated */
  int numCacheCollisions;	/* collisions in the method cache */
  int stackSizeSum;		/* sum at GC time of the saved stack pointers*/
  int stackDepth;		/* num records (blocks+methods) on stack now */
  int maxStackDepth;		/* the max it reaches ever */
};

extern struct profStruct ps;
#endif


#define uncheckedPushOOP(oop) \
  *++sp = (oop)

#define uncheckedSetTop(oop) \
  *sp = (oop)

#define pushOOP(oop) \
  uncheckedPushOOP(oop)

#define popOOP() \
  (*sp--)

#define popNOOPs(n) \
  sp -= (n)

#define unPop(n) \
  sp += (n)

#define stackTop() \
  (*sp)

#define setStackTop(oop) \
  uncheckedSetTop(oop)

#define setStackTopInt(i) \
  uncheckedSetTop(fromInt(i))

#define setStackTopBoolean(exp) \
  uncheckedSetTop((exp) ? trueOOP : falseOOP)

#define stackAt(i) \
  (sp[-(i)])

#define pushInt(i) \
  uncheckedPushOOP(fromInt(i))

#define popInt() \
  toInt(popOOP())

#define pushBoolean(exp) \
  uncheckedPushOOP((exp) ? trueOOP : falseOOP)

#define isOOPMarked(oop) \
  ((oop)->flags & F_REACHABLE)

#define isPooled(oop) \
  ((oop)->flags & F_POOLED)

#define isOOPFree(oop) \
  ((oop)->flags & F_FREE)


/* This macro should only be used right after an allocOOP, when the
 * emptyBytes field is guaranteed to be zero
 */
#define initEmptyBytes(oop, value) \
    ((oop)->flags |= (SIZEOF_LONG - (value)) & EMPTY_BYTES)

/* Use this one to assign a particular value */
#define setEmptyBytes(oop, value) \
    { (oop)->flags &= ~EMPTY_BYTES; initEmptyBytes(oop, value); }


/* Generally useful conversion functions */
#define size2Bytes(size) \
  ((size) << LONG_SHIFT)

#define bytes2Size(bytes) \
  ((bytes) >> LONG_SHIFT)


/* integer conversions */

#define toInt(oop) \
  ((long)(oop) >> 1) 

#define fromInt(i) \
  (OOP)( ((long)(i) << 1) | 1)

/* Be sure to update these if you change the representation of SmallInteger 
 * objects.  Also update mulWithCheck() in interp.c
 * INT_OVERFLOW(i) checks if adding or subtracting two integers resulted
 * in an overflow.  OVERFLOWING_INT is any integer such that
 * INT_OVERFLOW(OVERFLOWING_INT) = true.
 */

#define ST_INT_SIZE        ((SIZEOF_LONG * 8) - 2)
#define MAX_ST_INT         (( ((long) 1) << ST_INT_SIZE) - 1)
#define MIN_ST_INT         ( ~MAX_ST_INT)
#define INT_OVERFLOW(i)    ( (i) > MAX_ST_INT || (i) < MIN_ST_INT )
#define OVERFLOWING_INT    (MAX_ST_INT + 1)

#define incrInt(i)         ((OOP) (((long)i) + 2))		/* 1 << 1 */
#define decrInt(i)         ((OOP) (((long)i) - 2))		/* 1 << 1 */

#ifndef max
#define	max(x, y) 		( ((x) > (y)) ? (x) : (y) )
#endif
#ifndef min
#define	min(x, y) 		( ((x) > (y)) ? (y) : (x) )
#endif

/* Everything has been included -- define the __GST__ guard */
#define __GST__
#endif /* __GST_FROM_GSTPUB_H__ not defined */

#endif /* __GST__ */
