/******************************** -*- C -*- ****************************
 *
 *	Dictionary Support Module Inlines.
 *
 *	$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 __GSTDICT_INLINES__
#define  __GSTDICT_INLINES__

#include "memzero.h"
#include "register.h"

#if STDC_HEADERS
#include <string.h>
#include <stdlib.h>
#endif /* STDC_HEADERS */

#include <stdio.h>

static inline mst_Boolean isAKindOf(), indexOOPPut(), instVarAtPut(),
			  isCLong(), indexStringOOPPut();

static inline int 	  instanceSize(), oopNumFields();

static inline OOP *	  nilFill();

static inline mst_Object  newInstanceWith(), newInstance(),
	      		  instantiateWith(), instantiate();

static inline OOP	  instantiateOOPWith(), 
			  dictionaryAdd(), dictionaryAssociationAt(),
			  dictionaryAt(), associationNew(), indexOOP(),
			  indexStringOOP(), floatNew(),
			  fromCLong(), fromCULong();

static inline long	  toCLong();

#include "sym.h"
#include "interp.h"
#include "oop.h"
#include "lex.h"


#define isSymbol(oop) \
  ( !isNil(oop) && (oopClass(oop) ==  symbolClass) )

#define stringOOPChars(stringOOP) \
  ((Byte *)((String)oopToObj(stringOOP))->chars)

#define messageSelector(messageOOP) \
  (((Message)oopToObj(messageOOP))->selector)

#define messageArgs(messageOOP) \
  (((Message)oopToObj(messageOOP))->args)

#define cObjectNew(cObjPtr) \
  (cObjectNewTyped(cObjPtr, cObjectTypeCType))

#define cObjectValueObj(cObj) \
  ( ((voidPtr *) cObj) [((mst_Object)cObj)->objSize - 1])

#define setCObjectValueObj(cObj, value) \
  ( ((voidPtr *) cObj) [((mst_Object)cObj)->objSize - 1] = (voidPtr)(value))

#define cObjectValue(cObjOOP) \
  cObjectValueObj(oopToObj(cObjOOP))

#define setCObjectValue(cObjOOP, value) \
  setCObjectValueObj(oopToObj(cObjOOP), value)

#define superClass(classOOP) \
  (((Class)oopToObj(classOOP))->superClass)

#define oopFixedFields(oop) \
  (oopInstanceSpec(oop) >> ISP_NUMFIXEDFIELDS)

#define numIndexableFields(oop) \
	(isInt(oop) ? 0 : oopNumFields(oop) - oopFixedFields(oop))

#define arrayNew(numElts) \
	(allocOOP(instantiateWith(arrayClass, (numElts))))

#define arrayAt(arrayOOP, index) \
	( ((Array)oopToObj(arrayOOP))->elements[(index)-1])

#define arrayAtPut(arrayOOP, index, value) \
	((Array)oopToObj(arrayOOP))->elements[index-1] = value

#define dictionarySize(dictionaryOOP) \
  (toInt(((Dictionary)oopToObj(dictionaryOOP))->tally))

#define dictionaryAtPut(dictionaryOOP, keyOOP, valueOOP) \
  (dictionaryAdd(dictionaryOOP, associationNew(keyOOP, valueOOP)))

#define isAMetaclass(oop) \
  (isOOP(oop) && oopClass(oop) == metaclassClass)

#define isAClass(oop) \
  (isOOP(oop) && oopClass(oopClass(oop)) == metaclassClass)

#define metaclassInstance(metaclassOOP) \
  (((Metaclass)oopToObj(metaclassOOP))->instanceClass)

#define associationValue(associationOOP) \
  (((Association)oopToObj(associationOOP))->value)

#define setAssociationValue(associationOOP, valueOOP) \
  (((Association)oopToObj(associationOOP))->value = valueOOP)

#define setClassEnvironment(classOOP, namespaceOOP) \
  (((Class)oopToObj(classOOP))->environment = namespaceOOP)

