/*************************************************************************
*									 *
*	 YAP Prolog 							 *
*									 *
*	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
*									 *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
*									 *
**************************************************************************
*									 *
* File:		rheap.h							 *
* comments:	walk through heap code					 *
*									 *
* Last rev:     $Date: 2008-08-07 20:51:23 $,$Author: vsc $						 *
* $Log: not supported by cvs2svn $
* Revision 1.99  2008/07/22 23:34:49  vsc
* SWI and module fixes
*
* Revision 1.98  2008/05/12 22:31:37  vsc
* fix previous fixes
*
* Revision 1.97  2008/05/12 14:04:23  vsc
* updates to restore
*
* Revision 1.96  2008/04/11 16:58:17  ricroc
* yapor: seq_def initialization
*
* Revision 1.95  2008/04/06 12:06:48  vsc
* more small fixes
*
* Revision 1.94  2008/04/06 11:53:02  vsc
*  fix some restore bugs
*
* Revision 1.93  2008/04/04 09:10:02  vsc
* restore was restoring twice
*
* Revision 1.92  2008/04/03 11:34:47  vsc
* fix restorebb in cases entry key is not an atom (obs from Nicos
* Angelopoulos)
*
* Revision 1.91  2008/04/01 15:31:43  vsc
* more saved state fixes
*
* Revision 1.90  2008/04/01 14:09:43  vsc
* improve restore
*
* Revision 1.89  2008/04/01 09:41:05  vsc
* more fixes to restore
*
* Revision 1.88  2008/04/01 08:42:46  vsc
* fix restore and small VISTA thingies
*
* Revision 1.87  2008/03/25 22:03:14  vsc
* fix some icc warnings
*
* Revision 1.86  2008/03/25 16:45:53  vsc
* make or-parallelism compile again
*
* Revision 1.85  2008/02/12 17:03:52  vsc
* SWI-portability changes
*
* Revision 1.84  2008/02/07 21:39:51  vsc
* fix case where predicate is for an integer (DBEntry).
*
* Revision 1.83  2008/01/23 17:57:55  vsc
* valgrind it!
* enable atom garbage collection.
*
* Revision 1.82  2007/12/05 12:17:23  vsc
* improve JT
* fix graph compatibility with SICStus
* re-export declaration.
*
* Revision 1.81  2007/11/26 23:43:09  vsc
* fixes to support threads and assert correctly, even if inefficiently.
*
* Revision 1.80  2007/11/07 09:35:53  vsc
* small fix
*
* Revision 1.79  2007/11/07 09:25:27  vsc
* speedup meta-calls
*
* Revision 1.78  2007/11/06 17:02:12  vsc
* compile ground terms away.
*
* Revision 1.77  2007/10/10 09:44:24  vsc
* some more fixes to make YAP swi compatible
* fix absolute_file_name (again)
* fix setarg
*
* Revision 1.76  2007/09/28 23:18:17  vsc
* handle learning from interpretations.
*
* Revision 1.75  2007/04/10 22:13:21  vsc
* fix max modules limitation
*
* Revision 1.74  2007/03/22 11:12:21  vsc
* make sure that YAP_Restart does not restart a failed goal.
*
* Revision 1.73  2007/02/18 00:26:36  vsc
* fix atom garbage collector (although it is still off by default)
* make valgrind feel better
*
* Revision 1.72  2007/01/08 08:27:19  vsc
* fix restore (Trevor)
* make indexing a bit faster on IDB
*
* Revision 1.71  2006/11/27 17:42:03  vsc
* support for UNICODE, and other bug fixes.
*
* Revision 1.70  2006/08/25 19:50:35  vsc
* global data structures
*
* Revision 1.69  2006/08/22 16:12:46  vsc
* global variables
*
* Revision 1.68  2006/08/02 18:18:30  vsc
* preliminary support for readutil library (SWI compatible).
*
* Revision 1.67  2006/05/17 18:38:11  vsc
* make system library use true file name
*
* Revision 1.66  2006/04/28 15:48:33  vsc
* do locking on streams
*
* Revision 1.65  2006/04/28 13:23:23  vsc
* fix number of overflow bugs affecting threaded version
* make current_op faster.
*
* Revision 1.64  2006/03/22 20:07:28  vsc
* take better care of zombies
*
* Revision 1.63  2006/03/06 14:04:56  vsc
* fixes to garbage collector
* fixes to debugger
*
* Revision 1.62  2006/02/24 14:03:42  vsc
* fix refs to old LogUpd implementation (pre 5).
*
* Revision 1.61  2006/01/02 02:16:18  vsc
* support new interface between YAP and GMP, so that we don't rely on our own
* allocation routines.
* Several big fixes.
*
* Revision 1.60  2005/12/17 03:25:39  vsc
* major changes to support online event-based profiling
* improve error discovery and restart on scanner.
*
* Revision 1.59  2005/12/05 17:16:11  vsc
* write_depth/3
* overflow handlings and garbage collection
* Several ipdates to CLPBN
* dif/2 could be broken in the presence of attributed variables.
*
* Revision 1.58  2005/11/23 03:01:33  vsc
* fix several bugs in save/restore.b
*
* Revision 1.57  2005/10/28 17:38:50  vsc
* sveral updates
*
* Revision 1.56  2005/10/21 16:09:03  vsc
* SWI compatible module only operators
*
* Revision 1.55  2005/10/19 19:00:48  vsc
* extend arrays with nb_terms so that we can implement nb_ builtins
* correctly.
*
* Revision 1.54  2005/09/09 17:24:39  vsc
* a new and hopefully much better implementation of atts.
*
* Revision 1.53  2005/08/01 15:40:38  ricroc
* TABLING NEW: better support for incomplete tabling
*
* Revision 1.52  2005/07/06 19:34:11  ricroc
* TABLING: answers for completed calls can now be obtained by loading (new option) or executing (default) them from the trie data structure.
*
* Revision 1.51  2005/07/06 15:10:15  vsc
* improvements to compiler: merged instructions and fixes for ->
*
* Revision 1.50  2005/06/01 13:53:46  vsc
* improve bb routines to use the DB efficiently
* change interface between DB and BB.
*
* Revision 1.49  2005/05/30 03:26:37  vsc
* add some atom gc fixes
*
* Revision 1.48  2005/01/04 02:50:21  vsc
* - allow MegaClauses with blobs
* - change Diffs to be thread specific
* - include Christian's updates
*
* Revision 1.47  2004/12/02 06:06:47  vsc
* fix threads so that they at least start
* allow error handling to work with threads
* replace heap_base by Yap_heap_base, according to Yap's convention for globals.
*
* Revision 1.46  2004/11/23 21:16:21  vsc
* A few extra fixes for saved states.
*
* Revision 1.45  2004/10/26 20:16:18  vsc
* More bug fixes for overflow handling
*
* Revision 1.44  2004/10/06 16:55:47  vsc
* change configure to support big mem configs
* get rid of extra globals
* fix trouble with multifile preds
*
* Revision 1.43  2004/09/27 20:45:04  vsc
* Mega clauses
* Fixes to sizeof(expand_clauses) which was being overestimated
* Fixes to profiling+indexing
* Fixes to reallocation of memory after restoring
* Make sure all clauses, even for C, end in _Ystop
* Don't reuse space for Streams
* Fix Stream_F on StreaNo+1
*
* Revision 1.42  2004/06/05 03:37:00  vsc
* coroutining is now a part of attvars.
* some more fixes.
*
* Revision 1.41  2004/04/29 03:45:50  vsc
* fix garbage collection in execute_tail
*
* Revision 1.40  2004/03/31 01:03:10  vsc
* support expand group of clauses
*
* Revision 1.39  2004/03/19 11:35:42  vsc
* trim_trail for default machine
* be more aggressive about try-retry-trust chains.
*    - handle cases where block starts with a wait
*    - don't use _killed instructions, just let the thing rot by itself.
*									 *
*									 *
*************************************************************************/
#ifdef SCCS
static char     SccsId[] = "@(#)rheap.c	1.3 3/15/90";
#endif

