// error.cc -- error handling
//
// Author: Ian.Piumarta@inria.fr
//
// last edited: Tue Feb 23 15:16:24 1999 by piumarta (Ian Piumarta) on pingu


#include "interp.h"
#include "error.h"
#include "translate.h"
#include "cache.h"

#include <stdarg.h>


void printObject(oop o)
{
       if (o == nilObj)		  printf("nil");
  else if (o == trueObj)	  printf("true");
  else if (o == falseObj)	  printf("false");
  else if (o->isInteger())	  printf("=%d", o->integerValue());
  else {
    printf("%p:", o);
    Class *cls= o->fetchClass();
    printNameOfClasscount(cls, 5);
  }
}

void dumpObject(char *prefix, oop o)
{
  printf(prefix);
  printObject(o);
  printf("\n");
}

void dumpMethod(char *prefix, CompiledMethod *m, oop r)
{
  printf(prefix);
  Class *methodClass= findClassOfMethodforReceiver(m, r);
  oop methodSel= findSelectorOfMethodforReceiver(m, r);
  printNameOfClasscount(methodClass, 5);
  printf(">");
  printStringOf(methodSel);
  printf("\n");
}

void dumpMethodContext(MethodContext *cx)
{
  printf("MethodContext  %p\n", cx);
  dumpObject("  sender       ", cx->sender);
  dumpObject("  pc           ", cx->pc);
  dumpObject("  stackp       ", cx->stackp);
  dumpObject("  method       ", cx->method);
  dumpObject("  receiverMap  ", cx->receiverMap);
  dumpObject("  receiver     ", cx->receiver);
  int stackp= cx->stackp->integerValue();
  for (int i= 0; i < stackp; ++i) {
    printf("  stack[%02d]  ", i);
    dumpObject("", cx->stack[i]);
  }
}

void dumpBlockContext(BlockContext *cx)
{
  printf("BlockContext   %p\n", cx);
  dumpObject("  sender       ", cx->sender);
  dumpObject("  pc           ", cx->pc);
  dumpObject("  stackp       ", cx->stackp);
  dumpObject("  nargs        ", cx->nargs);
  dumpObject("  startpc      ", cx->startpc);
  dumpObject("  home         ", cx->home);
  MethodContext *home= cx->home;
  dumpObject("    receiver   ", home->receiver);
  dumpMethod("    method     ", home->method, home->receiver);
  int stackp= cx->stackp->integerValue();
  for (int i= 0; i < stackp; ++i) {
    printf("  stack[%02d]  ", i);
    dumpObject("", cx->stack[i]);
  }
}

void dumpContext(Context *cx)
{
  if (cx->isBlock())
    dumpBlockContext(cx->asBlockContext());
  else
    dumpMethodContext(cx->asMethodContext());
}

///
/// ERROR HANDLING
///
		     
// need to reimplement this so that it knows about cached contexts
void printCallStack(void)
{
  CachedContext *acc= activeCachedContext; 
  Context *ctxt= activeContext;

  if (acc != 0) {
    for (;;) {
      Class *methodClass=
	findClassOfMethodforReceiver(acc->compiledMethod(), acc->receiver);
      oop methodSel=
	findSelectorOfMethodforReceiver(acc->compiledMethod(), acc->receiver);
      printf("*%08x ", (unsigned)acc);
      if (acc->isBlock()) printf("[] in ");
      printNameOfClasscount(methodClass, 5);
      printf(">");
      printStringOf(methodSel);
      printf("\n");
      fflush(stdout);
      if (acc == lowestCachedContext) break;
      acc= acc->parent();
    }
    activeCachedContext= 0;
    ctxt= topStableContext;
    topStableContext= nilObj->asContext();
  }

  assert(ctxt != nilObj->asContext());

  while (ctxt != nilObj) {
    MethodContext *home;
    if (ctxt->isBlockContext())
      home= ctxt->asBlockContext()->home;
    else 
      home= ctxt->asMethodContext();
    Class *methodClass=
      findClassOfMethodforReceiver(home->method, home->receiver);
    oop methodSel=
      findSelectorOfMethodforReceiver(home->method, home->receiver);
    printf(" %08x ", (unsigned)ctxt);
    if (ctxt != home->asContext()) printf("[] in ");
    printNameOfClasscount(methodClass, 5);
    printf(">");
    printStringOf(methodSel);
    printf("\n");
    fflush(stdout);
    ctxt= ctxt->sender;
  }
}


void error(char *fmt, ...)
{
  // Print an error message and exit.
  static bool printingStack= false;

  fprintf(stderr, "\n");
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  va_end(ap);
  fprintf(stderr, "\n\n");

  if (!printingStack) {
    // flag prevents recursive error when trying to print a broken stack
    printingStack= true;
    printCallStack();
  }
  abort();
}