#define classInstanceSpec(classOOP) \
  (((Class)oopToObj(classOOP))->instanceSpec)

#define getInstanceSpec(obj) \
  classInstanceSpec((obj)->objClass)

#define oopInstanceSpec(oop) \
  classInstanceSpec(oopClass(oop))

#define checkBoundsOf(oop, index) \
  (isOOP(oop) && (index >= 1 && index <= oopNumFields(oop)))

#define classIsPointers(classOOP) \
  (classInstanceSpec(classOOP) & ISP_ISPOINTERS)

#define isPointers(oop) \
  (oopInstanceSpec(oop) & ISP_ISPOINTERS)

#define classIsIndexable(classOOP) \
  (classInstanceSpec(classOOP) & ISP_ISINDEXABLE)

#define oopSizeBytes(oop) \
  ((oopToObj(oop)->objSize << LONG_SHIFT) - sizeof(ObjectHeader))

/* return the number of availble longwords in object, excluding the header */
#define numOOPs(obj) \
  ((long) ((classInstanceSpec(obj->objClass) & ISP_ISPOINTERS) \
    ? (1 + (obj)->objSize - sizeof(struct ObjectStruct) / sizeof(OOP)) \
    : (classInstanceSpec(obj->objClass) >> ISP_NUMFIXEDFIELDS) \
  ))



#if (DOUBLE_ALIGNMENT <= SIZEOF_CHAR_P)
#define floatOOPValue(floatOOP) \
	(((FloatObject)oopToObj(floatOOP))->value)

#else
static inline double
floatOOPValue(floatOOP)
OOP	floatOOP;
{
  register mst_Object obj;
  union {
    unsigned long l[2];
    double d;
  } hack;

  /* we may not be aligned properly...fetch things out the hard way */
  obj = oopToObj(floatOOP);
  hack.l[0] = (unsigned long)obj->data[0];
  hack.l[1] = (unsigned long)obj->data[1];
  return (hack.d);
}
#endif

static inline OOP
floatNew (f)
     double	f;
{
  FloatObject	floatObject;

  floatObject = (FloatObject)newInstanceWith(floatClass, sizeof(double));

#if (DOUBLE_ALIGNMENT <= SIZEOF_CHAR_P)
  floatObject->value = f;
#else
  {
    /* we may not be aligned properly...store things the hard way */
    mst_Object obj;
    union {
      unsigned long l[2];
      double d;
    } hack;

    obj = (mst_Object)floatObject; /* alias -- avoid left side casts*/
    hack.d = f;
    obj->data[0] = (voidPtr)hack.l[0];
    obj->data[1] = (voidPtr)hack.l[1];
  }
#endif

  return (allocOOP(floatObject));
}

#endif


/*
 *	mst_Boolean isAKindOf(memberOOP, classOOP)
 *
 * Description
 *
 *	Checks to see if "memberOOP" is a subclass of "classOOP", returning
 *	true if it is.
 *
 * Inputs
 *
 *	memberOOP: 
 *		A class OOP that's to be checked for (sub)class membership.
 *	classOOP: 
 *		A class OOP that's the conjectured (super)class.
 *
 * Outputs
 *
 *	True if "memberOOP" is a (sub)class of "classOOP".
 */
static inline mst_Boolean
isAKindOf (memberOOP, classOOP)
     OOP	memberOOP, classOOP;
{
  for ( ; !isNil(memberOOP); memberOOP = superClass(memberOOP)) {
    if (memberOOP == classOOP) {
      return (true);
    }
  }
  
  return (false);
}

static inline int
instanceSize (classOOP)
     OOP	classOOP;
{
  register int		numBytes;
  register long        	instanceSpec;

  instanceSpec = classInstanceSpec(classOOP);
  numBytes = instanceSpec >> ISP_NUMFIXEDFIELDS;

  /* Fixed instance vars are always pointers */
  numBytes <<= LONG_SHIFT;

  return (numBytes + sizeof(ObjectHeader));
}



