// primAccess.cc -- object access ([{instVar,object}]at:[put:]) primitives
// 
// Author: Ian.Piumarta@INRIA.Fr
// 
// Last edited: 2000-11-30 12:06:17 by piumarta on emilia.rd.wdi.disney.com



#include "debug.h"
#include "archdep.h"
#include "generate.h"
#include "machine.h"
#include "primitive.h"

#include "Frame.h"


extern "C" { void primitiveLoadInstVar(void); }

// caller MUST set primitiveIndex!!

void j_primitiveLoadInstVar(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  assert((primitiveIndex >= 264) && (primitiveIndex <= 519));
  oop rcvr= stackPointer[0];

  if ((!rcvr->isInteger()) && (rcvr->isPseudoContext()))
    {
      oop field= rcvr->asPseudoContext()->frame()->instVarAt(primitiveIndex - 264);
      if (field != 0)
	{
	  stackPointer[0]= field;
	  return;
	}
      successFlag= false;
      return;
    }

  primitiveLoadInstVar();
}



extern "C" { void primitiveClone(void); }

void j_primitiveClone(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[0];
  if ((!rcvr->isInteger()) && (rcvr->isPseudoContext()))
    {
      Context *copy= rcvr->asPseudoContext()->frame()->clone();
      assert(copy->isMethodContext() || copy->isBlockContext());
      stackPointer[0]= copy;
      return;
    }
  primitiveClone();
}



extern "C" { void primitiveStoreStackp(void); }

void j_primitiveStoreStackp(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[-1];
  oop idxOop= stackPointer[0];
  if ((!rcvr->isInteger()) && (rcvr->isPseudoContext()))
    {
      if (idxOop->isInteger())
	{
	  int index= idxOop->integerValue();
	  successFlag= rcvr->asPseudoContext()->frame()->storeStackp(index);
	  if (successFlag)
	    stackPointer-= 1;
	  return;
	}
    }
  // non-Pseudo receiver: run regular primitive
  primitiveStoreStackp();
}



extern "C" { void primitiveSize(void); }

void j_primitiveSize(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[0];
  if ((!rcvr->isInteger()) && (rcvr->isPseudoContext()))
    {
      oop field= rcvr->asPseudoContext()->frame()->instVarAt(2);	// stackp
      if (field != 0)
	stackPointer[0]= field;
      else
	successFlag= false;
      return;
    }
  primitiveSize();
}



extern "C" { oop stObjectat(oop, int); }

//  lkupClass messageSelector
void j_primitiveAt(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop index= stackPointer[0];
  if (index->isInteger())
    {
      oop rcvr= stackPointer[-1];
      oop elt= 0;
      if (!rcvr->isInteger())
	{
	  if (rcvr->isPseudoContext())
	    {
	      elt= rcvr->asPseudoContext()->frame()->at(index->integerValue() - 1);
	      successFlag= (elt != 0);
	    }
	  else
	    elt= stObjectat(rcvr, index->integerValue());
	  if (successFlag)
	    {
	      stackPointer-= 1;
	      *stackPointer= elt;
#if 0
	      if (nMeth->primitiveIndex == 60)
		{
		  printf("explicit primitive 60 rcvr ");
		  rcvr->print();
		  printf("[%d], index ", rcvr->wordLength());
		  index->print();
		  printf(", elt ");
		  elt->print();
		  putchar('\n');
		}
#endif
	    }
	  return;
	}
    }
  successFlag= false;
}



extern "C" { void stObjectatput(oop, int, oop); }

