#ifndef __VM_HEADER__
#define __VM_HEADER__
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include "slate.h"
#include "file.h"
#include "directory.h"
#include "extprim.h"

struct Object;
struct RoleTable;
struct SlotTable;
struct ObjectHeader;
struct ByteArray;
struct ObjectHeap;
struct CompiledMethod;
struct LexicalContext;
struct OopArray;
struct Closure;
struct SlotEntry;
struct ObjectPayload;
struct Map;
struct Root;
struct PrimitiveMethod;
struct RoleEntry;
struct Interpreter;
struct ForwardedObject;
struct BreakEntry;
struct Symbol;
struct MethodDefinition;
struct ObjectHeader
{
  unsigned long int isMarked:1;
  unsigned long int idHash:23;
  unsigned long int objectSize:6;
  unsigned long int objectFormat:2;
};
typedef unsigned char Byte;
struct Object
{
  struct ObjectHeader header;
  struct Map * map;
};
typedef unsigned long int Word;
typedef unsigned long int Bool;
struct BreakEntry
{
  unsigned long int oldAddress;
  unsigned long int newAddress;
};
struct ForwardedObject
{
  struct ObjectHeader header;
  struct Object * target;
};
struct Closure
{
  struct ObjectHeader header;
  struct Map * map;
  struct CompiledMethod * method;
  struct LexicalContext * lexicalWindow[0];
};
struct Root
{
  struct ObjectHeader header;
  struct Map * map;
};
struct ObjectPayload
{
  unsigned long int payloadSize:30;
  unsigned long int payloadFormat:2;
};
struct ByteArray
{
  struct ObjectHeader header;
  struct Map * map;
  Byte elements[0];
};
typedef Word ObjectPointer;
struct PrimitiveMethod
{
  struct ObjectHeader header;
  struct Map * map;
  ObjectPointer index;
  ObjectPointer selector;
  ObjectPointer inputVariables;
};
struct RoleEntry
{
  ObjectPointer name;
  ObjectPointer rolePositions;
  struct MethodDefinition * methodDefinition;
  ObjectPointer nextRole;
};
struct SlotEntry
{
  ObjectPointer name;
  ObjectPointer offset;
};
struct RoleTable
{
  struct ObjectHeader header;
  struct Map * map;
  struct RoleEntry roles[0];
};
struct Map
{
  struct ObjectHeader header;
  struct Map * map;
  ObjectPointer flags;
  ObjectPointer representative;
  struct OopArray * delegates;
  ObjectPointer slotCount;
  struct SlotTable * slotTable;
  struct RoleTable * roleTable;
  unsigned long long int dispatchID;
  unsigned long int visitedPositions;
};
struct SlotTable
{
  struct ObjectHeader header;
  struct Map * map;
  struct SlotEntry slots[0];
};
struct OopArray
{
  struct ObjectHeader header;
  struct Map * map;
  ObjectPointer elements[0];
};
struct MethodDefinition
{
  struct ObjectHeader header;
  struct Map * map;
  ObjectPointer method;
  ObjectPointer slotAccessor;
  unsigned long long int dispatchID;
  unsigned long int dispatchPositions;
  unsigned long int foundPositions;
  unsigned long int dispatchRank;
};
struct LexicalContext
{
  struct ObjectHeader header;
  struct Map * map;
  ObjectPointer framePointer;
  ObjectPointer variables[0];
};
struct ObjectHeap
{
  ObjectPointer * rootStack[16];
  unsigned long int rootStackPosition;
  struct Object * markStack[4096];
  unsigned long int markStackPosition;
  Bool markStackOverflow;
  unsigned long int markColor;
  unsigned long int * pinnedCards;
  unsigned long int * stackBottom;
  struct BreakEntry breakTable[512];
  unsigned long int breakTableSize;
  unsigned long int totalAllocated;
  unsigned long int lastAllocated;
  unsigned long int nextLive;
  unsigned long int * memory;
  unsigned long int memoryEnd;
  unsigned long int memoryLimit;
  unsigned long int totalObjectCount;
  unsigned long int lowSpaceThreshold;
  unsigned long int shrinkThreshold;
  unsigned long int growthHeadroom;
  unsigned long int lastHash;
  ObjectPointer TrueObject;
  ObjectPointer FalseObject;
  ObjectPointer NilObject;
  ObjectPointer ClosureWindow;
  ObjectPointer CompiledMethodWindow;
  ObjectPointer PrimitiveMethodWindow;
  ObjectPointer specialObjectsOop;
};
struct Interpreter
{
  struct ObjectHeader header;
  struct Map * map;
  struct OopArray * stack;
  struct CompiledMethod * method;
  struct Closure * closure;
  struct LexicalContext * lexicalContext;
  ObjectPointer ensureHandlers;
  unsigned long int framePointer;
  unsigned long int codePointer;
  unsigned long int codeSize;
  unsigned long int stackPointer;
  unsigned long int stackSize;
};
struct CompiledMethod
{
  struct ObjectHeader header;
  struct Map * map;
  struct CompiledMethod * method;
  ObjectPointer selector;
  ObjectPointer inputVariables;
  ObjectPointer localVariables;
  ObjectPointer restVariable;
  struct OopArray * optionalKeywords;
  ObjectPointer heapAllocate;
  ObjectPointer environment;
  struct OopArray * literals;
  struct OopArray * selectors;
  struct ByteArray * code;
  ObjectPointer sourceTree;
  ObjectPointer debugMap;
};
struct Symbol
{
  struct ObjectHeader header;
  struct Map * map;
  ObjectPointer cacheMask;
  Byte elements[0];
};
extern const unsigned long int BCJumpTo;
extern const unsigned long int MapProto;
extern const unsigned long int BCPushInteger;
extern const unsigned long int MultiplyOverflowSymbol;
extern const unsigned long int BCReturnFrom;
extern const unsigned long int SlotTypeBits;
extern const unsigned long int BCBranchIfTrue;
extern const unsigned long int WrongInputsToSymbol;
extern const unsigned long int TrueObject;
extern const unsigned long int BCNewArray;
extern const unsigned long int ClosureWindow;
extern const unsigned long int BCResume;
extern const unsigned long int NilObject;
extern const unsigned long int NotABooleanSymbol;
extern const unsigned long int BCPushTrue;
extern const unsigned long int FormatOopArray;
extern const unsigned long int BCStoreFreeVariable;
extern const unsigned long int ClosureProto;
extern const unsigned long int ArrayProto;
extern const Bool True;
extern const unsigned long int FloatProto;
extern const unsigned long int SlotTypeDelegate;
extern const Bool False;
extern const unsigned long int BCLoadFreeVariable;
extern const unsigned long int BCPopStack;
extern const unsigned long int BCBranchIfFalse;
extern void * const Nil;
extern const unsigned long int BitShiftOverflowSymbol;
extern const unsigned long int BCPushEnvironment;
extern const unsigned long int BCIsIdenticalTo;
extern const unsigned long int PrimitiveMethodWindow;
extern const unsigned long int SubtractOverflowSymbol;
extern const unsigned long int BCPushNil;
extern const unsigned long int KeyNotFoundSymbol;
extern const unsigned long int SlotNotFoundSymbol;
extern const unsigned long int BCLoadLiteral;
extern const unsigned long int SlotOffsetMask;
extern const unsigned long int SlotTypeMask;
extern const unsigned long int BCBranchKeyed;
extern const unsigned long int AddOverflowSymbol;
extern const unsigned long int SlotTypeData;
extern const unsigned long int BCPushFalse;
extern const unsigned long int MayNotReturnToSymbol;
extern const unsigned long int NotFoundOnAfterSymbol;
extern const unsigned long int EnsureMarkerObject;
extern const unsigned long int NotFoundOnSymbol;
extern const unsigned long int ObjectSizeMask;
extern const unsigned long int TagMask;
extern const unsigned long int FormatPayload;
extern const unsigned long int InterpreterObject;
extern const unsigned long int ASCIIStringProto;
extern const unsigned long int MethodDefinitionProto;
extern const unsigned long int BCNewClosure;
extern const unsigned long int BCSendMessage;
extern const unsigned long int BCStoreVariable;
extern const unsigned long int LobbyObject;
extern const unsigned long int BCSendMessageWithOptionals;
extern const unsigned long int BCLoadSelector;
extern const unsigned long int BCExtended;
extern const unsigned long int SmallIntTag;
extern const unsigned long int ObjectTag;
extern const unsigned long int ApplyToSymbol;
extern const unsigned long int DivideByZeroSymbol;
extern const unsigned long int OptionalsSymbol;
extern const unsigned long int FormatByteArray;
extern const unsigned long int CompiledMethodWindow;
extern const unsigned long int FalseObject;
extern const unsigned long int FormatObject;
extern const unsigned long int NoRoleObject;
extern const unsigned long int SmallIntegerProto;
extern const unsigned long int LexicalContextProto;
extern const unsigned long int BCResendMessage;
extern const unsigned long int BCLoadVariable;
extern const unsigned long int ByteArrayProto;
extern struct ObjectHeap * CurrentMemory;
extern void (* primitives[]) (struct Interpreter *, ObjectPointer *, unsigned long int, struct OopArray *);
static Bool signedLongInt_fitsSmallInt(signed long int i);
static Bool ObjectPointer_isSmallInt(ObjectPointer oop);
static Bool ObjectPointer_isObject(ObjectPointer oop);
static struct Object * ObjectPointer_pointer(ObjectPointer oop);
static ObjectPointer PSObject_asObject(struct Object * p);
static ObjectPointer PSMap_asObject(struct Map * p);
static ObjectPointer unsignedLongInt_asObject(unsigned long int i);
static ObjectPointer signedLongInt_asObject(signed long int i);
static signed long int ObjectPointer_asSmallInt(ObjectPointer oop);
static void PSObjectHeap_rootStackPush_(struct ObjectHeap * oh, ObjectPointer * root);
static void PSObjectHeap_rootStackPop_(struct ObjectHeap * oh, unsigned long int n);
extern void PSObjectHeap_sweep(struct ObjectHeap * oh);
extern void PSObjectHeap_garbageCollect(struct ObjectHeap * oh);
extern void PSObjectHeap_compact_(struct ObjectHeap * oh, Bool mostlyCompact);
extern struct ForwardedObject * PSObjectHeap_forward_to_(struct ObjectHeap * oh, struct Object * old, struct Object * new);
extern void PSObjectHeap_findHoleSized_(struct ObjectHeap * oh, unsigned long int size);
extern struct Object * PSObjectHeap_allocateChunkSized_withPayload_(struct ObjectHeap * oh, unsigned long int words, unsigned long int payloadSize);
extern struct Object * PSObjectHeap_allocateChunkSized_(struct ObjectHeap * oh, unsigned long int words);
extern Bool PSObjectHeap_isFree_(struct ObjectHeap * oh, ObjectPointer oop);
extern ObjectPointer PSObjectHeap_firstObject(struct ObjectHeap * h);
extern ObjectPointer PSObjectHeap_objectAfter_(struct ObjectHeap * oh, ObjectPointer oop);
extern ObjectPointer PSObjectHeap_specialAt_(struct ObjectHeap * h, unsigned long int index);
extern unsigned long int PSObjectHeap_adjustAllOopsBy_(struct ObjectHeap * h, unsigned long int shiftAmountInBytes);
extern void PSObjectHeap_initializeWithShift_(struct ObjectHeap * h, unsigned long int shiftAmountInBytes);
extern unsigned long int PSObjectHeap_memoryStart(struct ObjectHeap * h);
extern Bool PSObjectHeap_includes_(struct ObjectHeap * h, unsigned long int address);
extern void PSObjectHeap_checkValid_(struct ObjectHeap * h, unsigned long int address);
static unsigned long int PSObjectHeap_memorySize(struct ObjectHeap * h);
extern void PSObjectHeap_growBy_(struct ObjectHeap * h, unsigned long int delta);
extern void PSObjectHeap_shrinkBy_(struct ObjectHeap * h, unsigned long int delta);
static void PWord_copyWords_into_(Word * src, unsigned long int n, Word * dst);
static void PByte_copyBytes_into_(Byte * src, unsigned long int n, Byte * dst);
static unsigned long int PSObject_payloadSize(struct Object * obj);
static unsigned long int PSObject_memoryUsage(struct Object * obj);
static unsigned long int PSObject_wordSize(struct Object * obj);
static unsigned long int PSObject_firstSlotOffset(struct Object * obj);
static unsigned long int PSObject_slotCount(struct Object * obj);
static unsigned long int PSObject_oopCount(struct Object * obj);
static unsigned long int PSObject_lastSlotOffset(struct Object * obj);
static unsigned long int PSObject_lastOopOffset(struct Object * obj);
static unsigned long int PSObject_arrayOffset(struct Object * obj);
static ObjectPointer * PSObject_arrayElements(struct Object * obj);
static unsigned long int PSObject_arraySize(struct Object * obj);
static unsigned long int PSObject_totalSize(struct Object * obj);
static unsigned long int PSObject_byteSize(struct Object * obj);
static ObjectPointer * PSObject_slotValues(struct Object * obj);
static ObjectPointer PSObject_slotValueAt_(struct Object * obj, unsigned long int index);
static ObjectPointer PSObject_slotValueAt_put_(struct Object * obj, unsigned long int index, unsigned long int oop);
static ObjectPointer PSObject_slotValueAtOffset_(struct Object * obj, unsigned long int offset);
static ObjectPointer PSObject_slotValueAtOffset_put_(struct Object * obj, unsigned long int offset, ObjectPointer value);
static signed long int PSByteArray_extractInto_sized_(struct ByteArray * fromArray, Byte * targetBuffer, unsigned long int bufferSize);
extern struct Object * PSObjectHeap_clone_(struct ObjectHeap * oh, struct Object * obj);
static struct Object * PSObjectHeap_cloneSpecial_(struct ObjectHeap * oh, unsigned long int index);
extern struct Object * PSObjectHeap_cloneOopArray_sized_(struct ObjectHeap * oh, struct Object * proto, unsigned long int oops);
extern struct Object * PSObjectHeap_cloneByteArray_sized_(struct ObjectHeap * oh, struct Object * proto, unsigned long int bytes);
static struct Object * PSObjectHeap_newOopArray_sized_(struct ObjectHeap * oh, unsigned long int index, unsigned long int oops);
static struct Object * PSObjectHeap_newByteArray_sized_(struct ObjectHeap * oh, unsigned long int index, unsigned long int bytes);
static struct Object * PSObjectHeap_newByteArray_from_sized_(struct ObjectHeap * oh, unsigned long int index, Byte * buffer, unsigned long int bytes);
extern struct SlotEntry * PSSlotTable_hashEntryForName_(struct SlotTable * slots, ObjectPointer name);
extern struct Object * PSObject_addSlotNamed_valued_(struct Object * obj, ObjectPointer name, ObjectPointer value);
extern struct Object * PSObject_addDelegateNamed_valued_(struct Object * obj, ObjectPointer name, ObjectPointer value);
extern struct Object * PSObject_addDelegateNamed_before_valued_(struct Object * obj, ObjectPointer name, ObjectPointer succ, ObjectPointer value);
extern struct Object * PSObject_addDelegateNamed_after_valued_(struct Object * obj, ObjectPointer name, ObjectPointer pred, ObjectPointer value);
extern struct Object * PSObject_removeSlotNamed_(struct Object * obj, ObjectPointer name);
extern Bool PSObject_addRoleNamed_at_dispatching_(struct Object * obj, ObjectPointer name, unsigned long int position, struct MethodDefinition * method);
extern Bool PSObject_removeRoleNamed_dispatching_(struct Object * obj, ObjectPointer name, struct MethodDefinition * method);
extern struct MethodDefinition * PSObject_hasRoleNamed_at_dispatching_(struct Object * obj, unsigned long int selector, unsigned long int positions, ObjectPointer method);
extern struct MethodDefinition * ObjectPointer_isMethod_on_arity_(ObjectPointer method, ObjectPointer selector, ObjectPointer * args, unsigned long int n);
extern struct MethodDefinition * ObjectPointer_asMethod_on_arity_(ObjectPointer method, ObjectPointer selector, ObjectPointer * args, unsigned long int n);
extern void ObjectPointer_flushMethodCache(ObjectPointer selector);
extern struct MethodDefinition * ObjectPointer_dispatchTo_arity_above_(ObjectPointer name, ObjectPointer * arguments, unsigned long int n, ObjectPointer resendMethod);
extern void PSInterpreter_growStack(struct Interpreter * i);
static void PSInterpreter_stackPush_(struct Interpreter * i, ObjectPointer oop);
static void PSInterpreter_stackAllocate_(struct Interpreter * i, unsigned long int n);
static ObjectPointer PSInterpreter_stackPop(struct Interpreter * i);
static signed long int PSInterpreter_decodeShort(struct Interpreter * i);
static unsigned long int PSInterpreter_decodeImmediate(struct Interpreter * i);
extern void PSInterpreter_signal_on_arity_withOptionals_(struct Interpreter * i, unsigned long int signalIndex, ObjectPointer * args, unsigned long int n, struct OopArray * opts);
extern void PSInterpreter_signal_with_(struct Interpreter * i, unsigned long int signalIndex, ObjectPointer x);
extern void PSInterpreter_signal_with_with_(struct Interpreter * i, unsigned long int signalIndex, ObjectPointer x, ObjectPointer y);
extern void PSInterpreter_signal_with_with_with_(struct Interpreter * i, unsigned long int signalIndex, ObjectPointer x, ObjectPointer y, ObjectPointer z);
static void PSInterpreter_sendMessage_withOptionals_(struct Interpreter * i, unsigned long int n, struct OopArray * opts);
static void PSInterpreter_sendMessageWithOptionals_(struct Interpreter * i, unsigned long int n);
extern void PSInterpreter_dispatchOptionals_(struct Interpreter * i, struct OopArray * opts);
static void PSInterpreter_send_to_arity_withOptionals_(struct Interpreter * i, ObjectPointer selector, ObjectPointer * args, unsigned long int n, struct OopArray * opts);
extern void PSInterpreter_send_to_through_arity_withOptionals_(struct Interpreter * i, ObjectPointer selector, ObjectPointer * args, ObjectPointer * dispatchers, unsigned long int n, struct OopArray * opts);
extern void PSInterpreter_apply_to_arity_withOptionals_(struct Interpreter * i, struct Closure * closure, ObjectPointer * args, unsigned long int n, struct OopArray * opts);
extern void PSInterpreter_resendMessage_(struct Interpreter * i, unsigned long int n);
static Bool PSInterpreter_dispatchOptionalKeyword_valued_(struct Interpreter * i, ObjectPointer key, ObjectPointer value);
static void PSInterpreter_loadVariable_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_storeVariable_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_loadFreeVariable_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_storeFreeVariable_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_loadLiteral_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_loadSelector_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_popStack_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_newArray_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_newClosure_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_pushInteger_(struct Interpreter * i, unsigned long int n);
static void PSInterpreter_jumpTo(struct Interpreter * i);
static void PSInterpreter_branchIfTrue(struct Interpreter * i);
static void PSInterpreter_branchIfFalse(struct Interpreter * i);
static void PSInterpreter_pushEnvironment(struct Interpreter * i);
static void PSInterpreter_pushNil(struct Interpreter * i);
static void PSInterpreter_pushTrue(struct Interpreter * i);
static void PSInterpreter_pushFalse(struct Interpreter * i);
static void PSInterpreter_isIdenticalTo(struct Interpreter * i);
extern Bool PSInterpreter_returnFrom_withResult_(struct Interpreter * i, unsigned long int n, Bool hasResult);
extern void PSInterpreter_branchKeyed_(struct Interpreter * i, unsigned long int n);
extern void PSInterpreter_interpret(struct Interpreter * i);
static INLINE Bool signedLongInt_fitsSmallInt(signed long int i)
{
  return (signed long int) (i ^ (i << 1)) >= 0;
}