#define Atomics		0
#define Funcs		1

#define ConstantTermAdjust(P) ConstantTermAdjust__(P PASS_REGS)
#define DBGroundTermAdjust(P) DBGroundTermAdjust__(P PASS_REGS)
#define AdjustDBTerm(P,A,B,C) AdjustDBTerm__(P,A,B,C PASS_REGS)
#define AdjustSwitchTable(op, table, i) AdjustSwitchTable__(op, table, i PASS_REGS)
#define RestoreOtaplInst(start, opc, pe)  RestoreOtaplInst__(start, opc, pe PASS_REGS)
#define RestoreDBErasedMarker()  RestoreDBErasedMarker__( PASS_REGS1 )
#define RestoreLogDBErasedMarker()  RestoreLogDBErasedMarker__( PASS_REGS1 )
#define RestoreForeignCode()	RestoreForeignCode__( PASS_REGS1 )
#define RestoreAtoms() RestoreAtoms__( PASS_REGS1 )
#define RestoreWideAtoms() RestoreWideAtoms__( PASS_REGS1 )
#define RestoreSWIBlobs() RestoreSWIBlobs__( PASS_REGS1 )
#define RestoreSWIBlobTypes() RestoreSWIBlobTypes__( PASS_REGS1 )
#define RestoreInvisibleAtoms() RestoreInvisibleAtoms__( PASS_REGS1 )
#define RestorePredHash() RestorePredHash__( PASS_REGS1 )
#define RestoreHiddenPredicates() RestoreHiddenPredicates__( PASS_REGS1 )
#define RestoreDBTermsList() RestoreDBTermsList__( PASS_REGS1 )
#define RestoreExpandList() RestoreExpandList__( PASS_REGS1 )
#define RestoreIntKeys() RestoreIntKeys__( PASS_REGS1 )
#define RestoreIntLUKeys() RestoreIntLUKeys__( PASS_REGS1 )
#define RestoreIntBBKeys() RestoreIntBBKeys__( PASS_REGS1 )
#define RestoreDeadStaticClauses() RestoreDeadStaticClauses__( PASS_REGS1 )
#define RestoreDeadMegaClauses() RestoreDeadMegaClauses__( PASS_REGS1 )
#define RestoreDeadStaticIndices() RestoreDeadStaticIndices__( PASS_REGS1 )
#define RestoreDBErasedList() RestoreDBErasedList__( PASS_REGS1 )
#define RestoreDBErasedIList() RestoreDBErasedIList__( PASS_REGS1 )
#define RestoreYapRecords() RestoreYapRecords__( PASS_REGS1 )
#define RestoreSWIAtoms() RestoreSWIAtoms__( PASS_REGS1 )
static Term
ConstantTermAdjust__ (Term t USES_REGS)
{
  if (IsAtomTerm(t))
    return AtomTermAdjust(t);
  return t;
}

static Term
DBGroundTermAdjust__ (Term t USES_REGS)
{
  /* The term itself is restored by dbtermlist */
  if (IsPairTerm(t)) {
    return AbsPair(PtoHeapCellAdjust(RepPair(t)));
  } else {
    return AbsAppl(PtoHeapCellAdjust(RepAppl(t)));
  }
}

/* Now, everything on its place so you must adjust the pointers */

static void 
do_clean_susp_clauses(yamop *ipc USES_REGS) {
  COUNT i;
  yamop **st = (yamop **)NEXTOP(ipc,sssllp);

  ipc->opc = Yap_opcode(_expand_clauses);
  ipc->u.sssllp.p = PtoPredAdjust(ipc->u.sssllp.p);
  if (ipc->u.sssllp.sprev) {
    ipc->u.sssllp.sprev = PtoOpAdjust(ipc->u.sssllp.sprev);
  }
  if (ipc->u.sssllp.snext) {
    ipc->u.sssllp.snext = PtoOpAdjust(ipc->u.sssllp.snext);
  }
  for (i = 0; i < ipc->u.sssllp.s1; i++, st++) {
    if (*st) {
      *st = PtoOpAdjust(*st);
    }
  }
}

static void
AdjustSwitchTable__(op_numbers op, yamop *table, COUNT i USES_REGS)
{
  CELL *startcode = (CELL *)table;
  /* in case the table is already gone */
  if (!table)
    return;
  switch (op) {
  case _switch_on_func:
    {
      COUNT            j;
      CELL            *oldcode;

      oldcode = startcode;
      for (j = 0; j < i; j++) {
	Functor oldfunc = (Functor)(oldcode[0]);
	CODEADDR oldjmp = (CODEADDR)(oldcode[1]);
	if (oldfunc) {
	  oldcode[0] = (CELL)FuncAdjust(oldfunc);
	}
	oldcode[1] = (CELL)CodeAddrAdjust(oldjmp);
	oldcode += 2;
      }
      rehash(startcode, i, Funcs PASS_REGS);
    }
    break;
  case _switch_on_cons:
    {
      COUNT            j;
      CELL            *oldcode;

#if !defined(USE_OFFSETS)
      oldcode = startcode;
#endif
      for (j = 0; j < i; j++) {
	Term oldcons = oldcode[0];
	CODEADDR oldjmp = (CODEADDR)(oldcode[1]);
	if (oldcons != 0x0 && IsAtomTerm(oldcons)) {
	  oldcode[0] = AtomTermAdjust(oldcons);
	}
	oldcode[1] = (CELL)CodeAddrAdjust(oldjmp);
	oldcode += 2;
      }
#if !USE_OFFSETS
      rehash(startcode, i, Atomics PASS_REGS);
#endif
    }
    break;
  case _go_on_func:
    {
      Functor oldfunc = (Functor)(startcode[0]);

      startcode[0] = (CELL)FuncAdjust(oldfunc);
      startcode[1] = (CELL)CodeAddrAdjust((CODEADDR)startcode[1]);
      startcode[3] = (CELL)CodeAddrAdjust((CODEADDR)startcode[3]);
    }
    break;
  case _go_on_cons:
    {
      Term oldcons = startcode[0];

      if (IsAtomTerm(oldcons)) {
	startcode[0] = AtomTermAdjust(oldcons);
      }
      startcode[1] = (CELL)CodeAddrAdjust((CODEADDR)startcode[1]);
      startcode[3] = (CELL)CodeAddrAdjust((CODEADDR)startcode[3]);
    }
    break;
  case _if_func:
    {
      Int j;

      for (j = 0; j < i; j++) {
	Functor oldfunc = (Functor)(startcode[0]);
	CODEADDR oldjmp = (CODEADDR)(startcode[1]);
	startcode[0] = (CELL)FuncAdjust(oldfunc);
	startcode[1] = (CELL)CodeAddrAdjust(oldjmp);
	startcode += 2;
      }
      /* adjust fail code */
      startcode[1] = (CELL)CodeAddrAdjust((CODEADDR)startcode[1]);
    }
    break;
  case _if_cons:
    {
      Int j;

      for (j = 0; j < i; j++) {
	Term oldcons = startcode[0];
	CODEADDR oldjmp = (CODEADDR)(startcode[1]);
	if (IsAtomTerm(oldcons)) {
	  startcode[0] = (CELL)AtomTermAdjust(oldcons);
	}
	startcode[1] = (CELL)CodeAddrAdjust(oldjmp);
	startcode += 2;
      }
      /* adjust fail code */
      startcode[1] = (CELL)CodeAddrAdjust((CODEADDR)startcode[1]);
    }
    break;
  default:
    Yap_Error(INTERNAL_ERROR,0L,"Opcode Not Implemented in AdjustSwitchTable");
  }
}