static inline OOP *
nilFill (oopPtr, oopCount)
     REGISTER(1, OOP	*oopPtr);
     REGISTER(2, long 	oopCount);
{
  REGISTER(3, OOP	nilObj);
  if (!oopCount) {
    return (oopPtr);
  }
  nilObj = nilOOP;
__switch:
  switch(oopCount) {
    default:
      do {
	oopPtr[0] = nilObj; oopPtr[1] = nilObj;
	oopPtr[2] = nilObj; oopPtr[3] = nilObj;
	oopPtr[4] = nilObj; oopPtr[5] = nilObj;
	oopPtr[6] = nilObj; oopPtr[7] = nilObj;
	oopPtr += 8; oopCount -= 8;
      } while(oopCount > 8);
      goto __switch;

    case 8: oopPtr[7] = nilObj;
    case 7: oopPtr[6] = nilObj;
    case 6: oopPtr[5] = nilObj;
    case 5: oopPtr[4] = nilObj;
    case 4: oopPtr[3] = nilObj;
    case 3: oopPtr[2] = nilObj;
    case 2: oopPtr[1] = nilObj;
    case 1: oopPtr[0] = nilObj;
    case 0: break;
  }
  return (oopPtr + oopCount);
}

static inline mst_Object
newInstanceWith (classOOP, numIndexFields)
     OOP	classOOP;
     long	numIndexFields;
{
  mst_Object	instance;
  register int	numBytes;
  register long	instanceSpec;

  numBytes = instanceSize(classOOP);
  instanceSpec = classInstanceSpec(classOOP);
  if (instanceSpec & (ISP_ISPOINTERS | ISP_ISWORDS)) {
    numIndexFields = size2Bytes(numIndexFields);
  }
  numBytes += numIndexFields;
  numBytes = size2Bytes(ROUNDED_WORDS(numBytes));
  instance = (mst_Object)allocObj(numBytes);
  instance->objSize = numBytes >> LONG_SHIFT;
  instance->objClass = classOOP;
  return (instance);
}


/*
 *	mst_Object newInstance(classOOP)
 *
 * Description
 *
 *	Creates a new instance of class "classOOP".  The space is allocated,
 *	the class and size fields of the class are filled in, and the instance
 *	is returned.  Its fields are NOT INITIALIZED.  "classOOP" must
 *	represent a class with no indexable fields.
 *
 * Inputs
 *
 *	classOOP: 
 *		OOP for the class that the new instance is to be an instance
 *		of.
 *
 * Outputs
 *
 *	The new instance, with objSize and objClass filled in.
 */
static inline mst_Object
newInstance (classOOP)
     register OOP	classOOP;
{
  register mst_Object	instance;
  int			numBytes;

  numBytes = instanceSize(classOOP);
  instance = (mst_Object)allocObj(numBytes);
  instance->objSize = bytes2Size(numBytes);
  instance->objClass = classOOP;
  return (instance);
}


/*
 *	mst_Object instantiateWith(classOOP, numIndexFields)
 *
 * Description
 *
 *	Returns a new, initialized instance with indexable fields.  If the
 *	instance contains pointers, they are initialized to nilOOP, else they
 *	are set to real zero.
 *
 * Inputs
 *
 *	classOOP: 
 *		Class to make an instance of.  An OOP.
 *	numIndexFields: 
 *		The number if indexed instance variables this instance is to
 *		have, possibly zero.  A long.
 *
 * Outputs
 *
 *	New instance with initialized, indexed instance variables.
 */