static INLINE Bool ObjectPointer_isSmallInt(ObjectPointer oop)
{
  return (oop & TagMask) == SmallIntTag;
}

static INLINE Bool ObjectPointer_isObject(ObjectPointer oop)
{
  return (oop & TagMask) == ObjectTag;
}

static INLINE struct Object * ObjectPointer_pointer(ObjectPointer oop)
{
  return (struct Object *) (oop & ~TagMask);
}

static INLINE ObjectPointer PSObject_asObject(struct Object * p)
{
  return (ObjectPointer) ((unsigned long int) p | ObjectTag);
}

static INLINE ObjectPointer PSMap_asObject(struct Map * p)
{
  return (ObjectPointer) ((unsigned long int) p | ObjectTag);
}

static INLINE ObjectPointer unsignedLongInt_asObject(unsigned long int i)
{
  return (ObjectPointer) ((i << 1) | SmallIntTag);
}

static INLINE ObjectPointer signedLongInt_asObject(signed long int i)
{
  return (ObjectPointer) ((i << 1) | SmallIntTag);
}

static INLINE signed long int ObjectPointer_asSmallInt(ObjectPointer oop)
{
  ASSERT(ObjectPointer_isSmallInt(oop));
  
  return (signed long int) oop >> 1;
}

static INLINE void PSObjectHeap_rootStackPush_(struct ObjectHeap * oh, ObjectPointer * root)
{
  ASSERT(PSObjectHeap_includes_(oh, (unsigned long int) ObjectPointer_pointer(*root)));
  (oh -> rootStack)[oh -> rootStackPosition] = root;
  oh -> rootStackPosition = oh -> rootStackPosition + 1;
}

