// generate.cc -- code generation support			-*- C++ -*-
// 
// Author: Ian.Piumarta@INRIA.Fr
//
// Last edited: 2000-10-22 20:39:21 by piumarta on emilia.rd.wdi.disney.com

#include "Memoizer.h"
#include "NativeMethod.h"
#include "RelinkCache.h"

#include "archdep.h"
#include "generate.h"
#include "cachebits.h"

insn *asm_pc= 0;
int   asm_pass= 0;

#include ARCHDEP(emit.h)

// glue

insn
  *g_Pop= 0, *g_Dup= 0,
  *g_LdSelf= 0, *g_bLdSelf= 0,
  *g_LdTrue= 0, *g_LdFalse= 0, *g_LdNil= 0, *g_LdInt= 0,
  *g_LdThisContext= 0,
  *g_LdLit= 0, *g_bLdLit= 0,
  *g_LdInst= 0, *g_bLdInst= 0,  *g_pLdInst= 0, *g_bpLdInst= 0,
  *g_StInst= 0, *g_bStInst= 0,  *g_pStInst= 0, *g_bpStInst= 0,
  *g_PopInst= 0, *g_bPopInst= 0,  *g_pPopInst= 0, *g_bpPopInst= 0,
  *g_LdTemp= 0, *g_bLdTemp= 0, *g_StTemp= 0,
  *g_bStTemp= 0,
  *g_LdLitInd= 0, *g_bLdLitInd= 0, *g_StLitInd= 0,
  *g_bStLitInd= 0,
  *g_Jmp= 0, *g_JmpF= 0, *g_JmpT= 0,
  *g_SuperUnlinked= 0, *g_SendUnlinked= 0, *g_SpecialUnlinked= 0, *g_SpecialDeferred= 0,
  *g_LocalRetTop= 0, *g_RemoteRetTop= 0,
  *g_Add= 0, *g_Subtract= 0,
  *g_LessThan= 0, *g_GreaterThan= 0, *g_LessOrEqual= 0, *g_GreaterOrEqual= 0,
  *g_Equal= 0, *g_NotEqual= 0, *g_Multiply= 0, *g_Divide= 0, *g_Mod= 0,
  *g_MakePoint= 0, *g_BitShift= 0, *g_Div= 0, *g_BitAnd= 0, *g_BitOr= 0, 
  *g_Equivalent= 0, *g_Class= 0,
  *g_BlockCopy= 0, *g_bBlockCopy= 0,
  *g_Lambda= 0, *g_bLambda= 0,
  // used to "escape" from primDoPrimWithArgs on success
  *g_primitiveEpilogue= 0,
  // check if unchecked store is ok
  *g_storeCheck= 0, *g_beRoot= 0, *g_fetchClass= 0,
  // linked send through indirect inline cache 
  *g_sendLinkedIndirect= 0;

// traps

insn
  *t_cxFault= 0, *t_mxFault= 0;



void gen_flushEntry(insn *entry, insn *relink)
{
  asm_pc= entry;
  emit_jmp(relink);
  iflush(entry, asm_pc);
}


void gen_flushMethod(CompiledMethod *cMeth)
{
  if (methodMemoizer->includes(cMeth))
    {
      RelinkCache::initialise();
      MemoIndex cmIndex= methodMemoizer->indexOf(cMeth);
      for (NativeMethod *nMeth= nativeMemoizer->atOrNil(cmIndex);
	   nMeth != 0;
	   nMeth= nMeth->next)
	{
	  PRINTF(("gen_flushMethod: %p ", nMeth);  println(nMeth));
	  nMeth->invalidate();
	}
      nativeMemoizer->flush(cmIndex);
    }
}


// A Behavior has changed.  Invalidate all native methods that are
// defined in cls or any of its subclasses.  This is to prevent (for
// example) native methods from trying to access instance variables
// that have moved.  Answer whether more than 50% of the methods
// have been flushed.

bool gen_flushClass(Class *changedClass)
{
  printf("gen_flushClass: %p ", changedClass);  println(changedClass);
  RelinkCache::initialise();
  int nMethods= 0;
  int nFlushed= 0;
  // scan all methods looking for methods that are defined in
  // classes that are subclasses of cls
  for (NativeMethod *nMeth= NativeMethod::methods;
       nMeth != 0;
       nMeth= nMeth->nextMethod)
    {
      ++nMethods;
      Class *nMethodClass= nMeth->methodClass();
      if (nMethodClass->isSubclassOf(changedClass))
	{
	  ++nFlushed;
	  MemoIndex mIndex= nMeth->methodIndex;
	  nMeth->invalidate();
	  printf("\r%d", nFlushed);
	  //if (0 != nativeMemoizer->atOrNil(mIndex))
	    nativeMemoizer->flush(mIndex);
	}
    }
  printf("/%d flushed\n", nMethods);
  return (nFlushed > (nMethods / 2));
}