STATIC_PROTO(void  RestoreAtomList, (Atom CACHE_TYPE));
STATIC_PROTO(void  RestoreAtom, (AtomEntry * CACHE_TYPE));
STATIC_PROTO(void  RestoreHashPreds, ( CACHE_TYPE1 ));

static void
RestoreAtoms__( USES_REGS1 )
{
  AtomHashEntry *HashPtr;
  register int    i;

  Yap_heap_regs->hash_chain = 
    PtoAtomHashEntryAdjust(Yap_heap_regs->hash_chain);
  HashPtr = HashChain;
  for (i = 0; i < AtomHashTableSize; ++i) {
    HashPtr->Entry = NoAGCAtomAdjust(HashPtr->Entry);
    RestoreAtomList(HashPtr->Entry PASS_REGS);
    HashPtr++;
  }  
}

static void
RestoreWideAtoms__( USES_REGS1 )
{
  AtomHashEntry *HashPtr;
  register int    i;

  Yap_heap_regs->wide_hash_chain = 
    PtoAtomHashEntryAdjust(Yap_heap_regs->wide_hash_chain);
  HashPtr = WideHashChain;
  for (i = 0; i < WideAtomHashTableSize; ++i) {
    HashPtr->Entry = AtomAdjust(HashPtr->Entry);
    RestoreAtomList(HashPtr->Entry PASS_REGS);
    HashPtr++;
  }  
}

static void
RestoreInvisibleAtoms__( USES_REGS1 )
{
  INVISIBLECHAIN.Entry = AtomAdjust(INVISIBLECHAIN.Entry);
  RestoreAtomList(INVISIBLECHAIN.Entry PASS_REGS);
  RestoreAtom(RepAtom(AtomFoundVar) PASS_REGS);
  RestoreAtom(RepAtom(AtomFreeTerm) PASS_REGS);
}

#include "rclause.h"

/* adjusts terms stored in the data base, when they have no variables */
static Term 
AdjustDBTerm__(Term trm, Term *p_base, Term *p_lim, Term *p_max USES_REGS)
{
  if (IsVarTerm(trm))
    return CodeVarAdjust(trm);
  if (IsAtomTerm(trm))
    return AtomTermAdjust(trm);
  if (IsPairTerm(trm)) {
    Term           *p;
    Term out;

    p = PtoHeapCellAdjust(RepPair(trm));
    out = AbsPair(p);
  loop:
    if (p >= p_base || p < p_lim) {
      p[0] = AdjustDBTerm(p[0], p, p_lim, p_max);
      if (IsPairTerm(p[1])) {
	/* avoid term recursion with very deep lists */
	Term *newp = PtoHeapCellAdjust(RepPair(p[1]));
	p[1] = AbsPair(newp);
	p_base = p;
	p = newp;
	goto loop;
      } else {
	p[1] = AdjustDBTerm(p[1], p, p_lim, p_max);
      }
    }
    return out;
  }
  if (IsApplTerm(trm)) {
    Term           *p;
    Functor f;
    Term *p0 = p = PtoHeapCellAdjust(RepAppl(trm));
    /* if it is before the current position, then we are looking
       at old code */
    if (p >= p_base || p < p_lim) {
      if (p >= p_max || p < p_lim) {
	if (DBRefOfTerm(trm)!=DBRefAdjust(DBRefOfTerm(trm),FALSE))
	/* external term pointer, has to be a DBRef */
	return MkDBRefTerm(DBRefAdjust(DBRefOfTerm(trm),FALSE));
      }
      f = (Functor)p[0];
      if (!IsExtensionFunctor(f)) {
	UInt             Arity, i;

	f = FuncAdjust(f);
	*p++ = (Term)f;
	Arity = ArityOfFunctor(f);
	for (i = 0; i < Arity; ++i) {
	  *p = AdjustDBTerm(*p, p0, p_lim, p_max);
	  p++;
	}
      } else if (f == FunctorDBRef) {
      }
    }
    return AbsAppl(p0);
  }
  return trm;
}

static void
RestoreDBTerm(DBTerm *dbr, int attachments USES_REGS)
{
  if (attachments) {
#ifdef COROUTINING
    if (dbr->ag.attachments)
      dbr->ag.attachments = AdjustDBTerm(dbr->ag.attachments, dbr->Contents, dbr->Contents, dbr->Contents+dbr->NOfCells);
#endif
  } else {
    if (dbr->ag.NextDBT)
      dbr->ag.NextDBT = DBTermAdjust(dbr->ag.NextDBT);
  }    
  if (dbr->DBRefs) {
    DBRef          *cp;
    DBRef            tm;

    dbr->DBRefs = DBRefPAdjust(dbr->DBRefs);
    cp = dbr->DBRefs;
    while ((tm = *--cp) != 0) {
      *cp = DBRefAdjust(tm,TRUE);
    }
  }
  dbr->Entry = AdjustDBTerm(dbr->Entry, dbr->Contents, dbr->Contents, dbr->Contents+dbr->NOfCells);
}

/* Restoring the heap */

/* Restores a prolog clause, in its compiled form */
static void 
RestoreStaticClause(StaticClause *cl USES_REGS)
/*
 * Cl points to the start of the code, IsolFlag tells if we have a single
 * clause for this predicate or not 
 */
{
  if (cl->usc.ClSource) {
    char *x = (char *)DBTermAdjust(cl->usc.ClSource);
    char *base = (char *)cl;

    if (x < base || x >= base+cl->ClSize) {
      cl->usc.ClPred = PtoPredAdjust(cl->usc.ClPred);
    } else {
      cl->usc.ClSource = DBTermAdjust(cl->usc.ClSource);
      RestoreDBTerm(cl->usc.ClSource, TRUE PASS_REGS);
    }
  }
  if (cl->ClNext) {
    cl->ClNext = PtoStCAdjust(cl->ClNext);
  }
  restore_opcodes(cl->ClCode, NULL PASS_REGS);
}

/* Restores a prolog clause, in its compiled form */
static void 
RestoreMegaClause(MegaClause *cl USES_REGS)
/*
 * Cl points to the start of the code, IsolFlag tells if we have a single
 * clause for this predicate or not 
 */
{
  yamop *ptr, *max, *nextptr;

  cl->ClPred = PtoPredAdjust(cl->ClPred);
  if (cl->ClNext) {
    cl->ClNext = (MegaClause *)AddrAdjust((ADDR)(cl->ClNext));
  }
  max = (yamop *)((CODEADDR)cl+cl->ClSize);

  if (cl->ClFlags & ExoMask) {
    CELL *base = (CELL *)((ADDR)cl->ClCode+2*sizeof(struct index_t *));
    CELL *end = (CELL*)max, *ptr;

    for (ptr = base; ptr < end; ptr++) {
      Term t = *ptr;
      if (IsAtomTerm(t)) *ptr = AtomTermAdjust(t);
      /* don't handle other complex terms just yet, ints are ok  */
    }
  } else {
    for (ptr = cl->ClCode; ptr < max; ) {
      nextptr = (yamop *)((char *)ptr + cl->ClItemSize);
      restore_opcodes(ptr, nextptr PASS_REGS);
      ptr = nextptr;
    }
  }
}