static INLINE void PSObjectHeap_rootStackPop_(struct ObjectHeap * oh, unsigned long int n)
{
  ASSERT((n > 0) && (n <= oh -> rootStackPosition));
  oh -> rootStackPosition = oh -> rootStackPosition - n;
}

static INLINE unsigned long int PSObjectHeap_memorySize(struct ObjectHeap * h)
{
  return (unsigned long int) h -> memoryEnd - (unsigned long int) h -> memory;
}

static INLINE void PWord_copyWords_into_(Word * src, unsigned long int n, Word * dst)
{
  if ((src < dst) && ((src + n) > dst))
  {
    dst+=n;
    src+=n;
    
    {
      do
      {
        --dst;
        --src;
        *dst = *src;
        --n;
      }
      while (n > 0);
    }
  }
  else
    while (n > 0)
    {
      *dst = *src;
      ++dst;
      ++src;
      --n;
    }
}

static INLINE void PByte_copyBytes_into_(Byte * src, unsigned long int n, Byte * dst)
{
  if ((src < dst) && ((src + n) > dst))
  {
    dst+=n;
    src+=n;
    
    {
      do
      {
        --dst;
        --src;
        *dst = *src;
        --n;
      }
      while (n > 0);
    }
  }
  else
    while (n > 0)
    {
      *dst = *src;
      ++dst;
      ++src;
      --n;
    }
}

