1850 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1850 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*************************************************************************
 | |
| *									 *
 | |
| *	 YAP Prolog 							 *
 | |
| *									 *
 | |
| *	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
 | |
| *									 *
 | |
| * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
 | |
| *									 *
 | |
| **************************************************************************
 | |
| *									 *
 | |
| * File:		save.c							 *
 | |
| * Last rev:								 *
 | |
| * mods:									 *
 | |
| * comments:	saving and restoring a Prolog computation		 *
 | |
| *									 *
 | |
| *************************************************************************/
 | |
| #ifdef SCCS
 | |
| static char     SccsId[] = "@(#)save.c	1.3 3/15/90";
 | |
| #endif
 | |
| 
 | |
| #include "SWI-Stream.h"
 | |
| #if _MSC_VER || defined(__MINGW32__)
 | |
| #include <windows.h>
 | |
| #include <psapi.h>
 | |
| #endif
 | |
| #include "absmi.h"
 | |
| #include "alloc.h"
 | |
| #if USE_DL_MALLOC
 | |
| #include "dlmalloc.h"
 | |
| #endif
 | |
| #include "yapio.h"
 | |
| #include "sshift.h"
 | |
| #include "Foreign.h"
 | |
| #if HAVE_STRING_H
 | |
| #include <string.h>
 | |
| #endif
 | |
| #if !HAVE_STRNCAT
 | |
| #define strncat(X,Y,Z) strcat(X,Y)
 | |
| #endif
 | |
| #if !HAVE_STRNCPY
 | |
| #define strncpy(X,Y,Z) strcpy(X,Y)
 | |
| #endif
 | |
| 
 | |
| #if HAVE_FCNTL_H
 | |
| #include <fcntl.h>
 | |
| #endif
 | |
| #ifdef HAVE_UNISTD_H
 | |
| #include <unistd.h>
 | |
| #endif
 | |
| #ifdef HAVE_SYS_TYPES_H
 | |
| #include <sys/types.h>
 | |
| #endif
 | |
| #ifdef HAVE_SYS_STAT_H
 | |
| #include <sys/stat.h>
 | |
| #endif
 | |
| #include "iopreds.h"
 | |
| 
 | |
| /*********  hack for accesing several kinds of terms. Should be cleaned **/
 | |
| 
 | |
| static char StartUpFile[] = "startup.yss";
 | |
| 
 | |
| static char end_msg[256] ="*** End of YAP saved state *****";
 | |
| 
 | |
| /* SWI IO, must be restarted after restore */
 | |
| void initIO(void);
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 
 | |
| /*
 | |
|  * 
 | |
|  #FOR DEBUGGING define DEBUG_RESTORE0 to check the file stuff,
 | |
|  #define DEBUG_RESTORE1 to see if it is able to prepare the chain,
 | |
|  #define DEBUG_RESTORE2 to see how things are going,
 | |
|  #define DEBUG_RESTORE3 to check if the atom chain is still a working chain,
 | |
|  * define DEBUG_RESTORE4 if you want to set the output for some
 | |
|  * particular file,
 | |
|  * define DEBUG_RESTORE5 if you want to see how the stacks are being
 | |
|  * cleaned up,
 | |
|  * define DEBUG_RESTORE6 if you want to follow the execution in 
 | |
|  *
 | |
|  * Also a file is defined where you can write things, by default stderr 
 | |
|  *
 | |
|  * Good Luck 
 | |
|  */
 | |
| 
 | |
| #endif
 | |
| 
 | |
| STATIC_PROTO(int   myread, (int, char *, Int));
 | |
| STATIC_PROTO(Int   mywrite, (int, char *, Int));
 | |
| STATIC_PROTO(int   open_file, (char *, int));
 | |
| STATIC_PROTO(int   close_file, (void));
 | |
| STATIC_PROTO(Int   putout, (CELL));
 | |
| STATIC_PROTO(Int   putcellptr, (CELL *));
 | |
| STATIC_PROTO(CELL  get_cell, (void));
 | |
| STATIC_PROTO(CELL  *get_cellptr, ( /* CELL * */ void));
 | |
| STATIC_PROTO(int   put_info, (int, int CACHE_TYPE));
 | |
| STATIC_PROTO(int   save_regs, (int CACHE_TYPE));
 | |
| STATIC_PROTO(int   save_code_info, (void));
 | |
| STATIC_PROTO(int   save_heap, (void));
 | |
| STATIC_PROTO(int   save_stacks, (int CACHE_TYPE));
 | |
| STATIC_PROTO(int   save_crc, (void));
 | |
| STATIC_PROTO(Int   do_save, (int CACHE_TYPE));
 | |