/* Restores a prolog clause, in its compiled form */
static void 
RestoreDynamicClause(DynamicClause *cl, PredEntry *pp USES_REGS)
/*
 * Cl points to the start of the code, IsolFlag tells if we have a single
 * clause for this predicate or not 
 */
{
  if (cl->ClPrevious != NULL) {
    cl->ClPrevious = PtoOpAdjust(cl->ClPrevious);
  }
  INIT_LOCK(cl->ClLock);
  restore_opcodes(cl->ClCode, NULL PASS_REGS);
}

/* Restores a prolog clause, in its compiled form */
static void 
RestoreLUClause(LogUpdClause *cl, PredEntry *pp USES_REGS)
/*
 * Cl points to the start of the code, IsolFlag tells if we have a single
 * clause for this predicate or not 
 */
{
  //  INIT_LOCK(cl->ClLock);
  if (cl->ClFlags & LogUpdRuleMask) {
    cl->ClExt = PtoOpAdjust(cl->ClExt);
  }
  if (cl->ClSource) {
    cl->ClSource = DBTermAdjust(cl->ClSource);
    RestoreDBTerm(cl->ClSource, TRUE PASS_REGS);
  }
  if (cl->ClPrev) {
    cl->ClPrev = PtoLUCAdjust(cl->ClPrev);
  }
  if (cl->ClNext) {
    cl->ClNext = PtoLUCAdjust(cl->ClNext);
  }
  cl->ClPred = PtoPredAdjust(cl->ClPred);
  restore_opcodes(cl->ClCode, NULL PASS_REGS);
}

static void
RestoreDBTermEntry(struct dbterm_list *dbl USES_REGS) {
  DBTerm *dbt;

  if (dbl->dbterms)
    dbt = dbl->dbterms = DBTermAdjust(dbl->dbterms);
  else
    return;
  dbl->clause_code = PtoOpAdjust(dbl->clause_code);
  if (dbl->next_dbl)
    dbl->next_dbl = PtoDBTLAdjust(dbl->next_dbl);
  dbl->p = PredEntryAdjust(dbl->p);
  while (dbt) {
    RestoreDBTerm(dbt, FALSE PASS_REGS);
    dbt = dbt->ag.NextDBT;
  }
}

static void 
CleanLUIndex(LogUpdIndex *idx, int recurse USES_REGS)
{
  //  INIT_LOCK(idx->ClLock);
  idx->ClPred = PtoPredAdjust(idx->ClPred);
  if (idx->ParentIndex)
    idx->ParentIndex = LUIndexAdjust(idx->ParentIndex);
  if (idx->PrevSiblingIndex) {
    idx->PrevSiblingIndex = LUIndexAdjust(idx->PrevSiblingIndex);
  }
  if (idx->SiblingIndex) {
    idx->SiblingIndex = LUIndexAdjust(idx->SiblingIndex);
    if (recurse)
      CleanLUIndex(idx->SiblingIndex, TRUE PASS_REGS);
  }
  if (idx->ChildIndex) {
    idx->ChildIndex = LUIndexAdjust(idx->ChildIndex);
    if (recurse)
      CleanLUIndex(idx->ChildIndex, TRUE PASS_REGS);
  }
  if (!(idx->ClFlags & SwitchTableMask)) {
    restore_opcodes(idx->ClCode, NULL PASS_REGS);
  }
}

static void 
CleanSIndex(StaticIndex *idx, int recurse USES_REGS)
{
 beginning:
  if (!(idx->ClFlags & SwitchTableMask)) {
    restore_opcodes(idx->ClCode, NULL PASS_REGS);
  }
  idx->ClPred = PtoPredAdjust(idx->ClPred);
  if (idx->ChildIndex) {
    idx->ChildIndex = SIndexAdjust(idx->ChildIndex);
    if (recurse)
      CleanSIndex(idx->ChildIndex, TRUE PASS_REGS);
  }
  if (idx->SiblingIndex) {
    idx->SiblingIndex = SIndexAdjust(idx->SiblingIndex);
    /* use loop to avoid recursion with very complex indices */
    if (recurse) {
      idx =  idx->SiblingIndex;
      goto beginning;
    }
  }
}

static void 
RestoreSWIAtoms__( USES_REGS1 )
{
  int i, j;
  for (i=0; i < N_SWI_ATOMS; i++) {
    SWI_Atoms[i] = AtomAdjust(SWI_Atoms[i]);
  }
  for (j=0; j < N_SWI_FUNCTORS; j++) {
    SWI_Functors[j] = FuncAdjust(SWI_Functors[j]);
  }
  RestoreSWIHash();
}

static void 
RestoreSWIBlobTypes__( USES_REGS1 )
{
}

static void 
RestoreSWIBlobs__( USES_REGS1 )
{
  SWI_Blobs = AtomAdjust(SWI_Blobs);
  RestoreAtomList(SWI_Blobs PASS_REGS);
}

static void
RestoreHiddenPredicates__( USES_REGS1 )
{
  HIDDEN_PREDICATES = PropAdjust(HIDDEN_PREDICATES);
  RestoreEntries(HIDDEN_PREDICATES, TRUE PASS_REGS);
}


static void
RestorePredHash__( USES_REGS1 )
{
  PredHash = PtoPtoPredAdjust(PredHash);
  if (PredHash == NULL) {
    Yap_Error(FATAL_ERROR,MkIntTerm(0),"restore should find predicate hash table");
  }
  REINIT_RWLOCK(PredHashRWLock);
  RestoreHashPreds( PASS_REGS1 ); /* does most of the work */
}

static void
RestoreEnvInst(yamop start[2], yamop **instp, op_numbers opc, PredEntry *pred)
{
  yamop *ipc = start;

  ipc->opc = Yap_opcode(_call);
  ipc->u.Osbpp.p = pred;
  ipc->u.Osbpp.p0 = pred;
  ipc = NEXTOP(ipc, Osbpp);
  ipc->opc = Yap_opcode(opc);
  *instp = ipc;
}

static void
RestoreOtaplInst__(yamop start[1], OPCODE opc, PredEntry *pe USES_REGS)
{
  yamop *ipc = start;

  /* this is a place holder, it should not really be used */
  ipc->opc = Yap_opcode(opc);
  ipc->u.Otapl.s = 0;
  ipc->u.Otapl.p = pe;
  if (ipc->u.Otapl.d)
    ipc->u.Otapl.d = PtoOpAdjust(ipc->u.Otapl.d);
#ifdef YAPOR
  INIT_YAMOP_LTT(ipc, 1);
#endif /* YAPOR */
#ifdef TABLING
  ipc->u.Otapl.te = NULL;
#endif /* TABLING */
}

static void
RestoreDBTermsList__( USES_REGS1 )
{
  if (Yap_heap_regs->dbterms_list) {
    struct dbterm_list *dbl = PtoDBTLAdjust(Yap_heap_regs->dbterms_list);
    Yap_heap_regs->dbterms_list = dbl;
    while (dbl) {
      RestoreDBTermEntry(dbl PASS_REGS);
      dbl = dbl->next_dbl;
    }
  }
}

static void
RestoreExpandList__( USES_REGS1 )
{
  if (Yap_heap_regs->expand_clauses_first)
    Yap_heap_regs->expand_clauses_first = PtoOpAdjust(Yap_heap_regs->expand_clauses_first);
  if (Yap_heap_regs->expand_clauses_last)
    Yap_heap_regs->expand_clauses_last = PtoOpAdjust(Yap_heap_regs->expand_clauses_last);
  {
    yamop *ptr = Yap_heap_regs->expand_clauses_first;
    while (ptr) {
      do_clean_susp_clauses(ptr PASS_REGS);
      ptr = ptr->u.sssllp.snext;
    }
  }
}