static INLINE unsigned long int PSObject_payloadSize(struct Object * obj)
{
  return ((struct ObjectPayload *) obj - 1) -> payloadSize;
}

static INLINE unsigned long int PSObject_memoryUsage(struct Object * obj)
{
  return (obj -> header).objectFormat == FormatObject?(obj -> header).objectSize * 4:((((obj -> header).objectSize * 4) + PSObject_payloadSize(obj)) + 7) & -4;
}

static INLINE unsigned long int PSObject_wordSize(struct Object * obj)
{
  return (obj -> header).objectFormat == FormatObject?(obj -> header).objectSize:(obj -> header).objectSize + ((PSObject_payloadSize(obj) + 3) / 4);
}

static INLINE unsigned long int PSObject_firstSlotOffset(struct Object * obj)
{
  return 8;
}

static INLINE unsigned long int PSObject_slotCount(struct Object * obj)
{
  return (obj -> header).objectSize - 2;
}

static INLINE unsigned long int PSObject_oopCount(struct Object * obj)
{
  return (obj -> header).objectFormat == FormatOopArray?PSObject_wordSize(obj) - 2:PSObject_slotCount(obj);
}

static INLINE unsigned long int PSObject_lastSlotOffset(struct Object * obj)
{
  return ((obj -> header).objectSize * 4) - 4;
}