static inline mst_Object
instantiateWith (classOOP, numIndexFields)
     OOP	classOOP;
     long	numIndexFields;
{
  register mst_Object	instance;
  register long		instanceSpec;
  long			numBytes;
  
  instance = newInstanceWith(classOOP, numIndexFields);
  instanceSpec = classInstanceSpec(classOOP);
  nilFill(instance->data, instanceSpec >> ISP_NUMFIXEDFIELDS);
  if (instanceSpec & ISP_ISPOINTERS) {
    nilFill(&instance->data[instanceSpec >> ISP_NUMFIXEDFIELDS], numIndexFields);
  } else {
    numBytes = numIndexFields;
    if (instanceSpec & ISP_ISWORDS) {
      numBytes = size2Bytes(numBytes);
    }
    /* not strictly necessary -- a convenience */
    memzero(&instance->data[instanceSpec >> ISP_NUMFIXEDFIELDS], numBytes);
  }
  return (instance);
}


/*
 *	OOP instantiateOOPWith(classOOP, numIndexFields)
 *
 * Description
 *
 *	Returns an OOP for a newly allocated instance of "classOOP", with
 *	"numIndexFields" fields.  The OOP is adjusted to reflect any
 *	variance in size (such as a string that's shorter than a word boundary.
 *
 * Inputs
 *
 *	classOOP: 
 *		An OOP for the class to create the instance of.
 *	numIndexFields: 
 *		The number of index fields to create in the instance.  Must be
 *		>= 0.
 *
 * Outputs
 *
 *	A new OOP that holds the newly allocated instance, with possible
 *	correction for size.
 */
static inline OOP
instantiateOOPWith (classOOP, numIndexFields)
     OOP	classOOP;
     long	numIndexFields;
{
  register mst_Object	object;
  register OOP		oop;
  long			instanceSpec;

  object = instantiateWith(classOOP, numIndexFields);
  oop = allocOOP(object);
  instanceSpec = classInstanceSpec(classOOP);
  if (!(instanceSpec & (ISP_ISWORDS | ISP_ISPOINTERS))) {
    initEmptyBytes(oop, numIndexFields);
  }

  return (oop);
}

/*
 *	mst_Object instantiate(classOOP)
 *
 * Description
 *
 *	Create and return a new instance of class "classOOP".  "classOOP" must
 *	be a class with no indexable fields.  The named instance variables of
 *	the new instance are initialized to nilObj, since fixed-field-only 
 *	objects can only have pointers.
 *
 * Inputs
 *
 *	classOOP: 
 *		An OOP for the class to create the instance of.
 *
 * Outputs
 *
 *	The new instance, with its fields initialized.
 */
static inline mst_Object
instantiate (classOOP)
     OOP	classOOP;
{
  register mst_Object	instance;
  register long		instanceSpec;

  instance = newInstance(classOOP);
  instanceSpec = classInstanceSpec(classOOP);
#ifndef OPTIMIZE
  if (!(instanceSpec & ISP_ISPOINTERS)) {
    errorf("Class with non-pointer instance spec passed to instantiate");
  }
#endif

  nilFill(instance->data, instanceSpec >> ISP_NUMFIXEDFIELDS);
  return (instance);
}


static int
findKey (dictionaryOOP, keyOOP)
     OOP	dictionaryOOP, keyOOP;
{
  register long		index;
  register Dictionary	dictionary; 
  long			initindex, numFields;
  OOP			associationOOP;
  Association		association;

  dictionary = (Dictionary)oopToObj(dictionaryOOP);
  numFields = numOOPs(dictionary) - 1;
  index = oopIndex(keyOOP);
  index %= numFields;
  initindex = index;

  do {
    if (isNil(dictionary->assoc[index])) {
      return (index);
    }

    associationOOP = dictionary->assoc[index];
    association = (Association)oopToObj(associationOOP);

    if (association->key == keyOOP) {
      return (index);
    }
    /* linear reprobe -- it is simple and guaranteed */
    if (++index == numFields) {
      index = 0;
    }
  } while (index != initindex);

  return(-1);
}