static void
RestoreUdiControlBlocks(void)
{
  if (Yap_heap_regs->udi_control_blocks) {
      Yap_Error(SYSTEM_ERROR, TermNil,
	    "YAP cannot restore UDI entries!!\n");
  }
}

static void
RestoreIntKeys__( USES_REGS1 )
{
  if (Yap_heap_regs->IntKeys != NULL) {
    Yap_heap_regs->IntKeys = (Prop *)AddrAdjust((ADDR)(Yap_heap_regs->IntKeys));
    {
      UInt i;
      for (i = 0; i < Yap_heap_regs->int_keys_size; i++) {
	if (Yap_heap_regs->IntKeys[i] != NIL) {
	  Prop p0 = Yap_heap_regs->IntKeys[i] = PropAdjust(Yap_heap_regs->IntKeys[i]);
	  RestoreEntries(RepProp(p0), TRUE PASS_REGS);
	}
      }
    }
  }
}

static void
RestoreIntLUKeys__( USES_REGS1 )
{
  if (Yap_heap_regs->IntLUKeys != NULL) {
    Yap_heap_regs->IntLUKeys = (Prop *)AddrAdjust((ADDR)(Yap_heap_regs->IntLUKeys));
    {
      Int i;
      for (i = 0; i < INT_KEYS_SIZE; i++) {
	Prop p0 = INT_LU_KEYS[i];
	if (p0) {
	  p0 = PropAdjust(p0);
	  INT_LU_KEYS[i] = p0;
	  while (p0) {
	    PredEntry *pe = RepPredProp(p0);
	    pe->NextOfPE =
	      PropAdjust(pe->NextOfPE);
	    CleanCode(pe PASS_REGS);
	    p0 = RepProp(pe->NextOfPE);
	  }
	}
      }
    }
  }
}

static void
RestoreIntBBKeys__( USES_REGS1 )
{
  if (Yap_heap_regs->IntBBKeys != NULL) {
    Yap_heap_regs->IntBBKeys = (Prop *)AddrAdjust((ADDR)(Yap_heap_regs->IntBBKeys));
    {
      UInt i;
      for (i = 0; i < Yap_heap_regs->int_bb_keys_size; i++) {
	if (Yap_heap_regs->IntBBKeys[i] != NIL) {
	  Prop p0 = Yap_heap_regs->IntBBKeys[i] = PropAdjust(Yap_heap_regs->IntBBKeys[i]);
	  RestoreEntries(RepProp(p0), TRUE PASS_REGS);
	}
      }
    }
  }
}

static void 
RestoreDBErasedMarker__( USES_REGS1 )
{
  Yap_heap_regs->db_erased_marker =
    DBRefAdjust(Yap_heap_regs->db_erased_marker,TRUE);
  Yap_heap_regs->db_erased_marker->id = FunctorDBRef;
  Yap_heap_regs->db_erased_marker->Flags = ErasedMask;
  Yap_heap_regs->db_erased_marker->Code = NULL;
  Yap_heap_regs->db_erased_marker->DBT.DBRefs = NULL;
  Yap_heap_regs->db_erased_marker->Parent = NULL;
}

static void 
RestoreLogDBErasedMarker__( USES_REGS1 )
{
  Yap_heap_regs->logdb_erased_marker =
    PtoLUCAdjust(Yap_heap_regs->logdb_erased_marker);
  Yap_heap_regs->logdb_erased_marker->Id = FunctorDBRef;
  Yap_heap_regs->logdb_erased_marker->ClFlags = ErasedMask|LogUpdMask;
  Yap_heap_regs->logdb_erased_marker->ClSource = NULL;
  Yap_heap_regs->logdb_erased_marker->ClRefCount = 0;
  Yap_heap_regs->logdb_erased_marker->ClPred = PredLogUpdClause;
  Yap_heap_regs->logdb_erased_marker->ClExt = NULL;
  Yap_heap_regs->logdb_erased_marker->ClPrev = NULL;
  Yap_heap_regs->logdb_erased_marker->ClNext = NULL;
  Yap_heap_regs->logdb_erased_marker->ClSize = (UInt)NEXTOP(((LogUpdClause *)NULL)->ClCode,e);
  Yap_heap_regs->logdb_erased_marker->ClCode->opc = Yap_opcode(_op_fail);
  INIT_CLREF_COUNT(Yap_heap_regs->logdb_erased_marker);
}

static void 
RestoreDeadStaticClauses__( USES_REGS1 )
{
  if (Yap_heap_regs->dead_static_clauses) {
    StaticClause *sc = PtoStCAdjust(Yap_heap_regs->dead_static_clauses);
    Yap_heap_regs->dead_static_clauses = sc;
    while (sc) {
      RestoreStaticClause(sc PASS_REGS);
      sc = sc->ClNext;
    }
  }
}

static void 
RestoreDeadMegaClauses__( USES_REGS1 )
{
  if (Yap_heap_regs->dead_mega_clauses) {
    MegaClause *mc = (MegaClause *)AddrAdjust((ADDR)(Yap_heap_regs->dead_mega_clauses));
    Yap_heap_regs->dead_mega_clauses = mc;
    while (mc) {
      RestoreMegaClause(mc PASS_REGS);
      mc = mc->ClNext;
    }
  }
}

static void 
RestoreDeadStaticIndices__( USES_REGS1 )
{
  if (Yap_heap_regs->dead_static_indices) {
    StaticIndex *si = (StaticIndex *)AddrAdjust((ADDR)(Yap_heap_regs->dead_static_indices));
    Yap_heap_regs->dead_static_indices = si;
    while (si) {
      CleanSIndex(si, FALSE PASS_REGS);
      si = si->SiblingIndex;
    }
  }
}

static void 
RestoreDBErasedList__( USES_REGS1 )
{
  if (Yap_heap_regs->db_erased_list) {
    LogUpdClause *lcl = Yap_heap_regs->db_erased_list = 
      PtoLUCAdjust(Yap_heap_regs->db_erased_list);
    while (lcl) {
      RestoreLUClause(lcl, FALSE PASS_REGS);
      lcl = lcl->ClNext;
    }
  }
}

static void 
RestoreDBErasedIList__( USES_REGS1 )
{
  if (Yap_heap_regs->db_erased_ilist) {
    LogUpdIndex *icl = Yap_heap_regs->db_erased_ilist = 
      LUIndexAdjust(Yap_heap_regs->db_erased_ilist);
    while (icl) {
      CleanLUIndex(icl, FALSE PASS_REGS);
      icl = icl->SiblingIndex;
    }
  }
}

static void
RestoreStreams(void)
{
}

static void
RestoreAliases(void)
{
}

static void
RestoreForeignCode__( USES_REGS1 )
{
  ForeignObj *f_code;

  if (!ForeignCodeLoaded)
    return;
  if (ForeignCodeLoaded != NULL) 
    ForeignCodeLoaded = (void *)AddrAdjust((ADDR)ForeignCodeLoaded);
  f_code = ForeignCodeLoaded;
  while (f_code != NULL) {
    StringList objs, libs;
    if (f_code->objs != NULL)
      f_code->objs = (StringList)AddrAdjust((ADDR)f_code->objs);
    objs = f_code->objs;
    while (objs != NULL) {
      if (objs->next != NULL)
	objs->next = (StringList)AddrAdjust((ADDR)objs->next);
	objs->name = AtomAdjust(objs->name);
      objs = objs->next;
    }
    if (f_code->libs != NULL)
      f_code->libs = (StringList)AddrAdjust((ADDR)f_code->libs);
    libs = f_code->libs;
    while (libs != NULL) {
      if (libs->next != NULL)
	libs->next = (StringList)AddrAdjust((ADDR)libs->next);
      libs->name = AtomAdjust(libs->name);
      libs = libs->next;
    }
    if (f_code->f != NULL) {
      f_code->f = AtomAdjust(f_code->f);
    }
    if (f_code->next != NULL)
      f_code->next = (ForeignObj *)AddrAdjust((ADDR)f_code->next);
    f_code = f_code->next;
  }
}