static INLINE unsigned long int PSObject_lastOopOffset(struct Object * obj)
{
  return (obj -> header).objectFormat == FormatOopArray?PSObject_lastSlotOffset(obj) + PSObject_payloadSize(obj):PSObject_lastSlotOffset(obj);
}

static INLINE unsigned long int PSObject_arrayOffset(struct Object * obj)
{
  return (obj -> header).objectSize * 4;
}

static INLINE ObjectPointer * PSObject_arrayElements(struct Object * obj)
{
  return (ObjectPointer *) ((Byte *) obj + PSObject_arrayOffset(obj));
}

static INLINE unsigned long int PSObject_arraySize(struct Object * obj)
{
  return (obj -> header).objectFormat == FormatObject?0:(PSObject_payloadSize(obj) + 3) / 4;
}

static INLINE unsigned long int PSObject_totalSize(struct Object * obj)
{
  return PSObject_wordSize(obj) * 4;
}

static INLINE unsigned long int PSObject_byteSize(struct Object * obj)
{
  return (obj -> header).objectFormat == FormatObject?PSObject_arrayOffset(obj):PSObject_arrayOffset(obj) + PSObject_payloadSize(obj);
}

static INLINE ObjectPointer * PSObject_slotValues(struct Object * obj)
{
  return (ObjectPointer *) (obj + 1);
}