static int
findKeyOrNil (dictionaryOOP, keyOOP)
     OOP	dictionaryOOP, keyOOP;
{
  long			count, numFields;
  register long		index;
  register Dictionary	dictionary; 
  OOP			associationOOP;
  Association		association;

  dictionary = (Dictionary)oopToObj(dictionaryOOP);
  numFields = numOOPs(dictionary) - 1;
  index = oopIndex(keyOOP);
  index %= numFields;
  count = numFields;

  for ( ; count; count--) {
    if (isNil(dictionary->assoc[index])) {
      return (index);
    }

    associationOOP = dictionary->assoc[index];
    association = (Association)oopToObj(associationOOP);

    if (association->key == keyOOP) {
      return (index);
    }

    /* linear reprobe -- it is simple and guaranteed */
    if (++index == numFields) {
      index = 0;
    }
  }
  errorf("Error - searching dictionary for nil, but it is full!\n");
  exit(1);
}

static inline int
identityDictionaryFindKeyOrNil (identityDictionaryOOP, keyOOP)
     OOP	identityDictionaryOOP, keyOOP;
{
  register IdentityDictionary	identityDictionary;
  register long			index;
  long				count;
  long				numFields;
  
  identityDictionary = (IdentityDictionary)oopToObj(identityDictionaryOOP);
  for ( ; ; ) {
    numFields = numOOPs(identityDictionary) - 2;
    index = oopIndex(keyOOP);
    index %= numFields;
    count = numFields;

    for ( ; count; count--) {
      if (isNil(identityDictionary->keys[index])) {
	return (index);
      }

      if (identityDictionary->keys[index] == keyOOP) {
	return (index);
      }

      /* linear reprobe -- it is simple and guaranteed */
      if (++index == numFields) {
        index = 0;
      }
    }

    /*
     * If we get to here, the dictionary is full, but we haven't found
     * the element that we're looking for.  Since we either return the
     * index of the element being sought, or the index of a nil element,
     * and the dictionary was full so that there was no nil element, we
     * grow the dictionary and scan it again.  We're guaranteed to exit
     * this loop via a return after at most two iterations.
     */
    identityDictionary = growIdentityDictionary(identityDictionaryOOP);
  }
}



static OOP
dictionaryAdd (dictionaryOOP, associationOOP)
     OOP	dictionaryOOP,  associationOOP;
{
  register long		index;
  Association		association;
  register Dictionary	dictionary;
  OOP			value;
  IncPtr		incPtr;		/* I'm not sure clients are protecting
					   association OOP */

  incPtr = incSavePointer();
  incAddOOP(associationOOP);

  association = (Association)oopToObj(associationOOP);
  dictionary = (Dictionary)oopToObj(dictionaryOOP);
  if (toInt(dictionary->tally) >= numOOPs(dictionary)-1) {
    dictionary = growDictionary(dictionaryOOP);
  }

  index = findKeyOrNil(dictionaryOOP, association->key);
  if (isNil(dictionary->assoc[index])) {
    dictionary->tally = incrInt(dictionary->tally);
    dictionary->assoc[index] = associationOOP;
  } else {
    value = associationValue(associationOOP);
    associationOOP = dictionary->assoc[index];
    setAssociationValue(associationOOP, value);
  }

  incRestorePointer(incPtr);
  return (associationOOP);
}


static inline OOP
dictionaryAssociationAt (dictionaryOOP, keyOOP)
     OOP	dictionaryOOP, keyOOP;
{
  register long		index;
  register Dictionary	dictionary; 

  if (isNil(dictionaryOOP)) {
    return (nilOOP);
  }

  index = findKey(dictionaryOOP, keyOOP);
  if (index == -1) {
    return (nilOOP);
  }
  dictionary = (Dictionary)oopToObj(dictionaryOOP);

  return (dictionary->assoc[index]);
}

static inline OOP
dictionaryAt (dictionaryOOP, keyOOP)
     OOP	dictionaryOOP, keyOOP;
{
  OOP		assocOOP;

  assocOOP = dictionaryAssociationAt(dictionaryOOP, keyOOP);

  if (isNil(assocOOP)) {
    return (nilOOP);
  } else {
    return (associationValue(assocOOP));
  }
}