static void
RestoreYapRecords__( USES_REGS1 )
{
  struct record_list *ptr;

  Yap_Records = DBRecordAdjust(Yap_Records);
  ptr = Yap_Records;
  while (ptr) {
    ptr->next_rec = DBRecordAdjust(ptr->next_rec);
    ptr->prev_rec = DBRecordAdjust(ptr->prev_rec);
    ptr->dbrecord = DBTermAdjust(ptr->dbrecord);
    RestoreDBTerm(ptr->dbrecord, FALSE PASS_REGS);
  }
}

static void
RestoreBallTerm(int wid)
{
  CACHE_REGS
  if (LOCAL_BallTerm) {
    LOCAL_BallTerm  = DBTermAdjust(LOCAL_BallTerm);
    RestoreDBTerm(LOCAL_BallTerm, TRUE PASS_REGS);
  }
}

#include "rglobals.h"
#include "rlocals.h"

/* restore the failcodes */
static void 
restore_codes(void)
{
  CACHE_REGS
  Yap_heap_regs->heap_top = AddrAdjust(LOCAL_OldHeapTop);
#include "rhstruct.h"
  RestoreGlobal();
#ifndef worker_id
#define worker_id 0
#endif
  RestoreWorker(worker_id  PASS_REGS);
 }


static void
RestoreDBEntry(DBRef dbr USES_REGS)
{
#ifdef DEBUG_RESTORE
  fprintf(stderr, "Restoring at %x", dbr);
  if (dbr->Flags & DBAtomic)
    fprintf(stderr, " an atomic term\n");
  else if (dbr->Flags & DBNoVars)
    fprintf(stderr, " with no vars\n");
  else if (dbr->Flags & DBComplex)
    fprintf(stderr, " complex term\n");
  else if (dbr->Flags & DBIsRef)
    fprintf(stderr, " a ref\n");
  else
    fprintf(stderr, " a var\n");
#endif
  RestoreDBTerm(&(dbr->DBT), TRUE PASS_REGS);
  if (dbr->Parent) {
    dbr->Parent = (DBProp)AddrAdjust((ADDR)(dbr->Parent));
  }
  if (dbr->Code != NULL)
    dbr->Code = PtoOpAdjust(dbr->Code);
  if (dbr->Prev != NULL)
    dbr->Prev = DBRefAdjust(dbr->Prev,TRUE);
  if (dbr->Next != NULL)
    dbr->Next = DBRefAdjust(dbr->Next,TRUE);
#ifdef DEBUG_RESTORE2
  fprintf(stderr, "Recomputing masks\n");
#endif
  recompute_mask(dbr);
}

/* Restores a DB structure, as it was saved in the heap */
static void 
RestoreDB(DBEntry *pp USES_REGS)
{
  register DBRef  dbr;

  if (pp->First != NULL)
    pp->First = DBRefAdjust(pp->First,TRUE);
  if (pp->Last != NULL)
    pp->Last = DBRefAdjust(pp->Last, TRUE);
  if (pp->ArityOfDB)
    pp->FunctorOfDB = FuncAdjust(pp->FunctorOfDB);
  else
    pp->FunctorOfDB = (Functor) AtomAdjust((Atom)(pp->FunctorOfDB));
  if (pp->F0 != NULL)
    pp->F0 = DBRefAdjust(pp->F0, TRUE);
  if (pp->L0 != NULL)
    pp->L0 = DBRefAdjust(pp->L0, TRUE);
  /* immediate update semantics */
  dbr = pp->F0;
  /* While we have something in the data base, even if erased, restore it */
  while (dbr) {
    RestoreDBEntry(dbr PASS_REGS);
    if (dbr->n != NULL)
      dbr->n = DBRefAdjust(dbr->n, TRUE);
    if (dbr->p != NULL)
      dbr->p = DBRefAdjust(dbr->p, TRUE);
    dbr = dbr->n;
  }
}

/*
 * Restores a group of clauses for the same predicate, starting with First
 * and ending with Last, First may be equal to Last 
 */
static void 
CleanClauses(yamop *First, yamop *Last, PredEntry *pp USES_REGS)
{
    if (!First)
      return;
  if (pp->PredFlags & LogUpdatePredFlag) {
    LogUpdClause *cl = ClauseCodeToLogUpdClause(First);
    while (cl != NULL) {
      RestoreLUClause(cl, pp PASS_REGS);
      cl = cl->ClNext;
    }
  } else if (pp->PredFlags & MegaClausePredFlag) {
    MegaClause *cl = ClauseCodeToMegaClause(First);

    RestoreMegaClause(cl PASS_REGS);
  } else if (pp->PredFlags & DynamicPredFlag) {
    yamop *cl = First;

    do {
      RestoreDynamicClause(ClauseCodeToDynamicClause(cl), pp PASS_REGS);
      if (cl == Last) return;
      cl = NextDynamicClause(cl);
    } while (TRUE);
  } else {
    StaticClause *cl = ClauseCodeToStaticClause(First);

    do {
      RestoreStaticClause(cl PASS_REGS);
      if (cl->ClCode == Last) return;
      cl = cl->ClNext;
    } while (TRUE);
  }
}



/* Restores a DB structure, as it was saved in the heap */
static void 
RestoreBB(BlackBoardEntry *pp, int int_key USES_REGS)
{
  Term t = pp->Element;
  if (t) {
    if (!IsVarTerm(t)) {
      if (IsAtomicTerm(t)) {
	if (IsAtomTerm(t)) {
	  pp->Element = AtomTermAdjust(t);
	}
      } else {
	RestoreLUClause((LogUpdClause *)DBRefOfTerm(t),NULL PASS_REGS);
      }
    }
  }
  if (!int_key) {
    pp->KeyOfBB = AtomAdjust(pp->KeyOfBB);
  }
  if (pp->ModuleOfBB) {
    pp->ModuleOfBB = AtomTermAdjust(pp->ModuleOfBB);
  }
}