static INLINE ObjectPointer PSObject_slotValueAt_(struct Object * obj, unsigned long int index)
{
  return (PSObject_slotValues(obj))[index];
}

static INLINE ObjectPointer PSObject_slotValueAt_put_(struct Object * obj, unsigned long int index, unsigned long int oop)
{
  return (PSObject_slotValues(obj))[index] = oop;
}

static INLINE ObjectPointer PSObject_slotValueAtOffset_(struct Object * obj, unsigned long int offset)
{
  return *((ObjectPointer *) ((Byte *) obj + offset));
}

static INLINE ObjectPointer PSObject_slotValueAtOffset_put_(struct Object * obj, unsigned long int offset, ObjectPointer value)
{
  return *((ObjectPointer *) ((Byte *) obj + offset)) = value;
}

static INLINE signed long int PSByteArray_extractInto_sized_(struct ByteArray * fromArray, Byte * targetBuffer, unsigned long int bufferSize)
{
  unsigned long int payloadSize;
  
  payloadSize = PSObject_payloadSize((struct Object *) fromArray);
  if (bufferSize < payloadSize)
    return -1;
  PByte_copyBytes_into_((Byte *) fromArray -> elements, bufferSize, targetBuffer);
  
  return payloadSize;
}

static INLINE struct Object * PSObjectHeap_cloneSpecial_(struct ObjectHeap * oh, unsigned long int index)
{
  return PSObjectHeap_clone_(oh, ObjectPointer_pointer(PSObjectHeap_specialAt_(oh, index)));
}

static INLINE struct Object * PSObjectHeap_newOopArray_sized_(struct ObjectHeap * oh, unsigned long int index, unsigned long int oops)
{
  return PSObjectHeap_cloneOopArray_sized_(oh, ObjectPointer_pointer(PSObjectHeap_specialAt_(oh, index)), oops);
}

static INLINE struct Object * PSObjectHeap_newByteArray_sized_(struct ObjectHeap * oh, unsigned long int index, unsigned long int bytes)
{
  return PSObjectHeap_cloneByteArray_sized_(oh, ObjectPointer_pointer(PSObjectHeap_specialAt_(oh, index)), bytes);
}

static INLINE struct Object * PSObjectHeap_newByteArray_from_sized_(struct ObjectHeap * oh, unsigned long int index, Byte * buffer, unsigned long int bytes)
{
  struct ByteArray * result;
  
  result = (struct ByteArray *) PSObjectHeap_newByteArray_sized_(oh, index, bytes);
  PByte_copyBytes_into_(buffer, bytes, result -> elements);
  
  return (struct Object *) result;
}

static INLINE void PSInterpreter_stackPush_(struct Interpreter * i, ObjectPointer oop)
{
  if (i -> stackPointer == i -> stackSize)
    PSInterpreter_growStack(i);
  ((i -> stack) -> elements)[i -> stackPointer] = oop;
  i -> stackPointer = i -> stackPointer + 1;
}

static INLINE void PSInterpreter_stackAllocate_(struct Interpreter * i, unsigned long int n)
{
  if ((i -> stackPointer + n) > i -> stackSize)
  {
    PSInterpreter_growStack(i);
    ASSERT((i -> stackPointer + n) <= i -> stackSize);
  }
  i -> stackPointer = i -> stackPointer + n;
}