static inline OOP
associationNew (key, value)
     OOP	key, value;
{
  Association	association;

  association = (Association)newInstance(associationClass);
  association->key = key;
  association->value = value;

  return (allocOOP(association));
}


static inline int
oopNumFields (oop)
     OOP	oop;
{
  register mst_Object	object;
  register long		instanceSpec;

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);

  if (instanceSpec & (ISP_ISPOINTERS | ISP_ISWORDS)) {
    return ((size2Bytes(object->objSize) - sizeof(ObjectHeader)) >> LONG_SHIFT);
  } else {			/* must be bytes */
    return (
      size2Bytes(object->objSize - (instanceSpec >> ISP_NUMFIXEDFIELDS)) -
      sizeof(ObjectHeader) -
      (oop->flags & EMPTY_BYTES) +
      (instanceSpec >> ISP_NUMFIXEDFIELDS));
  }
}

static inline OOP
indexOOP (oop, index)
     OOP	oop;
     int	index;
{
  register long		instanceSpec;
  register mst_Object	object;
  register long		maxIndex;

  if (index < 1) {
    return (nil);
  }

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);

  if (instanceSpec & ISP_ISPOINTERS) {
    maxIndex = ((size2Bytes(object->objSize) - sizeof(ObjectHeader)) >> LONG_SHIFT);
    index += instanceSpec >> ISP_NUMFIXEDFIELDS;
    if (index > maxIndex) {
      return (nil);
    }
    return (object->data[index-1]);
  } else if (instanceSpec & ISP_ISWORDS) {
    maxIndex = ((size2Bytes(object->objSize) - sizeof(ObjectHeader)) >> LONG_SHIFT);
    index += instanceSpec >> ISP_NUMFIXEDFIELDS;
    if (index > maxIndex) {
      return (nil);
    }
    return (fromCULong( ((long *)object->data)[index-1] ));
  } else {
    maxIndex =
      size2Bytes(object->objSize - (instanceSpec >> ISP_NUMFIXEDFIELDS)) -
      sizeof(ObjectHeader) -
      (oop->flags & EMPTY_BYTES);

    if (index > maxIndex) {
      return (nil);
    }
    index += (instanceSpec >> ISP_NUMFIXEDFIELDS) * sizeof(OOP);
    return (fromInt( ((Byte *)object->data)[index-1] ));
  }
}

static inline mst_Boolean
indexOOPPut (oop, index, value)
     OOP	oop, value;
     int	index;
{
  register long		instanceSpec;
  register mst_Object	object;
  register long		maxIndex;

  if (index < 1) {
    return (false);
  }

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);

  if (instanceSpec & ISP_ISPOINTERS) {
    maxIndex = ((size2Bytes(object->objSize) - sizeof(ObjectHeader)) >> LONG_SHIFT);
    index += instanceSpec >> ISP_NUMFIXEDFIELDS;
    if (index > maxIndex) {
      return (false);
    }
    object->data[index-1] = value;
  } else if (instanceSpec & ISP_ISWORDS) {
    maxIndex = ((size2Bytes(object->objSize) - sizeof(ObjectHeader)) >> LONG_SHIFT);
    index += instanceSpec >> ISP_NUMFIXEDFIELDS;
    if (index > maxIndex) {
      return (false);
    }
    ((long *)object->data)[index-1] = toCLong(value);
  } else {
    maxIndex =
      size2Bytes(object->objSize - (instanceSpec >> ISP_NUMFIXEDFIELDS)) -
      sizeof(ObjectHeader) -
      (oop->flags & EMPTY_BYTES);
    if (index > maxIndex) {
      return (false);
    }
    index += (instanceSpec >> ISP_NUMFIXEDFIELDS) * sizeof(OOP);
    if (toInt(value) >= 256) {
      return (false);
    }
    ((Byte *)object->data)[index-1] = (Byte)toInt(value);
  }

  return (true);
}