static void
restore_static_array(StaticArrayEntry *ae USES_REGS)
{
  Int sz = -ae->ArrayEArity;
  switch (ae->ArrayType) {
  case array_of_ints:
  case array_of_doubles:
  case array_of_chars:
  case array_of_uchars:
  return;
  case array_of_ptrs:
    {
      AtomEntry **base = (AtomEntry **)AddrAdjust((ADDR)(ae->ValueOfVE.ptrs));
      Int i;
      ae->ValueOfVE.ptrs = base;
      if (ae != NULL) {
	for (i=0; i<sz; i++) {
	  AtomEntry *reg = *base;
	  if (reg == NULL) {
	    base++;
	  } else if (IsOldCode((CELL)reg)) {
	    *base++ = AtomEntryAdjust(reg);
	  } else if (IsOldLocalInTR((CELL)reg)) {
	    *base++ = (AtomEntry *)LocalAddrAdjust((ADDR)reg);
	  } else if (IsOldGlobal((CELL)reg)) {
	    *base++ = (AtomEntry *)GlobalAddrAdjust((ADDR)reg);
	  } else if (IsOldTrail((CELL)reg)) {
	    *base++ = (AtomEntry *)TrailAddrAdjust((ADDR)reg);
	  } else {
	    /* oops */
	    base++;
	  }
	}
      }
    }
  return;
  case array_of_atoms:  
    {
      Term *base = (Term *)AddrAdjust((ADDR)(ae->ValueOfVE.atoms));
      Int i;
      ae->ValueOfVE.atoms = base;
      if (ae != 0L) {
	for (i=0; i<sz; i++) {
	  Term reg = *base;
	  if (reg == 0L) {
	    base++;
	  } else {
	    *base++ = AtomTermAdjust(reg);
	  }
	}
      }
    }
  return;
  case array_of_dbrefs:
    {
      Term *base = (Term *)AddrAdjust((ADDR)(ae->ValueOfVE.dbrefs));
      Int i;

      ae->ValueOfVE.dbrefs = base;
      if (ae != 0L) {
	for (i=0; i<sz; i++) {
	  Term reg = *base;
	  if (reg == 0L) {
	    base++;
	  } else {
	    *base++ = AbsAppl(PtoHeapCellAdjust(RepAppl(reg)));
	  }
	}
      }
    }
  return;
  case array_of_nb_terms:
    {
      live_term *base = (live_term *)AddrAdjust((ADDR)(ae->ValueOfVE.lterms));
      Int i;

      ae->ValueOfVE.lterms = base;
      if (ae != 0L) {
	for (i=0; i < sz; i++,base++) {
	  Term reg = base->tlive;
	  if (IsVarTerm(reg)) {
	    CELL *var = (CELL *)reg;

	    if (IsOldGlobalPtr(var)) {
	      base->tlive = (CELL)PtoGloAdjust(var);
	    } else {
	      base->tlive = (CELL)PtoHeapCellAdjust(var);
	    }
	  } else if (IsAtomTerm(reg)) {
	    base->tlive = AtomTermAdjust(reg);
	  } else if (IsApplTerm(reg)) {
	    CELL *db = RepAppl(reg);
	    db = PtoGloAdjust(db);
	    base->tlive = AbsAppl(db);
	  } else if (IsApplTerm(reg)) {
	    CELL *db = RepPair(reg);
	    db = PtoGloAdjust(db);
	    base->tlive = AbsPair(db);
	  }

	  reg = base->tstore;
	  if (IsVarTerm(reg)) {
	    base->tstore = (Term)GlobalAddrAdjust((ADDR)reg);
	  } else if (IsAtomTerm(reg)) {
	    base->tstore = AtomTermAdjust(reg);
	  } else {
	    DBTerm *db = (DBTerm *)RepAppl(reg);
	    db = DBTermAdjust(db);
	    RestoreDBTerm(db, TRUE PASS_REGS);
	    base->tstore = AbsAppl((CELL *)db);
	  }
	}
      }
    }
  case array_of_terms:
    {
      DBTerm **base = (DBTerm **)AddrAdjust((ADDR)(ae->ValueOfVE.terms));
      Int i;

      ae->ValueOfVE.terms = base;
      if (ae != 0L) {
	for (i=0; i<sz; i++) {
	  DBTerm *reg = *base;
	  if (reg == NULL) {
	    base++;
	  } else {
	    *base++ = reg = DBTermAdjust(reg);
	    RestoreDBTerm(reg, TRUE PASS_REGS);
	  }
	}
      }
    }
  return;
  }
}

/*
 * Clean all the code for a particular predicate, this can get a bit tricky,
 * because of the indexing code 
 */
static void 
CleanCode(PredEntry *pp USES_REGS)
{
  CELL            flag;


  /* Init takes care of the first 2 cases */
  if (pp->ModuleOfPred) {
    pp->ModuleOfPred = AtomTermAdjust(pp->ModuleOfPred);
  }
  if (pp->ArityOfPE) {
    if (pp->ModuleOfPred == IDB_MODULE) {
      if (pp->PredFlags & NumberDBPredFlag) {
	/* it's an integer, do nothing */
      } else if (pp->PredFlags & AtomDBPredFlag) {
	pp->FunctorOfPred = (Functor)AtomAdjust((Atom)(pp->FunctorOfPred));
      } else {
	pp->FunctorOfPred = FuncAdjust(pp->FunctorOfPred);
      }
    } else {
      pp->FunctorOfPred = FuncAdjust(pp->FunctorOfPred);
    }
  } else {
    pp->FunctorOfPred = (Functor)AtomAdjust((Atom)(pp->FunctorOfPred));
  }
  if (!(pp->PredFlags & NumberDBPredFlag)) {
    if (pp->src.OwnerFile) {
      pp->src.OwnerFile = AtomAdjust(pp->src.OwnerFile);
    }
  }
  pp->OpcodeOfPred = Yap_opcode(Yap_op_from_opcode(pp->OpcodeOfPred));
  if (pp->NextPredOfModule) {
    pp->NextPredOfModule = PtoPredAdjust(pp->NextPredOfModule);
  }
  if (pp->PredFlags & (AsmPredFlag|CPredFlag)) {
    /* assembly */
    if (pp->CodeOfPred) {
      pp->CodeOfPred = PtoOpAdjust(pp->CodeOfPred);
      CleanClauses(pp->CodeOfPred, pp->CodeOfPred, pp PASS_REGS);
    }
  } else {
    yamop        *FirstC, *LastC;
    /* Prolog code */
    if (pp->cs.p_code.FirstClause)
      pp->cs.p_code.FirstClause = PtoOpAdjust(pp->cs.p_code.FirstClause);
    if (pp->cs.p_code.LastClause)
      pp->cs.p_code.LastClause = PtoOpAdjust(pp->cs.p_code.LastClause);
    pp->CodeOfPred =PtoOpAdjust(pp->CodeOfPred);
    pp->cs.p_code.TrueCodeOfPred = PtoOpAdjust(pp->cs.p_code.TrueCodeOfPred);
    pp->cs.p_code.ExpandCode = Yap_opcode(_expand_index);
    flag = pp->PredFlags;
    FirstC = pp->cs.p_code.FirstClause;
    LastC = pp->cs.p_code.LastClause;
    /* We just have a fail here */
    if (FirstC == NULL && LastC == NULL) {
      return;
    }
#ifdef	DEBUG_RESTORE2
    fprintf(stderr, "at %ux Correcting clauses from %p to %p\n", *(OPCODE *) FirstC, FirstC, LastC);
#endif
    CleanClauses(FirstC, LastC, pp PASS_REGS);
    if (flag & IndexedPredFlag) {
#ifdef	DEBUG_RESTORE2
      fprintf(stderr, "Correcting indexed code\n");
#endif
      if (flag & LogUpdatePredFlag) {
	CleanLUIndex(ClauseCodeToLogUpdIndex(pp->cs.p_code.TrueCodeOfPred), TRUE PASS_REGS);
      } else {
	CleanSIndex(ClauseCodeToStaticIndex(pp->cs.p_code.TrueCodeOfPred), TRUE PASS_REGS);
      } 
    } else if (flag & DynamicPredFlag) {
#ifdef	DEBUG_RESTORE2
      fprintf(stderr, "Correcting dynamic code\n");
#endif
      RestoreDynamicClause(ClauseCodeToDynamicClause(pp->cs.p_code.TrueCodeOfPred),pp PASS_REGS);
    }
  }
  /* we are pointing at ourselves */
}

/*
 * Restores all of the entries, for a particular atom, we only have problems
 * if we find code or data bases 
 */