static INLINE ObjectPointer PSInterpreter_stackPop(struct Interpreter * i)
{
  if (i -> stackPointer == 0)
    error("Attempted to pop empty interpreter stack.");
  i -> stackPointer = i -> stackPointer - 1;
  
  return ((i -> stack) -> elements)[i -> stackPointer];
}

static INLINE signed long int PSInterpreter_decodeShort(struct Interpreter * i)
{
  unsigned long int n;
  
  n = i -> codePointer;
  i -> codePointer = n + 2;
  
  return (signed short int) ((((i -> method) -> code) -> elements)[n] | ((((i -> method) -> code) -> elements)[n + 1] << 8));
}

static INLINE unsigned long int PSInterpreter_decodeImmediate(struct Interpreter * i)
{
  unsigned long int code;
  unsigned long int val;
  unsigned long int n;
  
  n = i -> codePointer;
  code = (((i -> method) -> code) -> elements)[n];
  val = code & 127;
  while (code >= 128)
  {
    ++n;
    code = (((i -> method) -> code) -> elements)[n];
    val = (val << 7) | (code & 127);
  }
  i -> codePointer = n + 1;
  
  return val;
}

static INLINE void PSInterpreter_sendMessage_withOptionals_(struct Interpreter * i, unsigned long int n, struct OopArray * opts)
{
  ObjectPointer selector;
  ObjectPointer * args;
  
  i -> stackPointer = i -> stackPointer - n;
  args = &((i -> stack) -> elements)[i -> stackPointer];
  selector = PSInterpreter_stackPop(i);
  PSInterpreter_send_to_through_arity_withOptionals_(i, selector, args, args, n, opts);
}

static INLINE void PSInterpreter_sendMessageWithOptionals_(struct Interpreter * i, unsigned long int n)
{
  struct OopArray * opts;
  
  opts = (struct OopArray *) PSInterpreter_stackPop(i);
  PSInterpreter_sendMessage_withOptionals_(i, n, opts);
}

static INLINE void PSInterpreter_send_to_arity_withOptionals_(struct Interpreter * i, ObjectPointer selector, ObjectPointer * args, unsigned long int n, struct OopArray * opts)
{
  PSInterpreter_send_to_through_arity_withOptionals_(i, selector, args, args, n, opts);
}

static INLINE Bool PSInterpreter_dispatchOptionalKeyword_valued_(struct Interpreter * i, ObjectPointer key, ObjectPointer value)
{
  struct OopArray * optKeys;
  
  optKeys = (i -> method) -> optionalKeywords;
  
  {
    unsigned long int _i_ = 0;
    unsigned long int _j_ = (PSObject_arraySize((struct Object *) optKeys) - 1) + 1;
    
    for (; _i_ < _j_; _i_+=1)
    {
      unsigned long int optKey = _i_;
      
      
      {
        if ((optKeys -> elements)[optKey] == key)
        {
          if ((i -> method) -> heapAllocate == CurrentMemory -> TrueObject)
            ((i -> lexicalContext) -> variables)[ObjectPointer_asSmallInt((i -> method) -> inputVariables) + optKey] = value;
          else
            ((i -> stack) -> elements)[(i -> framePointer + ObjectPointer_asSmallInt((i -> method) -> inputVariables)) + optKey] = value;
          
          return True;
        }
      }
    }
  }
  
  return False;
}

static INLINE void PSInterpreter_loadVariable_(struct Interpreter * i, unsigned long int n)
{
  PSInterpreter_stackPush_(i, (i -> method) -> heapAllocate == CurrentMemory -> TrueObject?((i -> lexicalContext) -> variables)[n]:((i -> stack) -> elements)[i -> framePointer + n]);
}

static INLINE void PSInterpreter_storeVariable_(struct Interpreter * i, unsigned long int n)
{
  if ((i -> method) -> heapAllocate == CurrentMemory -> TrueObject)
    ((i -> lexicalContext) -> variables)[n] = ((i -> stack) -> elements)[i -> stackPointer - 1];
  else
    ((i -> stack) -> elements)[i -> framePointer + n] = ((i -> stack) -> elements)[i -> stackPointer - 1];
}

static INLINE void PSInterpreter_loadFreeVariable_(struct Interpreter * i, unsigned long int n)
{
  PSInterpreter_stackPush_(i, ((((i -> closure) -> lexicalWindow)[n - 1]) -> variables)[PSInterpreter_decodeImmediate(i)]);
}

static INLINE void PSInterpreter_storeFreeVariable_(struct Interpreter * i, unsigned long int n)
{
  ((((i -> closure) -> lexicalWindow)[n - 1]) -> variables)[PSInterpreter_decodeImmediate(i)] = ((i -> stack) -> elements)[i -> stackPointer - 1];
}

static INLINE void PSInterpreter_loadLiteral_(struct Interpreter * i, unsigned long int n)
{
  PSInterpreter_stackPush_(i, (((i -> method) -> literals) -> elements)[n]);
}

