// genCache.cc -- method prologue inline cache generation	-*- C++ -*-
// 
// Author: Ian.Piumarta@INRIA.Fr
//
// Last edited: 2000-12-07 15:27:40 by piumarta on emilia.rd.wdi.disney.com

#include "NativeMethod.h"

#include "archdep.h"

#include ARCHDEP(emit.h)


// reg[0] is receiver
// reg[1] is cache argument
// reg[2] is deferred send site (iff reg[1] & DeferredBit)


void genSICacheCheck(NativeMethod *nMeth, insn *enter, insn *relink)
{
  //gen_siCacheCheck(nMeth, enter, relink);
  const size_t nArgs= nMeth->argumentCount;
  //emit_move_S_r(nArgs, reg[0]);
  emit_bftst_i_i_r(0, 1, reg[0]);
  if (enter != 0) {
    emit_bne(enter);
    emit_jmp(relink);
  } else {
    emit_beq(relink);
  }
  // reg[0] is still the receiver
}


void genCCCacheCheck(NativeMethod *nMeth, insn *enter, insn *relink)
{

  //gen_ccCacheCheck(nMeth, enter, relink);
  const size_t nArgs= nMeth->argumentCount;
  //emit_move_S_r(nArgs, reg[0]);
  emit_bftst_i_i_r(0, 1, reg[0]);
  emit_bne(relink);				// SmallInteger => miss
  emit_get_i_r_r(0, reg[0], tmp[0]);		// base header
  emit_xor_r_r(reg[1], tmp[0]);			// compare
  emit_bftst_i_i_r(12, 5, tmp[0]);		// cc index bits
  if (enter != 0) {
    emit_beq(enter);
    emit_jmp(relink);
  } else {
    emit_bne(relink);
  }
  // reg[0] is still the receiver
}


void genNCCacheCheck(NativeMethod *nMeth, insn *enter, insn *relink)
{
  //gen_ncCacheCheck(nMeth, enter, relink);
  const size_t nArgs= nMeth->argumentCount;
  //emit_move_S_r(nArgs, reg[0]);
  emit_bftst_i_i_r(0, 1, reg[0]);
  emit_bne(relink);				// SmallInteger => miss
  emit_get_i_r_r(0, reg[0], tmp[0]);		// base header
  emit_bftst_i_i_r(12, 5, tmp[0]);		// cc index bits
  emit_bne(relink);				// non-zero => miss
# if defined(OOPS_IN_CACHE)
# warning: NAKED OOPS IN NC CACHE
  emit_get_i_r_r(-4, reg[0], tmp[0]);		// class header
  emit_xor_r_r(reg[1], tmp[0]);			// compare
# else
  emit_move_v_r(classMemoizer, tmp[0]);
  emit_bfextshl_i_i_i_r_r(18, 12, 2, reg[1], tmp[1]);	// major index
  emit_add_i_r(4, tmp[1]);				// base header
  emit_get_r_r_r(tmp[1], tmp[0], tmp[0]);		// fetch bucket
  emit_bfextshl_i_i_i_r_r( 2, 12, 2, reg[1], tmp[1]);	// minor index
  emit_add_i_r(4, tmp[1]);				// base header
  emit_get_r_r_r(tmp[1], tmp[0], tmp[0]);		// fetch element
  emit_get_i_r_r(-4, reg[0], tmp[1]);			// class header
  emit_xor_r_r(tmp[1], tmp[0]);				// compare
# endif
  emit_bftst_i_i_r(2, 28, tmp[0]);		// ignoring cache flags/type bits
  if (enter != 0) {
    emit_beq(enter);
    emit_jmp(relink);
  } else {
    emit_bne(relink);
  }
  // reg[0] is still the receiver
}


void genIXCacheCheck(NativeMethod *nMeth, Class *rcvrClass, insn *relink)
{
  const int nArgs= nMeth->argumentCount;
  //emit_move_S_r(nArgs, reg[0]);			// receiver
  if (rcvrClass == ClassSmallInteger)
    {
      emit_tagck_r_t(reg[0], relink);
    }
  else
    {
      emit_notagck_r_t(reg[0], relink);
      emit_get_i_r_r(0, reg[0], tmp[0]);	// base header
      if (rcvrClass->hasCompactInstances())
	{
	  const unsigned cci= rcvrClass->ccBits() >> 12;
	  emit_ccick_i_r(cci, tmp[0]);
	  emit_bne(relink);
	}
      else
	{
	  const unsigned major= nMeth->receiverClassIndex.major();
	  const unsigned minor= nMeth->receiverClassIndex.minor();
	  assert(classMemoizer->elementAt(MemoIndex(major, minor)) == rcvrClass);
	  emit_bftst_i_i_r(12, 5, tmp[0]);
	  emit_bne(relink);				// compact class
	  emit_get_i_r_r(-4, reg[0], tmp[0]);		// class header
	  emit_move_v_r(classMemoizer, tmp[1]);		// memoizer
	  emit_get_i_r_r((4+major*4), tmp[1], tmp[1]);	// bucket
	  emit_get_i_r_r((4+minor*4), tmp[1], tmp[1]);	// class
	  emit_bfclr_i_i_r(0, 2, tmp[0]);		// clear header type bits
	  emit_cmp_r_r(tmp[0], tmp[1]);
	  emit_bne(relink);
	}
    }
  // reg[0] is still the receiver
}