//  lkupClass messageSelector
void j_primitiveAtPut(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop value= stackPointer[0];
  oop index= stackPointer[-1];
  if (index->isInteger())
    {
      oop rcvr= stackPointer[-2];
      if (!rcvr->isInteger())
	{
	  if (rcvr->isPseudoContext())
	    {
	      successFlag= ((rcvr->asPseudoContext()->frame()
			     ->atPut(index->integerValue() - 1, value)) != 0);
	    }
	  else
	    {
	      stObjectatput(rcvr, index->integerValue(), value);
	    }
	  if (successFlag)
	    {
	      stackPointer-= 2;
	      *stackPointer= value;
#if 0
	      if (nMeth->primitiveIndex == 61)
		{
		  printf("explicit primitive 61 rcvr ");
		  rcvr->print();
		  printf("[%d], index ", rcvr->wordLength());
		  index->print();
		  printf(", value ");
		  value->print();
		  putchar('\n');
		}
#endif
	    }
	  return;
	}
      printf("FAILING %p ", rcvr);
      rcvr->print();
      printf(" at: ");
      index->print();
      printf(" put: %p ", value);
      value->print();
      putchar('\n');
      sender->printBacktrace();
    }
  successFlag= false;
}



extern "C" { void primitiveInstVarAt(void); }

void j_primitiveInstVarAt(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[-1];
  oop idxOop= stackPointer[0];

  if (idxOop->isInteger())
    {
      if ((!rcvr->isInteger()) && (rcvr->isPseudoContext()))
	{
	  int idx= idxOop->integerValue();
	  oop field= rcvr->asPseudoContext()->frame()->instVarAt(idx - 1);
	  if (field != 0)
	    {
	      stackPointer-= 1;
	      stackPointer[0]= field;
	      return;
	    }
	  successFlag= false;
	}
      else
	{
	  primitiveInstVarAt();
	}
      return;
    }
  successFlag= false;
  return;
}



extern "C" { void primitiveInstVarAtPut(void); }

void j_primitiveInstVarAtPut(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[-2];
  oop idxOop= stackPointer[-1];
  oop val= stackPointer[0];

  if (idxOop->isInteger())
    {
      if ((!rcvr->isInteger()) && (rcvr->isPseudoContext()))
	{
	  int idx= idxOop->integerValue();
	  oop field= rcvr->asPseudoContext()->frame()->instVarAtPut(idx - 1, val);
	  if (field != 0)
	    {
	      stackPointer-= 2;
	      stackPointer[0]= field;
	      return;
	    }
	  successFlag= false;
	}
      else
	{
	  primitiveInstVarAtPut();
	}
      return;
    }
  successFlag= false;
  return;
}



//  argumentCount newMethod
void j_primitiveInstVarsPutFromStack(NativeMethod *nMeth, Frame *sender)
{
  fatal("primitiveInstVarsPutFromStack is obsolete");
}



extern "C" {
  int positive32BitValueOf(oop);
  oop characterForAscii(int);
};

//  lkupClass messageSelector
void j_primitiveStringAt(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[-1];
  if (!rcvr->isInteger())
    {
      int index= positive32BitValueOf(stackPointer[0]);
      if (successFlag)
	{
	  oop result= stObjectat(rcvr, index);
	  if (successFlag)
	    {
	      result= characterForAscii(result->integerValue());
	      stackPointer-= 1;
	      stackPointer[0]= result;
#if 0
	      if (nMeth->primitiveIndex == 63)
		{
		  printf("explicit primitive 63 rcvr ");
		  rcvr->print();
		  printf("[%d], index %d, elt ", rcvr->wordLength(), index);
		  result->print();
		  putchar('\n');
		}
#endif
	      return;
	    }
	}
    }
  successFlag= false;
}



extern "C"
{
  void stObjectatput(oop, int, oop);
  int  asciiOfCharacter(oop);
};

//  lkupClass messageSelector
void j_primitiveStringAtPut(NativeMethod *nMeth, Frame *sender)
{
  assert(activeFrame == sender);
#ifndef NEW_PRIMITIVES
  assert(stackPointer == sender->stackp);
#endif
  oop rcvr= stackPointer[-2];
  if (!rcvr->isInteger())
    {
      int index= positive32BitValueOf(stackPointer[-1]);
      if (successFlag)
	{
	  oop value= stackPointer[0];
	  stObjectatput(rcvr, index, (oop)asciiOfCharacter(value));
	  if (successFlag)
	    {
	      stackPointer-= 2;
	      stackPointer[0]= value;
	      return;
	    }
	}
    }
  successFlag= false;
}