| STATIC_PROTO(Int   p_save2, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(Int   p_save_program, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(int   check_header, (CELL *, CELL *, CELL *, CELL * CACHE_TYPE));
 | |
| STATIC_PROTO(int   get_heap_info, (CACHE_TYPE1));
 | |
| STATIC_PROTO(int   get_regs, (int CACHE_TYPE));
 | |
| STATIC_PROTO(int   get_insts, (OPCODE []));
 | |
| STATIC_PROTO(int   get_hash, (void));
 | |
| STATIC_PROTO(int   CopyCode, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(int   CopyStacks, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(int   get_coded, (int, OPCODE [] CACHE_TYPE));
 | |
| STATIC_PROTO(void  restore_codes, (void));
 | |
| STATIC_PROTO(void  RestoreDB, (DBEntry * CACHE_TYPE));
 | |
| STATIC_PROTO(void  RestoreDBTerm, (DBTerm *, int CACHE_TYPE));
 | |
| STATIC_PROTO(void  CleanClauses, (yamop *, yamop *,PredEntry * CACHE_TYPE));
 | |
| STATIC_PROTO(void  rehash, (CELL *, int, int CACHE_TYPE));
 | |
| STATIC_PROTO(void  CleanCode, (PredEntry * CACHE_TYPE));
 | |
| STATIC_PROTO(void  RestoreEntries, (PropEntry *, int CACHE_TYPE));
 | |
| STATIC_PROTO(void  RestoreFreeSpace, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(void  restore_heap, (void));
 | |
| #ifdef DEBUG_RESTORE3
 | |
| STATIC_PROTO(void  ShowAtoms, (void));
 | |
| STATIC_PROTO(void  ShowEntries, (PropEntry *));
 | |
| #endif
 | |
| STATIC_PROTO(int   OpenRestore, (char *, char *, CELL *, CELL *, CELL *, CELL *, IOSTREAM **));
 | |
| STATIC_PROTO(void  CloseRestore, (void));
 | |
| #ifndef _WIN32
 | |
| STATIC_PROTO(int  check_opcodes, (OPCODE []));
 | |
| #endif
 | |
| STATIC_PROTO(void  RestoreHeap, (OPCODE [] CACHE_TYPE));
 | |
| STATIC_PROTO(Int  p_restore, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(void  restore_heap_regs, ( CACHE_TYPE1 ));
 | |
| STATIC_PROTO(void  restore_regs, (int CACHE_TYPE));
 | |
| #ifdef MACYAP
 | |
| STATIC_PROTO(void NewFileInfo, (long, long));
 | |
| extern int      DefVol;
 | |
| #endif
 | |
| 
 | |
| #ifdef _WIN32
 | |
| #if HAVE_IO_H
 | |
| #include <io.h>
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #ifdef LIGHT
 | |
| 
 | |
| #include <unix.h>
 | |
| #include <strings.h>
 | |
| 
 | |
| void 
 | |
| LightBug(char *);
 | |
| 
 | |
| static void 
 | |
| LightBug(s)
 | |
| 	char           *s;
 | |
| {
 | |
| }
 | |
| 
 | |
| #endif				/* LIGHT */
 | |
| 
 | |
| static Int
 | |
| do_system_error(yap_error_number etype, const char *msg)
 | |
| {
 | |
|   CACHE_REGS
 | |
| #if HAVE_SNPRINTF
 | |
| #if HAVE_STRERROR
 | |
|   snprintf(LOCAL_ErrorSay,MAX_ERROR_MSG_SIZE,"%s (%s when reading %s)", msg, strerror(errno), LOCAL_FileNameBuf);
 | |
| #else
 | |
|   snprintf(LOCAL_ErrorSay,MAX_ERROR_MSG_SIZE,"%s, (system error %d when reading %s)",msg,errno,LOCAL_FileNameBuf);  
 | |
| #endif
 | |
| #else
 | |
| #if HAVE_STRERROR
 | |
|   sprintf(LOCAL_ErrorSay,"%s, (%s when reading %s)",msg,strerror(errno),LOCAL_FileNameBuf);
 | |
| #else
 | |
|   sprintf(LOCAL_ErrorSay,"%s, (system error %d when reading %s)",msg,errno,LOCAL_FileNameBuf);  
 | |
| #endif
 | |
| #endif
 | |
|   LOCAL_ErrorMessage = LOCAL_ErrorSay;
 | |
|   LOCAL_Error_TYPE = etype;
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| inline static
 | |
| int myread(int fd, char *buffer, Int len) {
 | |
|   ssize_t nread;
 | |
| 
 | |
|   while (len > 0) {
 | |
|     nread = read(fd, buffer,  (int)len);
 | |
|     if (nread < 1) {
 | |
|       return do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"bad read on saved state");
 | |
|     }
 | |
|     buffer += nread;
 | |
|     len -= nread;
 | |
|   }
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| inline static
 | |
| Int
 | |
| mywrite(int fd, char *buff, Int len) {
 | |
|   ssize_t nwritten;
 | |
| 
 | |
|   while (len > 0) {
 | |
|     nwritten = write(fd, buff, (size_t)len);
 | |
|     if (nwritten < 0) {
 | |
|       return do_system_error(SYSTEM_ERROR,"bad write on saved state");
 | |
|     }
 | |
|     buff += nwritten;
 | |
|     len -= nwritten;
 | |
|   }
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| #define FullSaved		1
 | |
| 
 | |
| /* Where the code was before */
 | |
| 
 | |
| 
 | |
| 
 | |
| typedef CELL   *CELLPOINTER;
 | |
| 
 | |
| static int      splfild = 0;
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 
 | |
| #ifdef DEBUG_RESTORE4
 | |
| static FILE    *errout;
 | |
| #else
 | |
| #define errout GLOBAL_stderr
 | |
| #endif
 | |
| 
 | |
| #endif				/* DEBUG */
 | |
| 
 | |
| static Int      OldHeapUsed;
 | |
| 
 | |
| static CELL     which_save;
 | |
| 
 | |
| /* Open a file to read or to write */
 | |
| static int 
 | |
| open_file(char *my_file, int flag)
 | |
| {
 | |
|   int splfild;
 | |
| 
 | |
| #ifdef M_WILLIAMS
 | |
|   if (flag & O_CREAT)
 | |
|     splfild = creat(my_file, flag);
 | |
|   else
 | |
|     splfild = open(my_file, flag);
 | |
|   if (splfild < 0) {
 | |
| #else
 | |
| #ifdef O_BINARY
 | |
| #if _MSC_VER
 | |
|     if ((splfild = _open(my_file, flag | O_BINARY), _S_IREAD | _S_IWRITE) < 0)
 | |
| #else
 | |
|     if ((splfild = open(my_file, flag | O_BINARY, 0775)) < 0)
 | |
| #endif
 | |
| #else  /* O_BINARY */
 | |
|     if ((splfild = open(my_file, flag, 0755)) < 0)
 | |
| #endif  /* O_BINARY */
 | |
| #endif 	/* M_WILLIAMS */
 | |
|       {
 | |
| 	splfild = 0;	/* We do not have an open file */
 | |
| 	return -1;
 | |
|       }
 | |
| #ifdef undf0
 | |
|       fprintf(errout, "Opened file %s\n", my_file);
 | |
| #endif
 | |
|       return splfild;
 | |
| }
 | |
| 
 | |
| static int 
 | |
| close_file(void)
 | |
| {
 | |
|   if (splfild == 0)
 | |
|     return 0;
 | |
|   if (close(splfild) < 0)
 | |
|     return do_system_error(SYSTEM_ERROR,"bad close on saved state");
 | |
|   splfild = 0;
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* stores a cell in a file */
 | |
| static Int 
 | |
| putout(CELL l)
 | |
| {
 | |
|   return mywrite(splfild, (char *) &l, sizeof(CELL));
 | |
| }
 | |
| 
 | |
| /* stores a pointer to a cell in a file */
 | |
| static Int 
 | |
| putcellptr(CELL *l)
 | |
| {
 | |
|   return mywrite(splfild, (char *) &l, sizeof(CELLPOINTER));
 | |
| }
 | |
| 
 | |
| /* gets a cell from a file */
 | |
| static CELL 
 | |
| get_cell(void)
 | |
| {
 | |
|   CELL            l;
 | |
|   myread(splfild, (char *) &l, Unsigned(sizeof(CELL)));
 | |
|   return (l);
 | |
| }
 | |
| 
 | |
| /* gets a cell from a file */
 | |
| static CELL 
 | |
| get_header_cell(void)
 | |
| {
 | |
|   CELL l;
 | |
|   int count = 0, n;
 | |
|   while (count < sizeof(CELL)) {
 | |
|     if ((n = read(splfild, &l, sizeof(CELL)-count)) < 0) {
 | |
|       do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"failed to read saved state header");
 | |
|       return 0L;
 | |
|     }
 | |
|     count += n;
 | |
|   }
 | |
|   return l;
 | |
| }
 | |
| 
 | |
| /* gets a pointer to cell from a file */
 | |
| static CELL    *
 | |
| get_cellptr(void)
 | |
| {
 | |
|   CELL           *l;
 | |
| 
 | |
|   if (myread(splfild, (char *) &l, Unsigned(sizeof(CELLPOINTER))) < 0)
 | |
|     return NULL;
 | |
|   return (l);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * writes the header (at the moment YAPV*), info about what kind of saved
 | |
|  * set, the work size, and the space ocuppied 
 | |
|  */
 | |
| static int 
 | |
| put_info(int info, int mode USES_REGS)
 | |
| {
 | |
|   char     msg[256];
 | |
| 
 | |
|   sprintf(msg, "#!/bin/sh\nexec_dir=${YAPBINDIR:-%s}\nexec $exec_dir/yap $0 \"$@\"\n%cYAP-%s", YAP_BINDIR, 1, YAP_SVERSION);
 | |
|   if (mywrite(splfild, msg, strlen(msg) + 1))
 | |
|     return -1;
 | |
|   if (putout(Unsigned(info)) < 0)
 | |
|     return -1;
 | |
|   /* say whether we just saved the heap or everything */
 | |
|   if (putout(mode) < 0)
 | |
|     return -1;
 | |
|   /* current state of stacks, to be used by SavedInfo */
 | |
|   /* space available in heap area */
 | |
|   if (putout(Unsigned(LOCAL_GlobalBase)-Unsigned(Yap_HeapBase)) < 0)
 | |
|     return -1;
 | |
|   /* space available for stacks */
 | |
|   if (putout(Unsigned(LOCAL_LocalBase)-Unsigned(LOCAL_GlobalBase)) < 0)
 | |
|     return -1;
 | |
|   /* space available for trail */
 | |
|   if (putout(Unsigned(LOCAL_TrailTop)-Unsigned(LOCAL_TrailBase)) < 0)
 | |
|     return -1;
 | |
|   /* Space used in heap area */
 | |
|   if (putout(Unsigned(HeapTop)-Unsigned(Yap_HeapBase)) < 0)
 | |
|     return -1;
 | |
|   /* Space used for local stack */
 | |
|   if (putout(Unsigned(LCL0)-Unsigned(ASP)) < 0)
 | |
|     return -1;
 | |
|   /* Space used for global stack */
 | |
|   if (putout(Unsigned(H) - Unsigned(LOCAL_GlobalBase)) < 0)
 | |
|     return -1;
 | |
|   /* Space used for trail */
 | |
|   if (putout(Unsigned(TR) - Unsigned(LOCAL_TrailBase)) < 0)
 | |
|     return -1;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| save_regs(int mode USES_REGS)
 | |
| {
 | |
|   /* save all registers */
 | |
|   if (putout((CELL)compile_arrays) < 0)
 | |
|     return -1;    
 | |
|   if (mode == DO_EVERYTHING) {
 | |
|     if (putcellptr((CELL *)CP) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(ENV) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(ASP) < 0)
 | |
|       return -1;
 | |
|     /* if (putout((CELL)N) < 0)
 | |
|        return -1; */
 | |
|     if (putcellptr(H0) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(LCL0) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(H) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(HB) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr((CELL *)B) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr((CELL *)TR) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(YENV) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr(S) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr((CELL *)P) < 0)
 | |
|       return -1;
 | |
|     if (putout(CreepFlag) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr((CELL *)EX) < 0)
 | |
|       return -1;
 | |
| #if defined(YAPOR_SBA) || defined(TABLING)
 | |
|     if (putcellptr(H_FZ) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr((CELL *)B_FZ) < 0)
 | |
|       return -1;
 | |
|     if (putcellptr((CELL *)TR_FZ) < 0)
 | |
|       return -1;
 | |
| #endif /* YAPOR_SBA || TABLING */
 | |
|   }
 | |
|   if (putout(CurrentModule) < 0)
 | |
|     return -1;
 | |
|   if (mode == DO_EVERYTHING) {
 | |
| #ifdef COROUTINING
 | |
|     if (putout(LOCAL_WokenGoals) < 0)
 | |
|       return -1;
 | |
| #endif
 | |
| #ifdef  DEPTH_LIMIT
 | |
|     if (putout(DEPTH) < 0)
 | |
|       return -1;
 | |
| #endif
 | |
|     if (putout(LOCAL_GcGeneration) < 0)
 | |
|       return -1;
 | |
|     if (putout(LOCAL_GcPhase) < 0)
 | |
|       return -1;
 | |
|     if (putout(LOCAL_GcCurrentPhase) < 0)
 | |
|       return -1;
 | |
|   }
 | |
|   /* The operand base */
 | |
|   if (putcellptr(CellPtr(XREGS)) < 0)
 | |
|     return -1;
 | |
|   if (putout(which_save) < 0)
 | |
|     return -1;
 | |
|   /* Now start by saving the code */
 | |
|   /* the heap boundaries */
 | |
|   if (putcellptr(CellPtr(Yap_HeapBase)) < 0)
 | |
|     return -1;
 | |
|   if (putcellptr(CellPtr(HeapTop)) < 0)
 | |
|     return -1;
 | |
|   /* and the space it ocuppies */
 | |
|   if (putout(Unsigned(Yap_heap_regs->heap_used)) < 0)
 | |
|     return -1;
 | |
|   /* Then the start of the free code */
 | |
|   if (putcellptr(CellPtr(FreeBlocks)) < 0)
 | |
|     return -1;
 | |
|   if (putcellptr(CellPtr(AuxBase)) < 0)
 | |
|     return -1;
 | |
|   if (putcellptr(AuxSp) < 0)
 | |
|     return -1;
 | |
|   if (putcellptr(CellPtr(AuxTop)) < 0)
 | |
|     return -1;
 | |
|   if (putcellptr(CellPtr(LOCAL_ScratchPad.ptr)) < 0)
 | |
|     return -1;
 | |
|   if (putout(LOCAL_ScratchPad.sz) < 0)
 | |
|     return -1;
 | |
|   if (putout(LOCAL_ScratchPad.msz) < 0)
 | |
|     return -1;
 | |
|   if (mode == DO_EVERYTHING) {
 | |
|     /* put the old trail base, just in case it moves again */
 | |
|     if (putout(ARG1) < 0)
 | |
|       return -1;
 | |
|     if (which_save == 2) {
 | |
|       if (putout(ARG2) < 0)
 | |
| 	return -1;
 | |
|     }
 | |
|     if (putcellptr(CellPtr(LOCAL_TrailBase)) < 0)
 | |
|       return -1;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| save_code_info(void)
 | |
| {
 | |
| 
 | |
|   /* First the instructions */
 | |
|   {
 | |
|     op_numbers i;
 | |
| 
 | |
|     OPCODE my_ops[_std_top+1];
 | |
|     for (i = _Ystop; i <= _std_top; ++i)
 | |
|       my_ops[i] = Yap_opcode(i);
 | |
|     if (mywrite(splfild, (char *)my_ops, sizeof(OPCODE)*(_std_top+1)) < 0)
 | |
|       return -1;
 | |
|   }
 | |
|   /* and the current character codes */
 | |
|   if (mywrite(splfild, Yap_chtype, NUMBER_OF_CHARS) < 0)
 | |
|     return -1;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| save_heap(void)
 | |
| {
 | |
| #ifdef USE_SYSTEM_MALLOC
 | |
|   return -1;
 | |
| #endif
 | |
|   int j;
 | |
|   /* Then save the whole heap */
 | |
|   Yap_ResetConsultStack();
 | |
|   j = Unsigned(HeapTop) - Unsigned(Yap_HeapBase);
 | |
|   /* store 10 more cells because of the memory manager */
 | |
|   if (mywrite(splfild, (char *) Yap_HeapBase, j) < 0)
 | |
|     return -1;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| save_stacks(int mode USES_REGS)
 | |
| {
 | |
|   int j;
 | |
|   
 | |
|   switch (mode) {
 | |
|   case DO_EVERYTHING:
 | |
|     /* Now, go and save the state */
 | |
|     /* Save the local stack */
 | |
|     j = Unsigned(LCL0) - Unsigned(ASP);
 | |
|     if (mywrite(splfild, (char *) ASP, j) < 0)
 | |
|       return -1;
 | |
|     /* Save the global stack */
 | |
|     j = Unsigned(H) - Unsigned(LOCAL_GlobalBase);
 | |
|     if (mywrite(splfild, (char *) LOCAL_GlobalBase, j) < 0)
 | |
|       return -1;
 | |
|     /* Save the trail */
 | |
|     j = Unsigned(TR) - Unsigned(LOCAL_TrailBase);
 | |
|     if (mywrite(splfild, (char *) LOCAL_TrailBase, j) < 0)
 | |
|       return -1;
 | |
|     break;
 | |
|   case DO_ONLY_CODE:
 | |
|     {
 | |
|       tr_fr_ptr tr_ptr = TR; 
 | |
|       while (tr_ptr != (tr_fr_ptr)LOCAL_TrailBase) {
 | |
| 	CELL val = TrailTerm(tr_ptr-1);
 | |
| 	if (IsVarTerm(val)) {
 | |
| 	  CELL *d1 = VarOfTerm(val);
 | |
| 	  if (d1 < (CELL *)HeapTop) {
 | |
| 	    if (putout(val) < 0)
 | |
| 	      return -1;
 | |
| 	  }
 | |
| 	} else if (IsPairTerm(val)) {
 | |
| 	  CELL *d1 = RepPair(val);
 | |
| 	  if (d1 < (CELL *)HeapTop) {
 | |
| 	    if (putout(val) < 0)
 | |
| 	      return -1;
 | |
| 	  }
 | |
| 	}
 | |
| 	tr_ptr--;
 | |
|       }
 | |
|     }
 | |
|     if (putcellptr(NULL) < 0)
 | |
|       return -1;
 | |
|     break;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| save_crc(void)
 | |
| {
 | |
|   /* Save a CRC */
 | |
|   return mywrite(splfild, end_msg, 256);
 | |
| }
 | |
| 
 | |
| static Int
 | |
| do_save(int mode USES_REGS) {
 | |
|   extern void Scleanup(void);
 | |
|   Term t1 = Deref(ARG1);
 | |
| 
 | |
|   if (Yap_HoleSize) {
 | |
|     Yap_Error(SYSTEM_ERROR,MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf)),
 | |
| 	      "restore/1: address space has holes of size %ld, cannot save", (long int)Yap_HoleSize);
 | |
|     return FALSE;
 | |
|   }
 | |
|   if (!Yap_GetName(LOCAL_FileNameBuf, YAP_FILENAME_MAX, t1)) {
 | |
|     Yap_Error(TYPE_ERROR_LIST,t1,"save/1");
 | |
|     return FALSE;
 | |
|   }
 | |
|   Scleanup();
 | |
|   Yap_CloseStreams(TRUE);
 | |
|   if ((splfild = open_file(LOCAL_FileNameBuf, O_WRONLY | O_CREAT)) < 0) {
 | |
|     Yap_Error(SYSTEM_ERROR,MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf)),
 | |
| 	  "restore/1, open(%s)", strerror(errno));
 | |
|     return(FALSE);
 | |
|   }
 | |
|   if (put_info(FullSaved, mode PASS_REGS) < 0)
 | |
|     return -1;
 | |
|   if (save_regs(mode PASS_REGS) < 0)
 | |
|     return -1;
 | |
|   if (save_code_info() < 0)
 | |
|     return -1;
 | |
|   if (save_heap() < 0)
 | |
|     return -1;
 | |
|   if (save_stacks(mode PASS_REGS) < 0)
 | |
|     return -1;
 | |
|   if (save_crc() < 0)
 | |
|     return -1;
 | |
|   close_file();
 | |
|   return (TRUE);
 | |
| }
 | |
| 
 | |
| /* Saves a complete prolog environment */
 | |
| static Int 
 | |
| p_save2( USES_REGS1 )
 | |
| {
 | |
|   Int res;
 | |
| 
 | |
|   Term t;
 | |
| #ifdef YAPOR
 | |
|   if (GLOBAL_number_workers != 1) {
 | |
|     Yap_Error(SYSTEM_ERROR,TermNil,
 | |
| 	       "cannot perform save: more than a worker/thread running");
 | |
|     return(FALSE);
 | |
|   }
 | |
| #endif /* YAPOR */
 | |
| #ifdef THREADS
 | |
|   if (GLOBAL_NOfThreads != 1) {
 | |
|     Yap_Error(SYSTEM_ERROR,TermNil,
 | |
| 	       "cannot perform save: more than a worker/thread running");
 | |
|     return(FALSE);
 | |
|   }
 | |
| #endif /* THREADS */
 | |
|   /* avoid double saves */
 | |
|   if (IsNonVarTerm(t = Deref(ARG2)))
 | |
|     return TRUE;
 | |
|   if (!Yap_unify(ARG2,MkIntTerm(1)))
 | |
|     return FALSE;
 | |
|   which_save = 2;
 | |
|   Yap_StartSlots( PASS_REGS1 );
 | |
|   res = do_save(DO_EVERYTHING PASS_REGS);
 | |
|   Yap_CloseSlots( PASS_REGS1 );
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /* Just save the program, not the stacks */
 | |
| static Int 
 | |
| p_save_program( USES_REGS1 )
 | |
| {
 | |
|   which_save = 0;
 | |
|   return do_save(DO_ONLY_CODE PASS_REGS);
 | |
| }
 | |
| 
 | |
| /* Now, to restore the saved code */
 | |
| 
 | |
| /* First check out if we are dealing with a valid file */
 | |
| static int 
 | |
| check_header(CELL *info, CELL *ATrail, CELL *AStack, CELL *AHeap USES_REGS)
 | |
| {
 | |
|   char pp[256];
 | |
|   char msg[256];
 | |
|   CELL hp_size, gb_size, lc_size, tr_size, mode;
 | |
|   int n;
 | |
| 
 | |
|   /* make sure we always check if there are enough bytes */
 | |
|   /* skip the first line */
 | |
|   pp[0] = '\0';
 | |
|   do {
 | |
|     if ((n = read(splfild, pp, 1)) <= 0) {
 | |
|       do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"failed to scan first line from saved state");
 | |
|       return FAIL_RESTORE;
 | |
|     }
 | |
|   } while (pp[0] != 1);
 | |
|   /* now check the version */
 | |
|   sprintf(msg, "YAP-%s", YAP_SVERSION);
 | |
|   {
 | |
|     int count = 0, n, to_read = Unsigned(strlen(msg) + 1);
 | |
|     while (count < to_read) {
 | |
|       if ((n = read(splfild, pp, to_read-count)) <= 0) {
 | |
| 	do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"failed to scan version info from saved state");
 | |
| 	return FAIL_RESTORE;
 | |
|       }
 | |
|       count += n;
 | |
|     }
 | |
|   }
 | |
|   if (strcmp(pp, msg) != 0) {
 | |
|     LOCAL_ErrorMessage = LOCAL_ErrorSay;
 | |
|     strncpy(LOCAL_ErrorMessage, "saved state ", MAX_ERROR_MSG_SIZE);
 | |
|     strncat(LOCAL_ErrorMessage, LOCAL_FileNameBuf, MAX_ERROR_MSG_SIZE);
 | |
|     strncat(LOCAL_ErrorMessage, " failed to match version ID", MAX_ERROR_MSG_SIZE);
 | |
|     LOCAL_Error_TYPE = CONSISTENCY_ERROR;
 | |
|     return FAIL_RESTORE;
 | |
|   }
 | |
|   /* check info on header */
 | |
|   /* ignore info on saved state */
 | |
|   *info = get_header_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|      return FAIL_RESTORE;
 | |
|   /* check the restore mode */
 | |
|   mode = get_header_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|      return FAIL_RESTORE;
 | |
|   if (mode != DO_EVERYTHING && mode != DO_ONLY_CODE) {
 | |
|     return FAIL_RESTORE;
 | |
|   }
 | |
|   /* ignore info on stacks size */
 | |
|   *AHeap = get_header_cell();
 | |
|   if (LOCAL_ErrorMessage) {
 | |
|      return FAIL_RESTORE;
 | |
|   }
 | |
|   *AStack = get_header_cell();
 | |
|   if (LOCAL_ErrorMessage) {
 | |
|      return FAIL_RESTORE;
 | |
|   }
 | |
|   *ATrail = get_header_cell();
 | |
|   if (LOCAL_ErrorMessage) {
 | |
|      return FAIL_RESTORE;
 | |
|   }
 | |
|   /* now, check whether we got enough enough space to load the
 | |
|      saved space */
 | |
|   hp_size = get_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|      return FAIL_RESTORE;
 | |
|   while (Yap_HeapBase != NULL &&
 | |
| 	 hp_size > Unsigned(HeapLim) - Unsigned(Yap_HeapBase)) {
 | |
|     if(!Yap_growheap(FALSE, hp_size, NULL)) {
 | |
|       return FAIL_RESTORE;
 | |
|     }
 | |
|   }
 | |
|   if (mode == DO_EVERYTHING) {
 | |
|     lc_size = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return FAIL_RESTORE;
 | |
|     gb_size=get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return FAIL_RESTORE;
 | |
|     if (Yap_HeapBase != NULL && lc_size+gb_size > Unsigned(LOCAL_LocalBase) - Unsigned(LOCAL_GlobalBase)) {
 | |
|       if (LOCAL_ErrorMessage != NULL)
 | |
| 	LOCAL_ErrorMessage = "could not allocate enough stack space";
 | |
|       return FAIL_RESTORE;
 | |
|     }
 | |
|     if (Yap_HeapBase != NULL && (tr_size = get_cell()) > Unsigned(LOCAL_TrailTop) - Unsigned(LOCAL_TrailBase)) {
 | |
|       if (LOCAL_ErrorMessage != NULL)
 | |
| 	LOCAL_ErrorMessage = "could not allocate enough trail space";
 | |
|       return FAIL_RESTORE;
 | |
|     }
 | |
|   } else {
 | |
|     /* skip cell size */
 | |
|     get_header_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return FAIL_RESTORE;
 | |
|     get_header_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return FAIL_RESTORE;
 | |
|     get_header_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return FAIL_RESTORE;
 | |
|   }
 | |
|   return(mode);
 | |
| }
 | |
| 
 | |
| /* Gets the state of the heap, and evaluates the related variables */
 | |
| static int 
 | |
| get_heap_info(USES_REGS1)
 | |
| {
 | |
|   LOCAL_OldHeapBase = (ADDR) get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   LOCAL_OldHeapTop = (ADDR) get_cellptr();
 | |
| 
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   OldHeapUsed = (Int) get_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   FreeBlocks = (BlockHeader *) get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   AuxBase = (ADDR)get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   AuxSp = get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   AuxTop = (ADDR)get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   LOCAL_ScratchPad.ptr = (ADDR)get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   LOCAL_ScratchPad.sz = get_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   LOCAL_ScratchPad.msz = get_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   LOCAL_HDiff = Unsigned(Yap_HeapBase) - Unsigned(LOCAL_OldHeapBase);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Gets the register array */
 | |
| /* Saves the old bases for the work areas */
 | |
| /* and evaluates the difference from the old areas to the new ones */
 | |
| static int 
 | |
| get_regs(int flag USES_REGS)
 | |
| {
 | |
|   CELL           *NewGlobalBase = (CELL *)LOCAL_GlobalBase;
 | |
|   CELL           *NewLCL0 = LCL0;
 | |
|   CELL           *OldXREGS;
 | |
| 
 | |
|   /* Get regs */
 | |
|   compile_arrays = (int)get_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   if (flag == DO_EVERYTHING) {
 | |
|     CP = (yamop *)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     ENV = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     ASP = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     /* N = get_cell(); */
 | |
|     H0 = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     LCL0 = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     H = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     HB = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     B = (choiceptr)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     TR = (tr_fr_ptr)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     YENV = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     S = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     P = (yamop *)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     CreepFlag = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     EX = (struct DB_TERM *)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
| #if defined(YAPOR_SBA) || defined(TABLING)
 | |
|     H_FZ = get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     B_FZ = (choiceptr)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     TR_FZ = (tr_fr_ptr)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
| #endif /* YAPOR_SBA || TABLING */
 | |
|   }
 | |
|   CurrentModule = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   if (flag == DO_EVERYTHING) {
 | |
| #ifdef COROUTINING
 | |
|     LOCAL_WokenGoals = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
| #endif
 | |
| #ifdef  DEPTH_LIMIT
 | |
|     DEPTH = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
| #endif
 | |
|     LOCAL_GcGeneration = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     LOCAL_GcPhase = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     LOCAL_GcCurrentPhase = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   }
 | |
|   /* Get the old bases */
 | |
|   OldXREGS = get_cellptr();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|     return -1;
 | |
|   which_save = get_cell();
 | |
|   if (LOCAL_ErrorMessage)
 | |
|     return -1;
 | |
|   LOCAL_XDiff =  (CELL)XREGS - (CELL)OldXREGS;
 | |
|   if (LOCAL_ErrorMessage)
 | |
|     return -1;
 | |
|   if (get_heap_info( PASS_REGS1 ) < 0)
 | |
|     return -1;
 | |
|   if (flag == DO_EVERYTHING) {
 | |
|     ARG1 = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     if (which_save == 2) {
 | |
|       ARG2 = get_cell();
 | |
|       if (LOCAL_ErrorMessage)
 | |
| 	return -1;
 | |
|     }
 | |
|     /* get old trail base */
 | |
|     LOCAL_OldTrailBase = (ADDR)get_cellptr();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|     /* Save the old register where we can easily access them */
 | |
|     LOCAL_OldASP = ASP;
 | |
|     LOCAL_OldLCL0 = LCL0;
 | |
|     LOCAL_OldGlobalBase = (CELL *)LOCAL_GlobalBase;
 | |
|     LOCAL_OldH = H;
 | |
|     LOCAL_OldTR = TR;
 | |
|     LOCAL_GDiff = Unsigned(NewGlobalBase) - Unsigned(LOCAL_GlobalBase);
 | |
|     LOCAL_GDiff0 = 0;
 | |
|     LOCAL_LDiff = Unsigned(NewLCL0) - Unsigned(LCL0);
 | |
|     LOCAL_TrDiff = LOCAL_LDiff;
 | |
|     LOCAL_GlobalBase = (ADDR)NewGlobalBase;
 | |
|     LCL0 = NewLCL0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Get the old opcodes and place them in a hash table */
 | |
| static int 
 | |
| get_insts(OPCODE old_ops[])
 | |
| {
 | |
|   return myread(splfild, (char *)old_ops, sizeof(OPCODE)*(_std_top+1));
 | |
| }
 | |
| 
 | |
| /* Get the old atoms hash table */
 | |
| static int 
 | |
| get_hash(void)
 | |
| {
 | |
|   return myread(splfild, Yap_chtype , NUMBER_OF_CHARS);
 | |
| }
 | |
| 
 | |
| /* Copy all of the old code to the new Heap */
 | |
| static int 
 | |
| CopyCode( USES_REGS1 )
 | |
| {
 | |
|   if (myread(splfild, (char *) Yap_HeapBase, (Unsigned(LOCAL_OldHeapTop) - Unsigned(LOCAL_OldHeapBase))) < 0) {
 | |
|     return -1;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Copy the local and global stack and also the trail to their new home */
 | |
| /* In REGS we still have nonadjusted values !! */
 | |
| static int 
 | |
| CopyStacks( USES_REGS1 )
 | |
| {
 | |
|   Int             j;
 | |
|   char           *NewASP;
 | |
| 
 | |
|   j = Unsigned(LOCAL_OldLCL0) - Unsigned(ASP);
 | |
|   NewASP = (char *) (Unsigned(ASP) + (Unsigned(LCL0) - Unsigned(LOCAL_OldLCL0)));
 | |
|   if (myread(splfild, (char *) NewASP, j) < 0)
 | |
|     return -1;
 | |
|   j = Unsigned(H) - Unsigned(LOCAL_OldGlobalBase);
 | |
|   if (myread(splfild, (char *) LOCAL_GlobalBase, j) < 0)
 | |
|     return -1;
 | |
|   j = Unsigned(TR) - Unsigned(LOCAL_OldTrailBase);
 | |
|   if (myread(splfild, LOCAL_TrailBase, j))
 | |
|     return -1;
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Copy the local and global stack and also the trail to their new home */
 | |
| /* In REGS we still have nonadjusted values !! */
 | |
| static int
 | |
| CopyTrailEntries( USES_REGS1 )
 | |
| {
 | |
|   CELL           entry, *Entries;
 | |
| 
 | |
|   Entries = (CELL *)LOCAL_TrailBase;
 | |
|   do {
 | |
|     *Entries++ = entry = get_cell();
 | |
|     if (LOCAL_ErrorMessage)
 | |
|       return -1;
 | |
|   } while ((CODEADDR)entry != NULL);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* get things which are saved in the file */
 | |
| static int 
 | |
| get_coded(int flag, OPCODE old_ops[] USES_REGS)
 | |
| {
 | |
|   char my_end_msg[256];
 | |
|   
 | |
|   if (get_regs(flag PASS_REGS) < 0)
 | |
|     return -1;
 | |
|   if (get_insts(old_ops) < 0)
 | |
|     return -1;
 | |
|   if (get_hash() < 0)
 | |
|     return -1;
 | |
|   if (CopyCode( PASS_REGS1 ) < 0)
 | |
|     return -1;
 | |
|   switch (flag) {
 | |
|   case DO_EVERYTHING:
 | |
|     if (CopyStacks( PASS_REGS1 ) < 0)
 | |
|       return -1;
 | |
|     break;
 | |
|   case DO_ONLY_CODE:
 | |
|     if (CopyTrailEntries( PASS_REGS1 ) < 0)
 | |
|       return -1;
 | |
|     break;
 | |
|   }
 | |
|   /* Check CRC */
 | |
|   if (myread(splfild, my_end_msg, 256) < 0)
 | |
|     return -1;
 | |
|   if (strcmp(end_msg,my_end_msg) != 0) {
 | |
|     LOCAL_ErrorMessage = "bad trailing CRC in saved state";
 | |
|     return -1;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* restore some heap registers */
 | |
| static void 
 | |
| restore_heap_regs( USES_REGS1 )
 | |
| {
 | |
|   if (HeapTop) {
 | |
|     HeapTop = AddrAdjust(HeapTop);
 | |
|     *((YAP_SEG_SIZE *) HeapTop) = InUseFlag;
 | |
|   }
 | |
|   HeapMax = Yap_heap_regs->heap_used = OldHeapUsed;
 | |
|   HeapLim = LOCAL_GlobalBase;
 | |
| }
 | |
| 
 | |
| /* adjust abstract machine registers */
 | |
| static void 
 | |
| restore_regs(int flag USES_REGS)
 | |
| {
 | |
|   restore_heap_regs( PASS_REGS1 );
 | |
|   if (CurrentModule) {
 | |
|     CurrentModule = AtomTermAdjust(CurrentModule);;
 | |
|   }
 | |
|   if (flag == DO_EVERYTHING) {
 | |
|     CP = PtoOpAdjust(CP);
 | |
|     ENV = PtoLocAdjust(ENV);
 | |
|     ASP = PtoLocAdjust(ASP);
 | |
|     H = PtoGloAdjust(H);
 | |
|     B = (choiceptr)PtoLocAdjust(CellPtr(B));
 | |
|     TR = PtoTRAdjust(TR);
 | |
|     P = PtoOpAdjust(P);
 | |
|     HB = PtoLocAdjust(HB);
 | |
|     YENV = PtoLocAdjust(YENV);
 | |
|     S = PtoGloAdjust(S);
 | |
|     if (EX) {
 | |
|       EX = DBTermAdjust(EX);
 | |
|       RestoreDBTerm(EX, TRUE PASS_REGS);
 | |
|     }
 | |
|     LOCAL_WokenGoals = AbsAppl(PtoGloAdjust(RepAppl(LOCAL_WokenGoals)));
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| recompute_mask(DBRef dbr)
 | |
| {
 | |
|   if (dbr->Flags & DBNoVars) {
 | |
|     dbr->Mask = Yap_EvalMasks((Term) dbr->DBT.Entry, &(dbr->Key));
 | |
|   } else if (dbr->Flags & DBComplex) {
 | |
|     /* This is quite nasty, we want to recalculate the mask but
 | |
|        we don't want to rebuild the whole term. We'll just build whatever we
 | |
|        need to recompute the mask.
 | |
|     */
 | |
|     CELL *x = (CELL *)HeapTop, *tp;
 | |
|     unsigned int Arity, i;
 | |
|     Term out;
 | |
|     char *tbase = CharP(dbr->DBT.Contents-1);
 | |
| 
 | |
|     if (IsPairTerm(dbr->DBT.Entry)) {
 | |
| 
 | |
|       out = AbsPair(x);
 | |
|       Arity = 2;
 | |
|       tp = (CELL *)(tbase + (CELL) RepPair(dbr->DBT.Entry));
 | |
|     } else {
 | |
|       Functor f;
 | |
|     
 | |
|       tp = (CELL *)(tbase + (CELL) RepAppl(dbr->DBT.Entry));
 | |
|       f = (Functor)(*tp++);
 | |
|       out = AbsAppl(x);
 | |
|       Arity = ArityOfFunctor(f);
 | |
|       *x++ = (CELL)f;
 | |
|       if (Arity > 3) Arity = 3;
 | |
|     }
 | |
|     for (i = 0; i < Arity; i++) {
 | |
|       register Term   tw = *tp++;
 | |
|       if (IsVarTerm(tw)) {
 | |
| 	RESET_VARIABLE(x);
 | |
|       } else if (IsApplTerm(tw)) {
 | |
| 	/* just fetch the functor from where it is in the data-base.
 | |
| 	   This guarantees we have access to references and friends. */
 | |
| 	CELL offset = (CELL)RepAppl(tw);
 | |
| 	if (offset > dbr->DBT.NOfCells*sizeof(CELL))
 | |
| 	  *x = tw;
 | |
| 	else
 | |
| 	  *x = AbsAppl((CELL *)(tbase + offset));
 | |
|       } else if (IsAtomicTerm(tw)) {
 | |
| 	*x = tw;
 | |
|       } else if (IsPairTerm(tw)) {
 | |
| 	*x = AbsPair(x);
 | |
|       }
 | |
|       x++;
 | |
|     }
 | |
|     dbr->Mask = Yap_EvalMasks(out, &(dbr->Key));
 | |
|   }
 | |
| }
 | |
| 
 | |
| #define HASH_SHIFT 6
 | |
| 
 | |
| /*
 | |
|  * This is used to make an hash table correct, after displacing its elements,
 | |
|  * HCEnd should point to an area of free space, usually in the heap. The
 | |
|  * routine is very dependent on the hash function used, and it destroys the
 | |
|  * previous "hit" order 
 | |
|  */
 | |
| static void 
 | |
| rehash(CELL *oldcode, int NOfE, int KindOfEntries USES_REGS)
 | |
| {
 | |
|   register CELL  *savep, *basep;
 | |
|   CELL           *oldp = oldcode;
 | |
|   int             TableSize = NOfE - 1, NOfEntries;
 | |
|   register int    i;
 | |
|   int             hash;
 | |
|   CELL            WorkTerm, failplace = 0;
 | |
|   CELL           *Base = oldcode;
 | |
| 
 | |
|   if (LOCAL_HDiff == 0)
 | |
|       return;
 | |
|   basep = H;
 | |
|   if (H + (NOfE*2) > ASP) {
 | |
|     basep = (CELL *)TR;
 | |
|     if (basep + (NOfE*2) > (CELL *)LOCAL_TrailTop) {
 | |
|       if (!Yap_growtrail((ADDR)(basep + (NOfE*2))-LOCAL_TrailTop, TRUE)) {
 | |
| 	Yap_Error(OUT_OF_TRAIL_ERROR, TermNil,
 | |
| 	      "not enough space to restore hash tables for indexing");
 | |
| 	Yap_exit(1);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   for (i = 0; i < NOfE; ++i) {
 | |
|     if (*oldp == 0) {
 | |
|       failplace = oldp[1];
 | |
|       break;
 | |
|     }
 | |
|     oldp += 2;
 | |
|   }
 | |
|   savep = basep;
 | |
|   oldp = oldcode;
 | |
|   for (i = 0; i < NOfE; ++i) {
 | |
|     if (*oldp != 0) {
 | |
|       savep[0] = oldp[0];
 | |
|       savep[1] = oldp[1];
 | |
|       oldp[0] = 0;
 | |
|       oldp[1] = failplace;
 | |
|       savep += 2;
 | |
|     }
 | |
|     oldp += 2;
 | |
|   }
 | |
|   NOfEntries = (savep - basep)/2;
 | |
|   savep = basep;
 | |
|   for (i = 0; i < NOfEntries; ++i) {
 | |
|     register Int    d;
 | |
|     CELL *hentry;
 | |
| 
 | |
|     WorkTerm = savep[i*2];
 | |
|     hash = (Unsigned(WorkTerm) >> HASH_SHIFT) & TableSize;
 | |
|     hentry = Base + hash * 2;
 | |
|     d = TableSize & (Unsigned(WorkTerm) | 1);
 | |
|     while (*hentry) {
 | |
| #ifdef DEBUG
 | |
| #ifdef CLASHES
 | |
|       ++clashes;
 | |
| #endif /* CLASHES */
 | |
| #endif /* DEBUG */
 | |
|       hash = (hash + d) & TableSize;
 | |
|       hentry = Base + hash * 2;
 | |
|     }
 | |
|     hentry[0] = WorkTerm;
 | |
|     hentry[1] = savep[i*2+1];
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| RestoreSWIHash(void)
 | |
| {
 | |
|   Yap_InitSWIHash();
 | |
| }
 | |
| 
 | |
| 
 | |
| #include "rheap.h"
 | |
| 
 | |
| /* restore the atom entries which are invisible for the user */
 | |
| static void 
 | |
| RestoreIOStructures(void)
 | |
| {
 | |
|   Yap_InitStdStreams();
 | |
| }
 | |
| 
 | |
| static void 
 | |
| RestoreFreeSpace( USES_REGS1 )
 | |
| {
 | |
| #if USE_DL_MALLOC
 | |
|   Yap_av = (struct malloc_state *)AddrAdjust((ADDR)Yap_av);
 | |
|   Yap_RestoreDLMalloc();
 | |
|   if (AuxSp != NULL) {
 | |
|     if (AuxBase < LOCAL_OldHeapBase || AuxBase > LOCAL_OldHeapTop) {
 | |
|       AuxSp = NULL;
 | |
|       AuxBase = NULL;
 | |
|       AuxTop = NULL;
 | |
|     } else {
 | |
|       AuxSp = PtoHeapCellAdjust(AuxSp);
 | |
|       AuxBase = AddrAdjust(AuxBase);
 | |
|       AuxTop = AddrAdjust(AuxTop);
 | |
|       LOCAL_ScratchPad.ptr = AddrAdjust(LOCAL_ScratchPad.ptr);
 | |
|     }
 | |
|   }
 | |
| #else
 | |
|   /* restores the list of free space, with its curious structure */
 | |
|   BlockHeader *bpt, *bsz;
 | |
| 
 | |
|   if (FreeBlocks != NULL)
 | |
|     FreeBlocks = BlockAdjust(FreeBlocks);
 | |
|   bpt = FreeBlocks;
 | |
|   if (AuxSp != NULL)
 | |
|     AuxSp = CellPtoHeapAdjust(AuxSp);
 | |
|   if (AuxTop != NULL)
 | |
|     AuxTop = AddrAdjust(AuxTop);
 | |
|   while (bpt != NULL) {
 | |
|     if (bpt->b_next != NULL) {
 | |
|       bsz = bpt->b_next = BlockAdjust(bpt->b_next);
 | |
|       while (bsz != NULL) {
 | |
| 	if (bsz->b_next_size != NULL)
 | |
| 	  bsz->b_next_size = BlockAdjust(bsz->b_next_size);
 | |
| 	if (bsz->b_next != NULL)
 | |
| 	  bsz->b_next = BlockAdjust(bsz->b_next);
 | |
| 	bsz = bsz->b_next;
 | |
|       }
 | |
|     }
 | |
|     if (bpt->b_next_size != NULL)
 | |
|       bpt->b_next_size = BlockAdjust(bpt->b_next_size);
 | |
|     bpt = bpt->b_next_size;
 | |
|   }
 | |
|   *((YAP_SEG_SIZE *) HeapTop) = InUseFlag;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void
 | |
| RestoreAtomList(Atom atm USES_REGS)
 | |
| {
 | |
|   AtomEntry      *at;
 | |
| 
 | |
|   at = RepAtom(atm);
 | |
|   if (EndOfPAEntr(at))
 | |
|     return;
 | |
|   do {
 | |
|     RestoreAtom(at PASS_REGS);
 | |
|     at = RepAtom(at->NextOfAE);
 | |
|   } while (!EndOfPAEntr(at));
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| RestoreHashPreds( USES_REGS1 )
 | |
| {
 | |
|   UInt size = PredHashTableSize;
 | |
|   int malloced = FALSE;
 | |
|   PredEntry **np;
 | |
|   UInt i;
 | |
|   PredEntry **oldp = PredHash;
 | |
| 
 | |
|   np = (PredEntry **) Yap_AllocAtomSpace(sizeof(PredEntry **)*size);
 | |
|   if (!np) {
 | |
|     if (!(np = (PredEntry **) malloc(sizeof(PredEntry **)*size))) {
 | |
| 	Yap_Error(FATAL_ERROR,TermNil,"Could not allocate space for pred table");
 | |
| 	return;
 | |
|       }
 | |
|     malloced = TRUE;
 | |
|   }
 | |
|   for (i = 0; i < size; i++) {
 | |
|     np[i] = NULL;
 | |
|   }
 | |
|   for (i = 0; i < PredHashTableSize; i++) {
 | |
|     PredEntry *p = oldp[i];
 | |
| 
 | |
|     if (p)
 | |
|       p = PredEntryAdjust(p);
 | |
|     while (p) {
 | |
|       Prop nextp;
 | |
|       UInt hsh;
 | |
|       
 | |
|       if (p->NextOfPE)
 | |
| 	p->NextOfPE = PropAdjust(p->NextOfPE);
 | |
|       nextp = p->NextOfPE;
 | |
|       CleanCode(p PASS_REGS);
 | |
|       hsh = PRED_HASH(p->FunctorOfPred, p->ModuleOfPred, size);
 | |
|       p->NextOfPE = AbsPredProp(np[hsh]);
 | |
|       np[hsh] = p;
 | |
|       p = RepPredProp(nextp);
 | |
|     }
 | |
|   }
 | |
|   for (i = 0; i < size; i++) {
 | |
|     PredHash[i] = np[i];
 | |
|   }
 | |
|   if (malloced)
 | |
|     free((ADDR)np);
 | |
|   else
 | |
|     Yap_FreeAtomSpace((ADDR)np);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This is the really tough part, to restore the whole of the heap 
 | |
|  */
 | |
| static void 
 | |
| restore_heap(void)
 | |
| {
 | |
|   restore_codes();
 | |
|   RestoreIOStructures();
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef DEBUG_RESTORE3
 | |
| static void 
 | |
| ShowEntries(pp)
 | |
| 	PropEntry      *pp;
 | |
| {
 | |
|   while (!EndOfPAEntr(pp)) {
 | |
|     fprintf(GLOBAL_stderr,"Estou a ver a prop %x em %x\n", pp->KindOfPE, pp);
 | |
|     pp = RepProp(pp->NextOfPE);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void 
 | |
| ShowAtoms()
 | |
| {
 | |
|   AtomHashEntry  *HashPtr = HashChain;
 | |
|   register int    i;
 | |
|   for (i = 0; i < AtomHashTableSize; ++i) {
 | |
|     if (HashPtr->Entry != NIL) {
 | |
|       AtomEntry      *at;
 | |
|       at = RepAtom(HashPtr->Entry);
 | |
|       do {
 | |
| 	fprintf(GLOBAL_stderr,"Passei ao %s em %x\n", at->StrOfAE, at);
 | |
| 	ShowEntries(RepProp(at->PropsOfAE));
 | |
|       } while (!EndOfPAEntr(at = RepAtom(at->NextOfAE)));
 | |
|     }
 | |
|     HashPtr++;
 | |
|   }
 | |
|   HashPtr = WideHashChain;
 | |
|   for (i = 0; i < WideAtomHashTableSize; ++i) {
 | |
|     if (HashPtr->Entry != NIL) {
 | |
|       AtomEntry      *at;
 | |
|       at = RepAtom(HashPtr->Entry);
 | |
|       do {
 | |
| 	fprintf(GLOBAL_stderr,"Passei ao %s em %x\n", at->StrOfAE, at);
 | |
| 	ShowEntries(RepProp(at->PropsOfAE));
 | |
|       } while (!EndOfPAEntr(at = RepAtom(at->NextOfAE)));
 | |
|     }
 | |
|     HashPtr++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| #endif /* DEBUG_RESTORE3 */
 | |
| 
 | |
| #include <stdio.h>
 | |
| 
 | |
| static int
 | |
| commit_to_saved_state(char *s, CELL *Astate, CELL *ATrail, CELL *AStack, CELL *AHeap) {
 | |
|   CACHE_REGS
 | |
|   int mode;
 | |
| 
 | |
|   if ((mode = check_header(Astate,ATrail,AStack,AHeap PASS_REGS)) == FAIL_RESTORE)
 | |
|     return(FAIL_RESTORE);
 | |
|   LOCAL_PrologMode = BootMode;
 | |
|   if (Yap_HeapBase) {
 | |
|     extern void Scleanup(void);
 | |
|     if (!yap_flags[HALT_AFTER_CONSULT_FLAG] && !yap_flags[QUIET_MODE_FLAG]) {
 | |
|       Yap_TrueFileName(s,LOCAL_FileNameBuf2, YAP_FILENAME_MAX);
 | |
|       fprintf(stderr, "%% Restoring file %s\n", LOCAL_FileNameBuf2);
 | |
|     }
 | |
|     Scleanup();
 | |
|     Yap_CloseStreams(TRUE);
 | |
|   }
 | |
| #ifdef DEBUG_RESTORE4
 | |
|   /*
 | |
|    * This should be another file, like the log file 
 | |
|    */
 | |
|   errout = GLOBAL_stderr;
 | |
| #endif
 | |
|   return mode;
 | |
| }
 | |
| 
 | |
| static void
 | |
| cat_file_name(char *s, char *prefix, char *name, unsigned int max_length)
 | |
| {
 | |
|   strncpy(s, prefix, max_length);
 | |
| #if _MSC_VER || defined(__MINGW32__)
 | |
|   strncat(s,"\\", max_length);
 | |
| #else
 | |
|   strncat(s,"/", max_length);
 | |
| #endif
 | |
|   strncat(s, name, max_length-1);
 | |
| }
 | |
| 
 | |
| static int try_open(char *inpf, CELL *Astate, CELL *ATrail, CELL *AStack, CELL *AHeap, char *buf, IOSTREAM **streamp) {
 | |
|   int mode;
 | |
| 
 | |
|   if (streamp) {
 | |
|     if ((*streamp = Sopen_file(inpf, "rb"))) {
 | |
|       return DO_ONLY_CODE;
 | |
|     }
 | |
|     return FAIL_RESTORE;
 | |
|   }
 | |
|   if ((splfild = open_file(inpf, O_RDONLY)) < 0) {
 | |
|     return FAIL_RESTORE;
 | |
|   }
 | |
|   if (buf[0] == '\0')
 | |
|     strncpy(buf, inpf, YAP_FILENAME_MAX);
 | |
|   if ((mode = commit_to_saved_state(inpf,Astate,ATrail,AStack,AHeap)) != FAIL_RESTORE) {
 | |
|     CACHE_REGS
 | |
|     LOCAL_ErrorMessage = NULL;
 | |
|     return mode;
 | |
|   }
 | |
|   return mode;
 | |
| }
 | |
| 
 | |
| static int 
 | |
| OpenRestore(char *inpf, char *YapLibDir, CELL *Astate, CELL *ATrail, CELL *AStack, CELL *AHeap, IOSTREAM **streamp)
 | |
| {
 | |
|   CACHE_REGS
 | |
|   int mode = FAIL_RESTORE;
 | |
|   char save_buffer[YAP_FILENAME_MAX+1];
 | |
| 
 | |
|   save_buffer[0] = '\0';
 | |
|   //  LOCAL_ErrorMessage = NULL;
 | |
|   if (inpf == NULL) {
 | |
|       inpf = StartUpFile;
 | |
|   }
 | |
|   /* careful it starts from the root */
 | |
|   if (inpf[0] != '/') {
 | |
| #if __simplescalar__
 | |
|     /* does not implement getcwd */
 | |
|     strncpy(LOCAL_FileNameBuf,GLOBAL_pwd,YAP_FILENAME_MAX);
 | |
| #elif HAVE_GETCWD
 | |
|     if (getcwd (LOCAL_FileNameBuf, YAP_FILENAME_MAX) == NULL)
 | |
|       LOCAL_FileNameBuf[0] = '\0';
 | |
| #else
 | |
|     if (getwd (LOCAL_FileNameBuf) == NULL)
 | |
|       LOCAL_FileNameBuf[0] = '\0';
 | |
| #endif
 | |
|     strncat(LOCAL_FileNameBuf, "/", YAP_FILENAME_MAX-1);
 | |
|     strncat(LOCAL_FileNameBuf, inpf, YAP_FILENAME_MAX-1);
 | |
|   } else {
 | |
|     strncat(LOCAL_FileNameBuf, inpf, YAP_FILENAME_MAX-1);
 | |
|   }
 | |
|   if (inpf != NULL && (splfild = open_file(inpf, O_RDONLY)) > 0) {
 | |
|     if ((mode = try_open(inpf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
|       return mode;
 | |
|     }
 | |
|   }
 | |
|   if (!Yap_dir_separator(inpf[0]) && !Yap_volume_header(inpf)) {
 | |
|     /*
 | |
|       we have a relative path for the file, try to do somewhat better 
 | |
|       using YAPLIBDIR or friends.
 | |
|     */
 | |
|     if (YapLibDir != NULL) {
 | |
|       cat_file_name(LOCAL_FileNameBuf, Yap_LibDir, inpf, YAP_FILENAME_MAX);
 | |
|       if ((mode = try_open(LOCAL_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
| 	return mode;
 | |
|       }
 | |
|     } else {
 | |
|       if ((mode = try_open(LOCAL_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
| 	return mode;
 | |
|       }
 | |
|     }
 | |
| #if HAVE_GETENV
 | |
|     {
 | |
|       char *yap_env = getenv("YAPLIBDIR");
 | |
|       if (yap_env != NULL) {
 | |
| 	cat_file_name(LOCAL_FileNameBuf, yap_env, inpf, YAP_FILENAME_MAX);
 | |
| 	if ((mode = try_open(LOCAL_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
| 	  return mode;
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
| #endif
 | |
|     if (YAP_LIBDIR != NULL) {
 | |
|       cat_file_name(LOCAL_FileNameBuf, YAP_LIBDIR, inpf, YAP_FILENAME_MAX);
 | |
|       if ((splfild = open_file(LOCAL_FileNameBuf, O_RDONLY)) > 0) {
 | |
| 	if ((mode = try_open(LOCAL_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
| 	  return mode;
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| #if _MSC_VER || defined(__MINGW32__)
 | |
|   if ((inpf = Yap_RegistryGetString("startup"))) {
 | |
|     if ((splfild = open_file(inpf, O_RDONLY)) > 0) {
 | |
|       if ((mode = try_open(inpf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
| 	return mode;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   {
 | |
|     DWORD fatts;
 | |
|     int buflen;
 | |
|     char *pt;
 | |
| 
 | |
|     /* try to get it from current executable */
 | |
|     if ((fatts = GetFileAttributes(LOCAL_FileNameBuf)) == 0xFFFFFFFFL ||
 | |
| 	!(fatts & FILE_ATTRIBUTE_DIRECTORY)) {
 | |
|       /* couldn't find it where it was supposed to be,
 | |
| 	 let's try using the executable */
 | |
|       if (!GetModuleFileNameEx( GetCurrentProcess(), NULL, LOCAL_FileNameBuf, YAP_FILENAME_MAX)) {
 | |
| 	/* do nothing */
 | |
| 	goto end;
 | |
|       }
 | |
|       buflen = strlen(LOCAL_FileNameBuf);
 | |
|       pt = LOCAL_FileNameBuf+buflen;
 | |
|       while (*--pt != '\\') {
 | |
| 	/* skip executable */
 | |
| 	if (pt == LOCAL_FileNameBuf) {
 | |
| 	  /* do nothing */
 | |
| 	  goto end;
 | |
| 	}
 | |
|       }
 | |
|       while (*--pt != '\\') {
 | |
| 	/* skip parent directory "bin\\" */
 | |
| 	if (pt == LOCAL_FileNameBuf) {
 | |
| 	  goto end;
 | |
| 	}
 | |
|       }
 | |
|       /* now, this is a possible location for the ROOT_DIR, let's look for a share directory here */
 | |
|       pt[1] = '\0';
 | |
|       strncat(LOCAL_FileNameBuf,"lib/Yap/startup.yss",YAP_FILENAME_MAX);
 | |
|     }
 | |
|     if ((mode = try_open(LOCAL_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer,streamp)) != FAIL_RESTORE) {
 | |
|       return mode;
 | |
|     }
 | |
|   }
 | |
|  end:
 | |
| #endif
 | |
|   /* try to open from current directory */
 | |
|   /* could not open file */
 | |
|   if (LOCAL_ErrorMessage == NULL) {
 | |
|     if (save_buffer[0]) {
 | |
|       strncpy(LOCAL_FileNameBuf, save_buffer, YAP_FILENAME_MAX-1);
 | |
|       do_system_error(PERMISSION_ERROR_OPEN_SOURCE_SINK,"incorrect saved state");
 | |
|     } else {
 | |
|       strncpy(LOCAL_FileNameBuf, inpf, YAP_FILENAME_MAX-1);
 | |
|       do_system_error(PERMISSION_ERROR_OPEN_SOURCE_SINK,"could not open saved state");
 | |
|     }
 | |
|   }
 | |
|   return FAIL_RESTORE;
 | |
| }
 | |
| 
 | |
| IOSTREAM * 
 | |
| Yap_OpenRestore(char *inpf, char *YapLibDir)
 | |
| {
 | |
|   IOSTREAM *stream = NULL;
 | |
| 
 | |
|   OpenRestore(inpf, YapLibDir, NULL, NULL, NULL, NULL, &stream);
 | |
|   return stream;
 | |
| }
 | |
| 
 | |
| static void 
 | |
| CloseRestore(void)
 | |
| {
 | |
|  CACHE_REGS
 | |
| #ifdef DEBUG_RESTORE3
 | |
|   ShowAtoms();
 | |
| #endif
 | |
|   close_file();
 | |
|   LOCAL_PrologMode = UserMode;
 | |
| }
 | |
| 
 | |
| #if !defined(_WIN32)
 | |
| static int 
 | |
| check_opcodes(OPCODE old_ops[])
 | |
| {
 | |
| #if USE_THREADED_CODE
 | |
|   int have_shifted = FALSE;
 | |
|   op_numbers op = _Ystop;
 | |
|   for (op = _Ystop; op < _std_top; op++) {
 | |
|     if (Yap_opcode(op) != old_ops[op]) {
 | |
|       have_shifted = TRUE;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   return have_shifted;
 | |
| #else
 | |
|   /* be conservative */
 | |
|   return TRUE;
 | |
| #endif
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void 
 | |
| RestoreHeap(OPCODE old_ops[] USES_REGS)
 | |
| {
 | |
|   int heap_moved = (LOCAL_OldHeapBase != Yap_HeapBase ||
 | |
| 		    LOCAL_XDiff), opcodes_moved;
 | |
|   Term mod = CurrentModule;
 | |
| 
 | |
|   CurrentModule = PROLOG_MODULE;
 | |
| #if defined(_WIN32)
 | |
|   /* It seems that under WIN32 opcodes may not have moved but the
 | |
|      remaining code may have bmoved */ 
 | |
|   opcodes_moved = TRUE;
 | |
| #else
 | |
|   opcodes_moved = check_opcodes(old_ops);
 | |
| #endif
 | |
|   /* opcodes_moved has side-effects and should be tried first */
 | |
|   if (heap_moved) {
 | |
|     opcodes_moved = TRUE;
 | |
|     RestoreFreeSpace( PASS_REGS1 );
 | |
|   }
 | |
|   if (heap_moved || opcodes_moved) {
 | |
|     restore_heap();
 | |
|   }
 | |
|   /* This must be done after restore_heap */
 | |
|   Yap_InitAbsmi();
 | |
|   if (opcodes_moved) {
 | |
|     Yap_InitCPreds();
 | |
|     Yap_InitBackCPreds();
 | |
|   }
 | |
|   if (!(Yap_ReInitConstExps() &&
 | |
| 	Yap_ReInitUnaryExps() &&
 | |
| 	Yap_ReInitBinaryExps())) {
 | |
|     Yap_Error(SYSTEM_ERROR, TermNil, "arithmetic operator not in saved state");
 | |
|   }
 | |
| #ifdef DEBUG_RESTORE1
 | |
|   fprintf(errout, "phase 1 done\n");
 | |
| #endif
 | |
|   CurrentModule = mod;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This function is called to know about the parameters of the last saved
 | |
|  * state 
 | |
|  */
 | |
| int 
 | |
| Yap_SavedInfo(char *FileName, char *YapLibDir, CELL *ATrail, CELL *AStack, CELL *AHeap)
 | |
| {
 | |
|   return DO_ONLY_CODE;
 | |
| 
 | |
|   CELL MyTrail, MyStack, MyHeap, MyState;
 | |
|   int             mode;
 | |
| 
 | |
|   mode = OpenRestore(FileName, YapLibDir, &MyState, &MyTrail, &MyStack, &MyHeap, NULL);
 | |
|   if (mode == FAIL_RESTORE) {
 | |
|     return -1;
 | |
|   }
 | |
|   close_file();
 | |
|   if (! *AHeap)
 | |
|     *AHeap = MyHeap / 1024;
 | |
|   if (mode != DO_ONLY_CODE && *AStack)
 | |
|     *AStack = MyStack / 1024;
 | |
|   if (mode != DO_ONLY_CODE && *ATrail)
 | |
|     *ATrail = MyTrail / 1024;
 | |
|   return (MyState);
 | |
| }
 | |
| 
 | |
| static void
 | |
| UnmarkTrEntries( USES_REGS1 )
 | |
| {
 | |
|   CELL           entry, *Entries;
 | |
| 
 | |
|   /* initialise a choice point */
 | |
|   B = (choiceptr)LCL0;
 | |
|   B--;
 | |
|   B->cp_ap = NOCODE;
 | |
|   Entries = (CELL *)LOCAL_TrailBase;
 | |
|   while ((entry = *Entries++) != (CELL)NULL) {
 | |
|     if (!IsVarTerm(entry)) {
 | |
|       if(IsPairTerm(entry)) {
 | |
| 	CELL *ent = CellPtoHeapAdjust(RepPair(entry));
 | |
| 	register CELL flags;
 | |
| 
 | |
| 	flags = *ent;
 | |
| 	ResetFlag(InUseMask, flags);
 | |
| 	*ent = flags;
 | |
| 	if (FlagOn((DirtyMask|ErasedMask), flags)) {
 | |
| 	  if (FlagOn(DBClMask, flags)) {
 | |
| 	    Yap_ErDBE(DBStructFlagsToDBStruct(ent));
 | |
| 	  } else {
 | |
| 	    if (flags & LogUpdMask) {
 | |
| 	      if (flags & IndexMask) {
 | |
| 		if (FlagOn(ErasedMask, flags))
 | |
| 		  Yap_ErLogUpdIndex(ClauseFlagsToLogUpdIndex(ent));
 | |
| 		else
 | |
| 		  Yap_CleanUpIndex(ClauseFlagsToLogUpdIndex(ent));
 | |
| 	      } else {
 | |
| 		Yap_ErLogUpdCl(ClauseFlagsToLogUpdClause(ent));
 | |
| 	      }
 | |
| 	    } else {
 | |
| 	      Yap_ErCl(ClauseFlagsToDynamicClause(ent));
 | |
| 	    }
 | |
| 	  }
 | |
| 	}
 | |
| #ifdef MULTI_ASSIGNMENT_VARIABLES
 | |
|       } else /* if (IsApplTerm(d1)) */ {
 | |
| 	Entries += 2;
 | |
| #endif
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   B = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| int in_limbo = FALSE;
 | |
| 
 | |
| /* cleanup any records we had in the saved state. They are now inaccessible */
 | |
| static void
 | |
| FreeRecords(void) {
 | |
|   struct record_list *ptr;
 | |
| 
 | |
|   ptr = Yap_Records;
 | |
|   Yap_Records = NULL;
 | |
|   while (ptr) {
 | |
|     struct record_list *optr = ptr;
 | |
|     Yap_ReleaseTermFromDB(ptr->dbrecord);
 | |
|     ptr = ptr->next_rec;
 | |
|     Yap_FreeCodeSpace((void *)optr);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This function is called when wanting only to restore the heap and
 | |
|  * associated registers 
 | |
|  */
 | |
| static int 
 | |
| Restore(char *s, char *lib_dir USES_REGS)
 | |
| {
 | |
|   int restore_mode;
 | |
| 
 | |
|   OPCODE old_ops[_std_top+1];
 | |
|   CELL MyTrail, MyStack, MyHeap, MyState;
 | |
| 
 | |
|   if ((restore_mode = OpenRestore(s, lib_dir, &MyState, &MyTrail, &MyStack, &MyHeap, NULL)) == FAIL_RESTORE)
 | |
|     return(FALSE);
 | |
|   Yap_ShutdownLoadForeign();
 | |
|   in_limbo = TRUE;
 | |
|   if (get_coded(restore_mode, old_ops PASS_REGS) < 0)
 | |
|      return FAIL_RESTORE;  
 | |
|   restore_regs(restore_mode PASS_REGS);
 | |
|   in_limbo = FALSE;
 | |
|   /*#endif*/
 | |
|   RestoreHeap(old_ops PASS_REGS);
 | |
|   switch(restore_mode) {
 | |
|   case DO_EVERYTHING:
 | |
|     if (LOCAL_OldHeapBase != Yap_HeapBase ||
 | |
| 	LOCAL_OldLCL0 != LCL0 ||
 | |
| 	LOCAL_OldGlobalBase != (CELL *)LOCAL_GlobalBase ||
 | |
| 	LOCAL_OldTrailBase != LOCAL_TrailBase) {
 | |
|       Yap_AdjustStacksAndTrail();
 | |
|       if (which_save == 2) {
 | |
| 	Yap_AdjustRegs(2);
 | |
|       } else {
 | |
| 	Yap_AdjustRegs(1);
 | |
|       }
 | |
|       break;
 | |
| #ifdef DEBUG_RESTORE2
 | |
|       fprintf(errout, "phase 2 done\n");
 | |
| #endif
 | |
|     }
 | |
|     break;
 | |
|   case DO_ONLY_CODE:
 | |
|     UnmarkTrEntries( PASS_REGS1 );
 | |
|     Yap_InitYaamRegs();
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   Yap_ReOpenLoadForeign();
 | |
|   FreeRecords();
 | |
|   /* restart IO */
 | |
|   initIO();
 | |
|   /* reset time */
 | |
|   Yap_ReInitWallTime();
 | |
|   Yap_InitSysPath();
 | |
| #if USE_DL_MALLOC || USE_SYSTEM_MALLOC
 | |
|   if (!AuxSp) {
 | |
|     Yap_InitPreAllocCodeSpace();
 | |
|   }
 | |
| #endif
 | |
|   CloseRestore();
 | |
|   if (which_save == 2) {
 | |
|     Yap_unify(ARG2, MkIntTerm(0));
 | |
|   }
 | |
|   return restore_mode;
 | |
| }
 | |
| 
 | |
| int 
 | |
| Yap_SavedStateRestore(char *s, char *lib_dir)
 | |
| {
 | |
|   CACHE_REGS
 | |
|   return Restore(s, lib_dir PASS_REGS);
 | |
| }
 | |
| 
 | |
| static Int 
 | |
| p_restore( USES_REGS1 )
 | |
| {
 | |
|   int mode;
 | |
|   char s[YAP_FILENAME_MAX+1];
 | |
| 
 | |
|   Term t1 = Deref(ARG1);
 | |
| #ifdef YAPOR
 | |
|   if (GLOBAL_number_workers != 1) {
 | |
|     Yap_Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
 | |
|     return(FALSE);
 | |
|   }
 | |
| #endif /* YAPOR */
 | |
| #ifdef THREADS
 | |
|   if (GLOBAL_NOfThreads != 1) {
 | |
|     Yap_Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
 | |
|     return(FALSE);
 | |
|   }
 | |
| #endif /* THREADS */
 | |
|   if (!Yap_GetName(s, YAP_FILENAME_MAX, t1)) {
 | |
|     Yap_Error(TYPE_ERROR_LIST,t1,"restore/1");
 | |
|     return(FALSE);
 | |
|   }
 | |
|   if ((mode = Restore(s, NULL PASS_REGS)) == DO_ONLY_CODE) {
 | |
|     Yap_RestartYap( 3 );
 | |
|   }
 | |
|   return(mode != FAIL_RESTORE);
 | |
| }
 | |
| 
 | |
| void 
 | |
| Yap_InitSavePreds(void)
 | |
| {
 | |
|   Yap_InitCPred("$save", 2, p_save2, SyncPredFlag);
 | |
|   Yap_InitCPred("$save_program", 1, p_save_program, SyncPredFlag);
 | |
|   Yap_InitCPred("$restore", 1, p_restore, SyncPredFlag);
 | |
| }
 |