static void 
RestoreEntries(PropEntry *pp, int int_key USES_REGS)
{
  while (!EndOfPAEntr(pp)) {
    switch(pp->KindOfPE) {
    case FunctorProperty:
      {
	FunctorEntry *fe = (FunctorEntry *)pp;
	Prop p0;
	fe->NextOfPE =
	  PropAdjust(fe->NextOfPE);
	fe->NameOfFE =
	  AtomAdjust(fe->NameOfFE);
	p0 = fe->PropsOfFE =
	  PropAdjust(fe->PropsOfFE);
	if (!EndOfPAEntr(p0)) {
	  /* at most one property */
	  CleanCode(RepPredProp(p0) PASS_REGS);
	  RepPredProp(p0)->NextOfPE =
	    PropAdjust(RepPredProp(p0)->NextOfPE);
	  p0 = RepPredProp(p0)->NextOfPE;
	}
      }
      break;
    case ValProperty:
      {
	ValEntry *ve = (ValEntry *)pp;
	Term      tv = ve->ValueOfVE;
	ve->NextOfPE =
	  PropAdjust(ve->NextOfPE);
	if (IsAtomTerm(tv))
	  ve->ValueOfVE = AtomTermAdjust(tv);
      }
      break;
    case HoldProperty:
      {
	HoldEntry *he = (HoldEntry *)pp;
	he->NextOfPE =
	  PropAdjust(he->NextOfPE);
      }
      break;
    case ArrayProperty:
      {
	ArrayEntry *ae = (ArrayEntry *)pp;
	ae->NextOfPE =
	  PropAdjust(ae->NextOfPE);
	if (ae->ArrayEArity < 0) {
	  /* static array entry */
	  StaticArrayEntry *sae = (StaticArrayEntry *)ae;
	  if (sae->NextAE)
	    sae->NextAE = PtoArraySAdjust(sae->NextAE);
	  restore_static_array(sae PASS_REGS);
	} else {
	  if (ae->NextAE)
	    ae->NextAE = PtoArrayEAdjust(ae->NextAE);
	  if (IsVarTerm(ae->ValueOfVE))
	    RESET_VARIABLE(&(ae->ValueOfVE));
	  else {
	    CELL *ptr = RepAppl(ae->ValueOfVE);
	    /* in fact it should just be a pointer to the global,
	       but we'll be conservative.
	       Notice that the variable should have been reset in restore_program mode.
	    */
	    if (IsOldGlobalPtr(ptr)) {
	      ae->ValueOfVE = AbsAppl(PtoGloAdjust(ptr));
	    } else if (IsOldCodeCellPtr(ptr)) {
	      ae->ValueOfVE = AbsAppl(PtoHeapCellAdjust(ptr));
	    } else if (IsOldLocalInTRPtr(ptr)) {
	      ae->ValueOfVE = AbsAppl(PtoLocAdjust(ptr));
	    } else if (IsOldTrailPtr(ptr)) {
	      ae->ValueOfVE = AbsAppl(CellPtoTRAdjust(ptr));
	    }
	  }
	}
      }
      break;
    case PEProp:
      {
	PredEntry *pe = (PredEntry *) pp;
	pe->NextOfPE =
	  PropAdjust(pe->NextOfPE);
	CleanCode(pe PASS_REGS);
      }
      break;
    case DBProperty:
    case CodeDBProperty:
#ifdef DEBUG_RESTORE2
      fprintf(stderr, "Correcting data base clause at %p\n", pp);
#endif
      {
	DBEntry *de = (DBEntry *) pp;
	de->NextOfPE =
	  PropAdjust(de->NextOfPE);
	RestoreDB(de PASS_REGS);
      }
      break;
    case BBProperty:
      {
	BlackBoardEntry *bb = (BlackBoardEntry *) pp;
	bb->NextOfPE =
	  PropAdjust(bb->NextOfPE);
	RestoreBB(bb, int_key PASS_REGS);
      }
      break;
    case GlobalProperty:
      {
	GlobalEntry *gb = (GlobalEntry *) pp;
	Term gbt = gb->global;

	gb->NextOfPE =
	  PropAdjust(gb->NextOfPE);
	gb->AtomOfGE =
	  AtomEntryAdjust(gb->AtomOfGE);
	if (gb->NextGE) {
	  gb->NextGE =
	    GlobalEntryAdjust(gb->NextGE);
	}
	if (IsVarTerm(gbt)) {
	  CELL *gbp = VarOfTerm(gbt);
	  if (IsOldGlobalPtr(gbp))
	    gbp = PtoGloAdjust(gbp);
	  else
	    gbp = CellPtoHeapAdjust(gbp);
	  gb->global = (CELL)gbp;
	} else if (IsPairTerm(gbt)) {
	  gb->global = AbsPair(PtoGloAdjust(RepPair(gbt)));
	} else if (IsApplTerm(gbt)) {
	  CELL *gbp = RepAppl(gbt);
	  if (IsOldGlobalPtr(gbp))
	    gbp = PtoGloAdjust(gbp);
	  else
	    gbp = CellPtoHeapAdjust(gbp);
	  gb->global = AbsAppl(gbp);
	} else if (IsAtomTerm(gbt)) {
	  gb->global = AtomTermAdjust(gbt);
	} /* numbers need no adjusting */
      }
      break;
    case OpProperty:
      {
	OpEntry *opp = (OpEntry *)pp;
	if (opp->NextOfPE) {
	  opp->NextOfPE =
	    PropAdjust(opp->NextOfPE);
	}
	opp->OpName =
	  AtomAdjust(opp->OpName);
	if (opp->OpModule) {
	 opp->OpModule = AtomTermAdjust(opp->OpModule);
	}
	if (opp->OpNext) {
	 opp->OpNext = OpEntryAdjust(opp->OpNext);
	}
      }
      break;
    case ModProperty:
      {
	ModEntry *me = (ModEntry *)pp;
	if (me->NextOfPE) {
	  me->NextOfPE =
	    PropAdjust(me->NextOfPE);
	}
	if (me->PredForME) {
	  me->PredForME =
	  PtoPredAdjust(me->PredForME);
	}
	me->AtomOfME =
	  AtomAdjust(me->AtomOfME);
	if (me->NextME)
	  me->NextME = (struct mod_entry *)
	    AddrAdjust((ADDR)me->NextME);
      }
      break;      
    case ExpProperty:
      pp->NextOfPE =
	PropAdjust(pp->NextOfPE);
      break;
    case WideAtomProperty:
      pp->NextOfPE =
	PropAdjust(pp->NextOfPE);
      break;
    case BlobProperty:
      pp->NextOfPE =
	PropAdjust(pp->NextOfPE);
      {
	BlobPropEntry *bpe = (BlobPropEntry *)pp;
	bpe->blob_t =
	  BlobTypeAdjust(bpe->blob_t);
      }
      break;
    default:
      /* OOPS */
      Yap_Error(SYSTEM_ERROR, TermNil,
	    "Invalid Atom Property %d at %p", pp->KindOfPE, pp);
      return;
    }
    pp = RepProp(pp->NextOfPE);
  }
}

static void
RestoreAtom(AtomEntry *at USES_REGS)
{
  AtomEntry *nat;

  /* this should be done before testing for wide atoms */
  at->PropsOfAE = PropAdjust(at->PropsOfAE);
#if DEBUG_RESTORE2			/* useful during debug */
  if (IsWideAtom(AbsAtom(at)))
    fprintf(errout, "Restoring %S\n", at->WStrOfAE);
  else
    fprintf(errout, "Restoring %s\n", at->StrOfAE);
#endif
  RestoreEntries(RepProp(at->PropsOfAE), FALSE PASS_REGS);
  /* cannot use AtomAdjust without breaking agc */
  nat = RepAtom(at->NextOfAE);
  if (nat)
    at->NextOfAE = AbsAtom(AtomEntryAdjust(nat));
}