static inline OOP
indexStringOOP (oop, index)
     OOP	oop;
     int	index;
{
  register long		instanceSpec;
  register mst_Object	object;
  register long		maxIndex;

  if (index < 1) {
    return (nil);
  }

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);
  maxIndex =
    size2Bytes(object->objSize - (instanceSpec >> ISP_NUMFIXEDFIELDS)) -
    sizeof(ObjectHeader) -
    (oop->flags & EMPTY_BYTES);

  if (index > maxIndex) {
    return (nil);
  }
  index += (instanceSpec >> ISP_NUMFIXEDFIELDS) * sizeof(OOP);
  return (charOOPAt( ((Byte *)object->data)[index-1] ));
}

static inline mst_Boolean
indexStringOOPPut (oop, index, value)
     OOP	oop, value;
     int	index;
{
  register long		instanceSpec;
  register mst_Object	object;
  register long		maxIndex;

  if (index < 1) {
    return (false);
  }

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);
  maxIndex =
    size2Bytes(object->objSize - (instanceSpec >> ISP_NUMFIXEDFIELDS)) -
    sizeof(ObjectHeader) -
    (oop->flags & EMPTY_BYTES);

  if (index > maxIndex) {
    return (false);
  }
  index += (instanceSpec >> ISP_NUMFIXEDFIELDS) * sizeof(OOP);
  ((Byte *)object->data)[index-1] = charOOPValue(value);

  return (true);
}

static inline OOP
instVarAt (oop, index)
     OOP	oop;
     int	index;
{
  register long		instanceSpec;
  register mst_Object	object;

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);
  if (index <= (instanceSpec >> ISP_NUMFIXEDFIELDS)) {
    /* Fixed instance vars are always pointers */
    instanceSpec |= ISP_ISPOINTERS;
  }

  if (instanceSpec & ISP_ISPOINTERS) {
    return (object->data[index-1]);
  } else if (instanceSpec & ISP_ISWORDS) {
    return (fromCULong( ((long *)object->data)[index-1] ));
  } else {
    /* Adjust for the extra space took by fixed fields */
    index -= instanceSpec >> ISP_NUMFIXEDFIELDS;
    index += (instanceSpec >> ISP_NUMFIXEDFIELDS) * sizeof(OOP);
    return (fromInt( ((Byte *)object->data)[index-1] ));
  }
}

static inline mst_Boolean
instVarAtPut (oop, index, value)
     OOP	oop, value;
     int	index;
{
  register long		instanceSpec;
  register mst_Object	object;

  object = oopToObj(oop);
  instanceSpec = getInstanceSpec(object);
  if (index <= (instanceSpec >> ISP_NUMFIXEDFIELDS)) {
    /* Fixed instance vars are always pointers */
    instanceSpec |= ISP_ISPOINTERS;
  }

  if (instanceSpec & ISP_ISPOINTERS) {
    object->data[index-1] = value;
  } else if (instanceSpec & ISP_ISWORDS) {
    ((long *)object->data)[index-1] = toCLong(value);
  } else {
    if (toInt(value) >= 256) {
      return (false);
    }
    /* Adjust for the extra space took by fixed fields */
    index -= instanceSpec >> ISP_NUMFIXEDFIELDS;
    index += (instanceSpec >> ISP_NUMFIXEDFIELDS) * sizeof(OOP);
    ((Byte *)object->data)[index-1] = (Byte)toInt(value);
  }

  return (true);
}



#if SIZEOF_INT < SIZEOF_LONG
#define fromCInt(integer)	fromInt((signed long) (signed int) integer)
#define fromCUInt(integer)	fromInt((signed long) (unsigned int) integer)
#else
#define fromCInt(integer)	fromCLong((signed long) integer)
#define fromCUInt(integer)	fromCULong((unsigned long) integer)
#endif