static INLINE void PSInterpreter_loadSelector_(struct Interpreter * i, unsigned long int n)
{
  PSInterpreter_stackPush_(i, (((i -> method) -> selectors) -> elements)[n]);
}

static INLINE void PSInterpreter_popStack_(struct Interpreter * i, unsigned long int n)
{
  i -> stackPointer = i -> stackPointer - n;
}

static INLINE void PSInterpreter_newArray_(struct Interpreter * i, unsigned long int n)
{
  struct OopArray * arr;
  unsigned long int stackPointer;
  
  if (n == 0)
  {
    PSInterpreter_stackPush_(i, PSObjectHeap_specialAt_(CurrentMemory, ArrayProto));
    
    return;
  }
  arr = (struct OopArray *) PSObjectHeap_newOopArray_sized_(CurrentMemory, ArrayProto, n);
  stackPointer = i -> stackPointer - n;
  i -> stackPointer = stackPointer;
  PWord_copyWords_into_((Word *) (&((i -> stack) -> elements)[stackPointer]), n, (Word *) PSObject_arrayElements((struct Object *) arr));
  PSInterpreter_stackPush_(i, PSObject_asObject((struct Object *) arr));
}

static INLINE void PSInterpreter_newClosure_(struct Interpreter * i, unsigned long int n)
{
  struct Closure * newClosure;
  
  if ((struct CompiledMethod *) i -> closure == i -> method)
    newClosure = (struct Closure *) PSObjectHeap_newOopArray_sized_(CurrentMemory, ClosureProto, (unsigned long int) 1);
  else
  {
    unsigned long int inheritedSize;
    
    inheritedSize = PSObject_arraySize((struct Object *) i -> closure);
    newClosure = (struct Closure *) PSObjectHeap_newOopArray_sized_(CurrentMemory, ClosureProto, (unsigned long int) (inheritedSize + 1));
    PWord_copyWords_into_((Word *) (i -> closure) -> lexicalWindow, inheritedSize, (Word *) newClosure -> lexicalWindow + 1);
  }
  (newClosure -> lexicalWindow)[0] = i -> lexicalContext;
  newClosure -> method = (struct CompiledMethod *) (((i -> method) -> literals) -> elements)[n];
  PSInterpreter_stackPush_(i, PSObject_asObject((struct Object *) newClosure));
}

static INLINE void PSInterpreter_pushInteger_(struct Interpreter * i, unsigned long int n)
{
  PSInterpreter_stackPush_(i, unsignedLongInt_asObject(n));
}

static INLINE void PSInterpreter_jumpTo(struct Interpreter * i)
{
  signed long int offset;
  
  offset = PSInterpreter_decodeShort(i);
  i -> codePointer = i -> codePointer + offset;
}

static INLINE void PSInterpreter_branchIfTrue(struct Interpreter * i)
{
  signed long int offset;
  ObjectPointer condition;
  
  offset = PSInterpreter_decodeShort(i);
  condition = PSInterpreter_stackPop(i);
  if (condition == CurrentMemory -> TrueObject)
    i -> codePointer = i -> codePointer + offset;
  else
    if (!(condition == CurrentMemory -> FalseObject))
    {
      i -> codePointer = i -> codePointer - 3;
      PSInterpreter_signal_with_(i, NotABooleanSymbol, condition);
    }
}

static INLINE void PSInterpreter_branchIfFalse(struct Interpreter * i)
{
  signed long int offset;
  ObjectPointer condition;
  
  offset = PSInterpreter_decodeShort(i);
  condition = PSInterpreter_stackPop(i);
  if (condition == CurrentMemory -> FalseObject)
    i -> codePointer = i -> codePointer + offset;
  else
    if (!(condition == CurrentMemory -> TrueObject))
    {
      i -> codePointer = i -> codePointer - 3;
      PSInterpreter_signal_with_(i, NotABooleanSymbol, condition);
    }
}

static INLINE void PSInterpreter_pushEnvironment(struct Interpreter * i)
{
  PSInterpreter_stackPush_(i, (i -> method) -> environment);
}

static INLINE void PSInterpreter_pushNil(struct Interpreter * i)
{
  PSInterpreter_stackPush_(i, CurrentMemory -> NilObject);
}

static INLINE void PSInterpreter_pushTrue(struct Interpreter * i)
{
  PSInterpreter_stackPush_(i, CurrentMemory -> TrueObject);
}

static INLINE void PSInterpreter_pushFalse(struct Interpreter * i)
{
  PSInterpreter_stackPush_(i, CurrentMemory -> FalseObject);
}

static INLINE void PSInterpreter_isIdenticalTo(struct Interpreter * i)
{
  if (PSInterpreter_stackPop(i) == PSInterpreter_stackPop(i))
    PSInterpreter_stackPush_(i, CurrentMemory -> TrueObject);
  else
    PSInterpreter_stackPush_(i, CurrentMemory -> FalseObject);
}

#endif // __VM_HEADER__