#define toCInt(integer)		((int) toCLong(integer))
#define isCInt(integer)		isCLong(integer)

mst_Boolean
isCLong(oop)
     OOP	oop;
{
  ByteArray ba;

  if (isInt(oop)) {
    return (true);
  }
  ba = (ByteArray) oopToObj(oop);
  if (ba->objClass == largeNegativeIntegerClass) {
    return (numIndexableFields(oop) == SIZEOF_LONG);
  } else if (ba->objClass == largePositiveIntegerClass) {
    switch (numIndexableFields(oop)) {
      case SIZEOF_LONG: return (true);
      case SIZEOF_LONG+1: return (ba->bytes[SIZEOF_LONG] == 0);
    }
  }

  return (false);
}

long
toCLong(oop)
     OOP	oop;
{
  ByteArray ba;

  if (isInt(oop)) {
    return (toInt(oop));
  }

  ba = (ByteArray) oopToObj(oop);
  return ((long) (
#if SIZEOF_LONG == 8
     (((unsigned long) ba->bytes[7]) << 56) + (((unsigned long) ba->bytes[6]) << 48) +
     (((unsigned long) ba->bytes[5]) << 40) + (((unsigned long) ba->bytes[4]) << 32) +
#endif
     (((unsigned long) ba->bytes[3]) << 24) + (((unsigned long) ba->bytes[2]) << 16) +
     (((unsigned long) ba->bytes[1]) <<  8) +  ((unsigned long) ba->bytes[0])
  ));
}

OOP
fromCLong(lng)
     long	lng;
{
  ByteArray		ba;
  OOP			oop;
  const unsigned long	ul = (unsigned long) lng;

  if (lng >= MIN_ST_INT && lng <= MAX_ST_INT) {
    return(fromInt(lng));
  }

  if (lng < 0) {
    oop = instantiateOOPWith(largeNegativeIntegerClass, SIZEOF_LONG);
  } else {
    oop = instantiateOOPWith(largePositiveIntegerClass, SIZEOF_LONG);
  }

  ba = (ByteArray) oopToObj(oop);
  ba->bytes[0] = (Byte) ul;
  ba->bytes[1] = (Byte) (ul >>  8);
  ba->bytes[2] = (Byte) (ul >> 16);
  ba->bytes[3] = (Byte) (ul >> 24);
#if SIZEOF_LONG == 8
  ba->bytes[4] = (Byte) (ul >> 32);
  ba->bytes[5] = (Byte) (ul >> 40);
  ba->bytes[6] = (Byte) (ul >> 48);
  ba->bytes[7] = (Byte) (ul >> 56);
#endif

  return (oop);
}

OOP
fromCULong(ul)
     unsigned long	ul;
{
  ByteArray		ba;
  OOP			oop;

  if (ul <= MAX_ST_INT) {
    return(fromInt(ul));
  }

  if ( ((signed long) ul) < 0) {
    oop = instantiateOOPWith(largePositiveIntegerClass, SIZEOF_LONG + 1);
    ba = (ByteArray) oopToObj(oop);
    ba->bytes[SIZEOF_LONG] = 0;
  } else {
    oop = instantiateOOPWith(largePositiveIntegerClass, SIZEOF_LONG);
    ba = (ByteArray) oopToObj(oop);
  }

  ba = (ByteArray) oopToObj(oop);
  ba->bytes[0] = (Byte) ul;
  ba->bytes[1] = (Byte) (ul >>  8);
  ba->bytes[2] = (Byte) (ul >> 16);
  ba->bytes[3] = (Byte) (ul >> 24);
#if SIZEOF_LONG == 8
  ba->bytes[4] = (Byte) (ul >> 32);
  ba->bytes[5] = (Byte) (ul >> 40);
  ba->bytes[6] = (Byte) (ul >> 48);
  ba->bytes[7] = (Byte) (ul >> 56);
#endif

  return (oop);
}
