1 /*************************************************************************
2 *									 *
3 *	 YAP Prolog 							 *
4 *									 *
5 *	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
6 *									 *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
8 *									 *
9 **************************************************************************
10 *									 *
11 * File:		save.c							 *
12 * Last rev:								 *
13 * mods:									 *
14 * comments:	saving and restoring a Prolog computation		 *
15 *									 *
16 *************************************************************************/
17 #ifdef SCCS
18 static char     SccsId[] = "@(#)save.c	1.3 3/15/90";
19 #endif
20 
21 #if _MSC_VER || defined(__MINGW32__)
22 #include <windows.h>
23 #include <psapi.h>
24 #endif
25 #include "absmi.h"
26 #include "alloc.h"
27 #if USE_DL_MALLOC
28 #include "dlmalloc.h"
29 #endif
30 #include "yapio.h"
31 #include "sshift.h"
32 #include "Foreign.h"
33 #if HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #if !HAVE_STRNCAT
37 #define strncat(X,Y,Z) strcat(X,Y)
38 #endif
39 #if !HAVE_STRNCPY
40 #define strncpy(X,Y,Z) strcpy(X,Y)
41 #endif
42 
43 #if HAVE_FCNTL_H
44 #include <fcntl.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #ifdef HAVE_SYS_TYPES_H
50 #include <sys/types.h>
51 #endif
52 #ifdef HAVE_SYS_STAT_H
53 #include <sys/stat.h>
54 #endif
55 #include "iopreds.h"
56 
57 /*********  hack for accesing several kinds of terms. Should be cleaned **/
58 
59 static char StartUpFile[] = "startup.yss";
60 
61 static char end_msg[256] ="*** End of YAP saved state *****";
62 
63 
64 #ifdef DEBUG
65 
66 /*
67  *
68  #FOR DEBUGGING define DEBUG_RESTORE0 to check the file stuff,
69  #define DEBUG_RESTORE1 to see if it is able to prepare the chain,
70  #define DEBUG_RESTORE2 to see how things are going,
71  #define DEBUG_RESTORE3 to check if the atom chain is still a working chain,
72  * define DEBUG_RESTORE4 if you want to set the output for some
73  * particular file,
74  * define DEBUG_RESTORE5 if you want to see how the stacks are being
75  * cleaned up,
76  * define DEBUG_RESTORE6 if you want to follow the execution in
77  *
78  * Also a file is defined where you can write things, by default stderr
79  *
80  * Good Luck
81  */
82 
83 #endif
84 
85 STATIC_PROTO(int   myread, (int, char *, Int));
86 STATIC_PROTO(Int   mywrite, (int, char *, Int));
87 STATIC_PROTO(int   open_file, (char *, int));
88 STATIC_PROTO(int   close_file, (void));
89 STATIC_PROTO(Int   putout, (CELL));
90 STATIC_PROTO(Int   putcellptr, (CELL *));
91 STATIC_PROTO(CELL  get_cell, (void));
92 STATIC_PROTO(CELL  *get_cellptr, ( /* CELL * */ void));
93 STATIC_PROTO(int   put_info, (int, int));
94 STATIC_PROTO(int   save_regs, (int));
95 STATIC_PROTO(int   save_code_info, (void));
96 STATIC_PROTO(int   save_heap, (void));
97 STATIC_PROTO(int   save_stacks, (int));
98 STATIC_PROTO(int   save_crc, (void));
99 STATIC_PROTO(Int   do_save, (int));
100 STATIC_PROTO(Int   p_save2, (void));
101 STATIC_PROTO(Int   p_save_program, (void));
102 STATIC_PROTO(int   check_header, (CELL *, CELL *, CELL *, CELL *));
103 STATIC_PROTO(int   get_heap_info, (void));
104 STATIC_PROTO(int   get_regs, (int));
105 STATIC_PROTO(int   get_insts, (OPCODE []));
106 STATIC_PROTO(int   get_hash, (void));
107 STATIC_PROTO(int   CopyCode, (void));
108 STATIC_PROTO(int   CopyStacks, (void));
109 STATIC_PROTO(int   get_coded, (int, OPCODE []));
110 STATIC_PROTO(void  restore_codes, (void));
111 STATIC_PROTO(Term  AdjustDBTerm, (Term, Term *));
112 STATIC_PROTO(void  RestoreDB, (DBEntry *));
113 STATIC_PROTO(void  RestoreDBTerm, (DBTerm *, int));
114 STATIC_PROTO(void  CleanClauses, (yamop *, yamop *,PredEntry *));
115 STATIC_PROTO(void  rehash, (CELL *, int, int));
116 STATIC_PROTO(void  CleanCode, (PredEntry *));
117 STATIC_PROTO(void  RestoreEntries, (PropEntry *, int));
118 STATIC_PROTO(void  RestoreFreeSpace, (void));
119 STATIC_PROTO(void  restore_heap, (void));
120 #ifdef DEBUG_RESTORE3
121 STATIC_PROTO(void  ShowAtoms, (void));
122 STATIC_PROTO(void  ShowEntries, (PropEntry *));
123 #endif
124 STATIC_PROTO(int   OpenRestore, (char *, char *, CELL *, CELL *, CELL *, CELL *));
125 STATIC_PROTO(void  CloseRestore, (void));
126 #ifndef _WIN32
127 STATIC_PROTO(int  check_opcodes, (OPCODE []));
128 #endif
129 STATIC_PROTO(void  RestoreHeap, (OPCODE []));
130 STATIC_PROTO(Int  p_restore, (void));
131 STATIC_PROTO(void  restore_heap_regs, (void));
132 STATIC_PROTO(void  restore_regs, (int));
133 #ifdef MACYAP
134 STATIC_PROTO(void NewFileInfo, (long, long));
135 extern int      DefVol;
136 #endif
137 
138 #ifdef _WIN32
139 #if HAVE_IO_H
140 #include <io.h>
141 #endif
142 #endif
143 
144 #ifdef LIGHT
145 
146 #include <unix.h>
147 #include <strings.h>
148 
149 void
150 LightBug(char *);
151 
152 static void
LightBug(s)153 LightBug(s)
154 	char           *s;
155 {
156 }
157 
158 #endif				/* LIGHT */
159 
160 static Int
do_system_error(yap_error_number etype,const char * msg)161 do_system_error(yap_error_number etype, const char *msg)
162 {
163 #if HAVE_SNPRINTF
164 #if HAVE_STRERROR
165   snprintf(Yap_ErrorSay,MAX_ERROR_MSG_SIZE,"%s (%s when reading %s)", msg, strerror(errno), Yap_FileNameBuf);
166 #else
167   snprintf(Yap_ErrorSay,MAX_ERROR_MSG_SIZE,"%s, (system error %d when reading %s)",msg,errno,Yap_FileNameBuf);
168 #endif
169 #else
170 #if HAVE_STRERROR
171   sprintf(Yap_ErrorSay,"%s, (%s when reading %s)",msg,strerror(errno),Yap_FileNameBuf);
172 #else
173   sprintf(Yap_ErrorSay,"%s, (system error %d when reading %s)",msg,errno,Yap_FileNameBuf);
174 #endif
175 #endif
176   Yap_ErrorMessage = Yap_ErrorSay;
177   Yap_Error_TYPE = etype;
178   return -1;
179 }
180 
181 
182 inline static
myread(int fd,char * buffer,Int len)183 int myread(int fd, char *buffer, Int len) {
184   ssize_t nread;
185 
186   while (len > 0) {
187     nread = read(fd, buffer,  (int)len);
188     if (nread < 1) {
189       return do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"bad read on saved state");
190     }
191     buffer += nread;
192     len -= nread;
193   }
194   return len;
195 }
196 
197 inline static
198 Int
mywrite(int fd,char * buff,Int len)199 mywrite(int fd, char *buff, Int len) {
200   ssize_t nwritten;
201 
202   while (len > 0) {
203     nwritten = write(fd, buff, (size_t)len);
204     if (nwritten < 0) {
205       return do_system_error(SYSTEM_ERROR,"bad write on saved state");
206     }
207     buff += nwritten;
208     len -= nwritten;
209   }
210   return len;
211 }
212 
213 #define FullSaved		1
214 
215 /* Where the code was before */
216 
217 
218 
219 typedef CELL   *CELLPOINTER;
220 
221 static int      splfild = 0;
222 
223 #ifdef DEBUG
224 
225 #ifdef DEBUG_RESTORE4
226 static FILE    *errout;
227 #else
228 #define errout Yap_stderr
229 #endif
230 
231 #endif				/* DEBUG */
232 
233 static Int      OldHeapUsed;
234 
235 static CELL     which_save;
236 
237 /* Open a file to read or to write */
238 static int
open_file(char * my_file,int flag)239 open_file(char *my_file, int flag)
240 {
241   int splfild;
242 
243 #ifdef M_WILLIAMS
244   if (flag & O_CREAT)
245     splfild = creat(my_file, flag);
246   else
247     splfild = open(my_file, flag);
248   if (splfild < 0) {
249 #else
250 #ifdef O_BINARY
251 #if _MSC_VER
252     if ((splfild = _open(my_file, flag | O_BINARY), _S_IREAD | _S_IWRITE) < 0)
253 #else
254     if ((splfild = open(my_file, flag | O_BINARY, 0775)) < 0)
255 #endif
256 #else  /* O_BINARY */
257     if ((splfild = open(my_file, flag, 0755)) < 0)
258 #endif  /* O_BINARY */
259 #endif 	/* M_WILLIAMS */
260       {
261 	splfild = 0;	/* We do not have an open file */
262 	return -1;
263       }
264 #ifdef undf0
265       fprintf(errout, "Opened file %s\n", my_file);
266 #endif
267       return splfild;
268 }
269 
270 static int
271 close_file(void)
272 {
273   if (splfild == 0)
274     return 0;
275   if (close(splfild) < 0)
276     return do_system_error(SYSTEM_ERROR,"bad close on saved state");
277   splfild = 0;
278   return 1;
279 }
280 
281 /* stores a cell in a file */
282 static Int
283 putout(CELL l)
284 {
285   return mywrite(splfild, (char *) &l, sizeof(CELL));
286 }
287 
288 /* stores a pointer to a cell in a file */
289 static Int
290 putcellptr(CELL *l)
291 {
292   return mywrite(splfild, (char *) &l, sizeof(CELLPOINTER));
293 }
294 
295 /* gets a cell from a file */
296 static CELL
297 get_cell(void)
298 {
299   CELL            l;
300   myread(splfild, (char *) &l, Unsigned(sizeof(CELL)));
301   return (l);
302 }
303 
304 /* gets a cell from a file */
305 static CELL
306 get_header_cell(void)
307 {
308   CELL l;
309   int count = 0, n;
310   while (count < sizeof(CELL)) {
311     if ((n = read(splfild, &l, sizeof(CELL)-count)) < 0) {
312       do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"failed to read saved state header");
313       return 0L;
314     }
315     count += n;
316   }
317   return l;
318 }
319 
320 /* gets a pointer to cell from a file */
321 static CELL    *
322 get_cellptr(void)
323 {
324   CELL           *l;
325 
326   if (myread(splfild, (char *) &l, Unsigned(sizeof(CELLPOINTER))) < 0)
327     return NULL;
328   return (l);
329 }
330 
331 /*
332  * writes the header (at the moment YAPV*), info about what kind of saved
333  * set, the work size, and the space ocuppied
334  */
335 static int
336 put_info(int info, int mode)
337 {
338   char     msg[256];
339 
340   sprintf(msg, "#!/bin/sh\nexec_dir=${YAPBINDIR:-%s}\nexec $exec_dir/yap $0 \"$@\"\n%cYAP-%s", YAP_BINDIR, 1, YAP_SVERSION);
341   if (mywrite(splfild, msg, strlen(msg) + 1))
342     return -1;
343   if (putout(Unsigned(info)) < 0)
344     return -1;
345   /* say whether we just saved the heap or everything */
346   if (putout(mode) < 0)
347     return -1;
348   /* current state of stacks, to be used by SavedInfo */
349   /* space available in heap area */
350   if (putout(Unsigned(Yap_GlobalBase)-Unsigned(Yap_HeapBase)) < 0)
351     return -1;
352   /* space available for stacks */
353   if (putout(Unsigned(Yap_LocalBase)-Unsigned(Yap_GlobalBase)) < 0)
354     return -1;
355   /* space available for trail */
356   if (putout(Unsigned(Yap_TrailTop)-Unsigned(Yap_TrailBase)) < 0)
357     return -1;
358   /* Space used in heap area */
359   if (putout(Unsigned(HeapTop)-Unsigned(Yap_HeapBase)) < 0)
360     return -1;
361   /* Space used for local stack */
362   if (putout(Unsigned(LCL0)-Unsigned(ASP)) < 0)
363     return -1;
364   /* Space used for global stack */
365   if (putout(Unsigned(H) - Unsigned(Yap_GlobalBase)) < 0)
366     return -1;
367   /* Space used for trail */
368   if (putout(Unsigned(TR) - Unsigned(Yap_TrailBase)) < 0)
369     return -1;
370   return 0;
371 }
372 
373 static int
374 save_regs(int mode)
375 {
376   /* save all registers */
377   if (putout((CELL)compile_arrays) < 0)
378     return -1;
379   if (mode == DO_EVERYTHING) {
380     if (putcellptr((CELL *)CP) < 0)
381       return -1;
382     if (putcellptr(ENV) < 0)
383       return -1;
384     if (putcellptr(ASP) < 0)
385       return -1;
386     /* if (putout((CELL)N) < 0)
387        return -1; */
388     if (putcellptr(H0) < 0)
389       return -1;
390     if (putcellptr(LCL0) < 0)
391       return -1;
392     if (putcellptr(H) < 0)
393       return -1;
394     if (putcellptr(HB) < 0)
395       return -1;
396     if (putcellptr((CELL *)B) < 0)
397       return -1;
398     if (putcellptr((CELL *)TR) < 0)
399       return -1;
400     if (putcellptr(YENV) < 0)
401       return -1;
402     if (putcellptr(S) < 0)
403       return -1;
404     if (putcellptr((CELL *)P) < 0)
405       return -1;
406     if (putout(CreepFlag) < 0)
407       return -1;
408     if (putcellptr((CELL *)EX) < 0)
409       return -1;
410 #if defined(SBA) || defined(TABLING)
411     if (putcellptr(H_FZ) < 0)
412       return -1;
413     if (putcellptr((CELL *)B_FZ) < 0)
414       return -1;
415     if (putcellptr((CELL *)TR_FZ) < 0)
416       return -1;
417 #endif /* SBA || TABLING */
418   }
419   if (putout(CurrentModule) < 0)
420     return -1;
421   if (mode == DO_EVERYTHING) {
422 #ifdef COROUTINING
423     if (putout(WokenGoals) < 0)
424       return -1;
425 #endif
426 #ifdef  DEPTH_LIMIT
427     if (putout(DEPTH) < 0)
428       return -1;
429 #endif
430     if (putout(GcGeneration) < 0)
431       return -1;
432     if (putout(GcPhase) < 0)
433       return -1;
434     if (putout(GcCurrentPhase) < 0)
435       return -1;
436   }
437   /* The operand base */
438   if (putcellptr(CellPtr(XREGS)) < 0)
439     return -1;
440   if (putout(which_save) < 0)
441     return -1;
442   /* Now start by saving the code */
443   /* the heap boundaries */
444   if (putcellptr(CellPtr(Yap_HeapBase)) < 0)
445     return -1;
446   if (putcellptr(CellPtr(HeapTop)) < 0)
447     return -1;
448   /* and the space it ocuppies */
449   if (putout(Unsigned(Yap_heap_regs->heap_used)) < 0)
450     return -1;
451   /* Then the start of the free code */
452   if (putcellptr(CellPtr(FreeBlocks)) < 0)
453     return -1;
454   if (putcellptr(CellPtr(AuxBase)) < 0)
455     return -1;
456   if (putcellptr(AuxSp) < 0)
457     return -1;
458   if (putcellptr(CellPtr(AuxTop)) < 0)
459     return -1;
460   if (putcellptr(CellPtr(ScratchPad.ptr)) < 0)
461     return -1;
462   if (putout(ScratchPad.sz) < 0)
463     return -1;
464   if (putout(ScratchPad.msz) < 0)
465     return -1;
466   if (mode == DO_EVERYTHING) {
467     /* put the old trail base, just in case it moves again */
468     if (putout(ARG1) < 0)
469       return -1;
470     if (which_save == 2) {
471       if (putout(ARG2) < 0)
472 	return -1;
473     }
474     if (putcellptr(CellPtr(Yap_TrailBase)) < 0)
475       return -1;
476   }
477   return 0;
478 }
479 
480 static int
481 save_code_info(void)
482 {
483 
484   /* First the instructions */
485   {
486     op_numbers i;
487 
488     OPCODE my_ops[_std_top+1];
489     for (i = _Ystop; i <= _std_top; ++i)
490       my_ops[i] = Yap_opcode(i);
491     if (mywrite(splfild, (char *)my_ops, sizeof(OPCODE)*(_std_top+1)) < 0)
492       return -1;
493   }
494   /* and the current character codes */
495   if (mywrite(splfild, Yap_chtype, NUMBER_OF_CHARS) < 0)
496     return -1;
497   return 0;
498 }
499 
500 static int
501 save_heap(void)
502 {
503 #ifdef USE_SYSTEM_MALLOC
504   return -1;
505 #endif
506   int j;
507   /* Then save the whole heap */
508   Yap_ResetConsultStack();
509   j = Unsigned(HeapTop) - Unsigned(Yap_HeapBase);
510   /* store 10 more cells because of the memory manager */
511   if (mywrite(splfild, (char *) Yap_HeapBase, j) < 0)
512     return -1;
513   return 0;
514 }
515 
516 static int
517 save_stacks(int mode)
518 {
519   int j;
520 
521   switch (mode) {
522   case DO_EVERYTHING:
523     /* Now, go and save the state */
524     /* Save the local stack */
525     j = Unsigned(LCL0) - Unsigned(ASP);
526     if (mywrite(splfild, (char *) ASP, j) < 0)
527       return -1;
528     /* Save the global stack */
529     j = Unsigned(H) - Unsigned(Yap_GlobalBase);
530     if (mywrite(splfild, (char *) Yap_GlobalBase, j) < 0)
531       return -1;
532     /* Save the trail */
533     j = Unsigned(TR) - Unsigned(Yap_TrailBase);
534     if (mywrite(splfild, (char *) Yap_TrailBase, j) < 0)
535       return -1;
536     break;
537   case DO_ONLY_CODE:
538     {
539       tr_fr_ptr tr_ptr = TR;
540       while (tr_ptr != (tr_fr_ptr)Yap_TrailBase) {
541 	CELL val = TrailTerm(tr_ptr-1);
542 	if (IsVarTerm(val)) {
543 	  CELL *d1 = VarOfTerm(val);
544 	  if (d1 < (CELL *)HeapTop) {
545 	    if (putout(val) < 0)
546 	      return -1;
547 	  }
548 	} else if (IsPairTerm(val)) {
549 	  CELL *d1 = RepPair(val);
550 	  if (d1 < (CELL *)HeapTop) {
551 	    if (putout(val) < 0)
552 	      return -1;
553 	  }
554 	}
555 	tr_ptr--;
556       }
557     }
558     if (putcellptr(NULL) < 0)
559       return -1;
560     break;
561   }
562   return 0;
563 }
564 
565 static int
566 save_crc(void)
567 {
568   /* Save a CRC */
569   return mywrite(splfild, end_msg, 256);
570 }
571 
572 static Int
573 do_save(int mode) {
574   Term t1 = Deref(ARG1);
575 
576   if (Yap_HoleSize) {
577     Yap_Error(SYSTEM_ERROR,MkAtomTerm(Yap_LookupAtom(Yap_FileNameBuf)),
578 	      "restore/1: address space has holes of size %ld, cannot save", (long int)Yap_HoleSize);
579     return FALSE;
580   }
581   if (!Yap_GetName(Yap_FileNameBuf, YAP_FILENAME_MAX, t1)) {
582     Yap_Error(TYPE_ERROR_LIST,t1,"save/1");
583     return FALSE;
584   }
585   Yap_CloseStreams(TRUE);
586   if ((splfild = open_file(Yap_FileNameBuf, O_WRONLY | O_CREAT)) < 0) {
587     Yap_Error(SYSTEM_ERROR,MkAtomTerm(Yap_LookupAtom(Yap_FileNameBuf)),
588 	  "restore/1, open(%s)", strerror(errno));
589     return(FALSE);
590   }
591   if (put_info(FullSaved, mode) < 0)
592     return -1;
593   if (save_regs(mode) < 0)
594     return -1;
595   if (save_code_info() < 0)
596     return -1;
597   if (save_heap() < 0)
598     return -1;
599   if (save_stacks(mode) < 0)
600     return -1;
601   if (save_crc() < 0)
602     return -1;
603   close_file();
604   return (TRUE);
605 }
606 
607 /* Saves a complete prolog environment */
608 static Int
609 p_save2(void)
610 {
611   Int res;
612 
613   Term t;
614 #if defined(YAPOR) && !defined(THREADS)
615   if (number_workers != 1) {
616     Yap_Error(SYSTEM_ERROR,TermNil,
617 	       "cannot perform save: more than a worker/thread running");
618     return(FALSE);
619   }
620 #elif defined(THREADS)
621   if (NOfThreads != 1) {
622     Yap_Error(SYSTEM_ERROR,TermNil,
623 	       "cannot perform save: more than a worker/thread running");
624     return(FALSE);
625   }
626 #endif
627   /* avoid double saves */
628   if (IsNonVarTerm(t = Deref(ARG2)))
629     return TRUE;
630   if (!Yap_unify(ARG2,MkIntTerm(1)))
631     return FALSE;
632   which_save = 2;
633   Yap_StartSlots();
634   res = do_save(DO_EVERYTHING);
635   Yap_CloseSlots();
636   return res;
637 }
638 
639 /* Just save the program, not the stacks */
640 static Int
641 p_save_program(void)
642 {
643   which_save = 0;
644   return do_save(DO_ONLY_CODE);
645 }
646 
647 /* Now, to restore the saved code */
648 
649 /* First check out if we are dealing with a valid file */
650 static int
651 check_header(CELL *info, CELL *ATrail, CELL *AStack, CELL *AHeap)
652 {
653   char pp[256];
654   char msg[256];
655   CELL hp_size, gb_size, lc_size, tr_size, mode;
656   int n;
657 
658   /* make sure we always check if there are enough bytes */
659   /* skip the first line */
660   pp[0] = '\0';
661   do {
662     if ((n = read(splfild, pp, 1)) <= 0) {
663       do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"failed to scan first line from saved state");
664       return FAIL_RESTORE;
665     }
666   } while (pp[0] != 1);
667   /* now check the version */
668   sprintf(msg, "YAP-%s", YAP_SVERSION);
669   {
670     int count = 0, n, to_read = Unsigned(strlen(msg) + 1);
671     while (count < to_read) {
672       if ((n = read(splfild, pp, to_read-count)) <= 0) {
673 	do_system_error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,"failed to scan version info from saved state");
674 	return FAIL_RESTORE;
675       }
676       count += n;
677     }
678   }
679   if (strcmp(pp, msg) != 0) {
680     Yap_ErrorMessage = Yap_ErrorSay;
681     strncpy(Yap_ErrorMessage, "saved state ", MAX_ERROR_MSG_SIZE);
682     strncat(Yap_ErrorMessage, Yap_FileNameBuf, MAX_ERROR_MSG_SIZE);
683     strncat(Yap_ErrorMessage, " failed to match version ID", MAX_ERROR_MSG_SIZE);
684     Yap_Error_TYPE = CONSISTENCY_ERROR;
685     return FAIL_RESTORE;
686   }
687   /* check info on header */
688   /* ignore info on saved state */
689   *info = get_header_cell();
690   if (Yap_ErrorMessage)
691      return FAIL_RESTORE;
692   /* check the restore mode */
693   mode = get_header_cell();
694   if (Yap_ErrorMessage)
695      return FAIL_RESTORE;
696   if (mode != DO_EVERYTHING && mode != DO_ONLY_CODE) {
697     return FAIL_RESTORE;
698   }
699   /* ignore info on stacks size */
700   *AHeap = get_header_cell();
701   if (Yap_ErrorMessage) {
702      return FAIL_RESTORE;
703   }
704   *AStack = get_header_cell();
705   if (Yap_ErrorMessage) {
706      return FAIL_RESTORE;
707   }
708   *ATrail = get_header_cell();
709   if (Yap_ErrorMessage) {
710      return FAIL_RESTORE;
711   }
712   /* now, check whether we got enough enough space to load the
713      saved space */
714   hp_size = get_cell();
715   if (Yap_ErrorMessage)
716      return FAIL_RESTORE;
717   while (Yap_HeapBase != NULL &&
718 	 hp_size > Unsigned(HeapLim) - Unsigned(Yap_HeapBase)) {
719     if(!Yap_growheap(FALSE, hp_size, NULL)) {
720       return FAIL_RESTORE;
721     }
722   }
723   if (mode == DO_EVERYTHING) {
724     lc_size = get_cell();
725     if (Yap_ErrorMessage)
726       return FAIL_RESTORE;
727     gb_size=get_cell();
728     if (Yap_ErrorMessage)
729       return FAIL_RESTORE;
730     if (Yap_HeapBase != NULL && lc_size+gb_size > Unsigned(Yap_LocalBase) - Unsigned(Yap_GlobalBase)) {
731       if (Yap_ErrorMessage != NULL)
732 	Yap_ErrorMessage = "could not allocate enough stack space";
733       return FAIL_RESTORE;
734     }
735     if (Yap_HeapBase != NULL && (tr_size = get_cell()) > Unsigned(Yap_TrailTop) - Unsigned(Yap_TrailBase)) {
736       if (Yap_ErrorMessage != NULL)
737 	Yap_ErrorMessage = "could not allocate enough trail space";
738       return FAIL_RESTORE;
739     }
740   } else {
741     /* skip cell size */
742     get_header_cell();
743     if (Yap_ErrorMessage)
744       return FAIL_RESTORE;
745     get_header_cell();
746     if (Yap_ErrorMessage)
747       return FAIL_RESTORE;
748     get_header_cell();
749     if (Yap_ErrorMessage)
750       return FAIL_RESTORE;
751   }
752   return(mode);
753 }
754 
755 /* Gets the state of the heap, and evaluates the related variables */
756 static int
757 get_heap_info(void)
758 {
759   OldHeapBase = (ADDR) get_cellptr();
760   if (Yap_ErrorMessage)
761       return -1;
762   OldHeapTop = (ADDR) get_cellptr();
763 
764   if (Yap_ErrorMessage)
765       return -1;
766   OldHeapUsed = (Int) get_cell();
767   if (Yap_ErrorMessage)
768       return -1;
769   FreeBlocks = (BlockHeader *) get_cellptr();
770   if (Yap_ErrorMessage)
771       return -1;
772   AuxBase = (ADDR)get_cellptr();
773   if (Yap_ErrorMessage)
774       return -1;
775   AuxSp = get_cellptr();
776   if (Yap_ErrorMessage)
777       return -1;
778   AuxTop = (ADDR)get_cellptr();
779   if (Yap_ErrorMessage)
780       return -1;
781   ScratchPad.ptr = (ADDR)get_cellptr();
782   if (Yap_ErrorMessage)
783       return -1;
784   ScratchPad.sz = get_cell();
785   if (Yap_ErrorMessage)
786       return -1;
787   ScratchPad.msz = get_cell();
788   if (Yap_ErrorMessage)
789       return -1;
790   HDiff = Unsigned(Yap_HeapBase) - Unsigned(OldHeapBase);
791   return 1;
792 }
793 
794 /* Gets the register array */
795 /* Saves the old bases for the work areas */
796 /* and evaluates the difference from the old areas to the new ones */
797 static int
798 get_regs(int flag)
799 {
800   CELL           *NewGlobalBase = (CELL *)Yap_GlobalBase;
801   CELL           *NewLCL0 = LCL0;
802   CELL           *OldXREGS;
803 
804   /* Get regs */
805   compile_arrays = (int)get_cell();
806   if (Yap_ErrorMessage)
807       return -1;
808   if (flag == DO_EVERYTHING) {
809     CP = (yamop *)get_cellptr();
810     if (Yap_ErrorMessage)
811       return -1;
812     ENV = get_cellptr();
813     if (Yap_ErrorMessage)
814       return -1;
815     ASP = get_cellptr();
816     if (Yap_ErrorMessage)
817       return -1;
818     /* N = get_cell(); */
819     H0 = get_cellptr();
820     if (Yap_ErrorMessage)
821       return -1;
822     LCL0 = get_cellptr();
823     if (Yap_ErrorMessage)
824       return -1;
825     H = get_cellptr();
826     if (Yap_ErrorMessage)
827       return -1;
828     HB = get_cellptr();
829     if (Yap_ErrorMessage)
830       return -1;
831     B = (choiceptr)get_cellptr();
832     if (Yap_ErrorMessage)
833       return -1;
834     TR = (tr_fr_ptr)get_cellptr();
835     if (Yap_ErrorMessage)
836       return -1;
837     YENV = get_cellptr();
838     if (Yap_ErrorMessage)
839       return -1;
840     S = get_cellptr();
841     if (Yap_ErrorMessage)
842       return -1;
843     P = (yamop *)get_cellptr();
844     if (Yap_ErrorMessage)
845       return -1;
846     CreepFlag = get_cell();
847     if (Yap_ErrorMessage)
848       return -1;
849     EX = (struct DB_TERM *)get_cellptr();
850     if (Yap_ErrorMessage)
851       return -1;
852 #if defined(SBA) || defined(TABLING)
853     H_FZ = get_cellptr();
854     if (Yap_ErrorMessage)
855       return -1;
856     B_FZ = (choiceptr)get_cellptr();
857     if (Yap_ErrorMessage)
858       return -1;
859     TR_FZ = (tr_fr_ptr)get_cellptr();
860     if (Yap_ErrorMessage)
861       return -1;
862 #endif /* SBA || TABLING */
863   }
864   CurrentModule = get_cell();
865     if (Yap_ErrorMessage)
866       return -1;
867   if (flag == DO_EVERYTHING) {
868 #ifdef COROUTINING
869     WokenGoals = get_cell();
870     if (Yap_ErrorMessage)
871       return -1;
872 #endif
873 #ifdef  DEPTH_LIMIT
874     DEPTH = get_cell();
875     if (Yap_ErrorMessage)
876       return -1;
877 #endif
878     GcGeneration = get_cell();
879     if (Yap_ErrorMessage)
880       return -1;
881     GcPhase = get_cell();
882     if (Yap_ErrorMessage)
883       return -1;
884     GcCurrentPhase = get_cell();
885     if (Yap_ErrorMessage)
886       return -1;
887   }
888   /* Get the old bases */
889   OldXREGS = get_cellptr();
890   if (Yap_ErrorMessage)
891     return -1;
892   which_save = get_cell();
893   if (Yap_ErrorMessage)
894     return -1;
895   XDiff =  (CELL)XREGS - (CELL)OldXREGS;
896   if (Yap_ErrorMessage)
897     return -1;
898   if (get_heap_info() < 0)
899     return -1;
900   if (flag == DO_EVERYTHING) {
901     ARG1 = get_cell();
902     if (Yap_ErrorMessage)
903       return -1;
904     if (which_save == 2) {
905       ARG2 = get_cell();
906       if (Yap_ErrorMessage)
907 	return -1;
908     }
909     /* get old trail base */
910     OldTrailBase = (ADDR)get_cellptr();
911     if (Yap_ErrorMessage)
912       return -1;
913     /* Save the old register where we can easily access them */
914     OldASP = ASP;
915     OldLCL0 = LCL0;
916     OldGlobalBase = (CELL *)Yap_GlobalBase;
917     OldH = H;
918     OldTR = TR;
919     GDiff = Unsigned(NewGlobalBase) - Unsigned(Yap_GlobalBase);
920     GDiff0 = 0;
921     LDiff = Unsigned(NewLCL0) - Unsigned(LCL0);
922     TrDiff = LDiff;
923     Yap_GlobalBase = (ADDR)NewGlobalBase;
924     LCL0 = NewLCL0;
925   }
926   return 1;
927 }
928 
929 /* Get the old opcodes and place them in a hash table */
930 static int
931 get_insts(OPCODE old_ops[])
932 {
933   return myread(splfild, (char *)old_ops, sizeof(OPCODE)*(_std_top+1));
934 }
935 
936 /* Get the old atoms hash table */
937 static int
938 get_hash(void)
939 {
940   return myread(splfild, Yap_chtype , NUMBER_OF_CHARS);
941 }
942 
943 /* Copy all of the old code to the new Heap */
944 static int
945 CopyCode(void)
946 {
947   if (myread(splfild, (char *) Yap_HeapBase, (Unsigned(OldHeapTop) - Unsigned(OldHeapBase))) < 0) {
948     return -1;
949   }
950   return 1;
951 }
952 
953 /* Copy the local and global stack and also the trail to their new home */
954 /* In REGS we still have nonadjusted values !! */
955 static int
956 CopyStacks(void)
957 {
958   Int             j;
959   char           *NewASP;
960 
961   j = Unsigned(OldLCL0) - Unsigned(ASP);
962   NewASP = (char *) (Unsigned(ASP) + (Unsigned(LCL0) - Unsigned(OldLCL0)));
963   if (myread(splfild, (char *) NewASP, j) < 0)
964     return -1;
965   j = Unsigned(H) - Unsigned(OldGlobalBase);
966   if (myread(splfild, (char *) Yap_GlobalBase, j) < 0)
967     return -1;
968   j = Unsigned(TR) - Unsigned(OldTrailBase);
969   if (myread(splfild, Yap_TrailBase, j))
970     return -1;
971   return 1;
972 }
973 
974 /* Copy the local and global stack and also the trail to their new home */
975 /* In REGS we still have nonadjusted values !! */
976 static int
977 CopyTrailEntries(void)
978 {
979   CELL           entry, *Entries;
980 
981   Entries = (CELL *)Yap_TrailBase;
982   do {
983     *Entries++ = entry = get_cell();
984     if (Yap_ErrorMessage)
985       return -1;
986   } while ((CODEADDR)entry != NULL);
987   return 1;
988 }
989 
990 /* get things which are saved in the file */
991 static int
992 get_coded(int flag, OPCODE old_ops[])
993 {
994   char my_end_msg[256];
995 
996   if (get_regs(flag) < 0)
997     return -1;
998   if (get_insts(old_ops) < 0)
999     return -1;
1000   if (get_hash() < 0)
1001     return -1;
1002   if (CopyCode() < 0)
1003     return -1;
1004   switch (flag) {
1005   case DO_EVERYTHING:
1006     if (CopyStacks() < 0)
1007       return -1;
1008     break;
1009   case DO_ONLY_CODE:
1010     if (CopyTrailEntries() < 0)
1011       return -1;
1012     break;
1013   }
1014   /* Check CRC */
1015   if (myread(splfild, my_end_msg, 256) < 0)
1016     return -1;
1017   if (strcmp(end_msg,my_end_msg) != 0) {
1018     Yap_ErrorMessage = "bad trailing CRC in saved state";
1019     return -1;
1020   }
1021   return 1;
1022 }
1023 
1024 /* restore some heap registers */
1025 static void
1026 restore_heap_regs(void)
1027 {
1028   if (HeapTop) {
1029     HeapTop = AddrAdjust(HeapTop);
1030     *((YAP_SEG_SIZE *) HeapTop) = InUseFlag;
1031   }
1032   HeapMax = Yap_heap_regs->heap_used = OldHeapUsed;
1033   HeapLim = Yap_GlobalBase;
1034 }
1035 
1036 /* adjust abstract machine registers */
1037 static void
1038 restore_regs(int flag)
1039 {
1040   restore_heap_regs();
1041   if (CurrentModule) {
1042     CurrentModule = AtomTermAdjust(CurrentModule);;
1043   }
1044   if (flag == DO_EVERYTHING) {
1045     CP = PtoOpAdjust(CP);
1046     ENV = PtoLocAdjust(ENV);
1047     ASP = PtoLocAdjust(ASP);
1048     H = PtoGloAdjust(H);
1049     B = (choiceptr)PtoLocAdjust(CellPtr(B));
1050     TR = PtoTRAdjust(TR);
1051     P = PtoOpAdjust(P);
1052     HB = PtoLocAdjust(HB);
1053     YENV = PtoLocAdjust(YENV);
1054     S = PtoGloAdjust(S);
1055     if (EX) {
1056       EX = DBTermAdjust(EX);
1057       RestoreDBTerm(EX, TRUE);
1058     }
1059     WokenGoals = AbsAppl(PtoGloAdjust(RepAppl(WokenGoals)));
1060   }
1061 }
1062 
1063 static void
1064 recompute_mask(DBRef dbr)
1065 {
1066   if (dbr->Flags & DBNoVars) {
1067     dbr->Mask = Yap_EvalMasks((Term) dbr->DBT.Entry, &(dbr->Key));
1068   } else if (dbr->Flags & DBComplex) {
1069     /* This is quite nasty, we want to recalculate the mask but
1070        we don't want to rebuild the whole term. We'll just build whatever we
1071        need to recompute the mask.
1072     */
1073     CELL *x = (CELL *)HeapTop, *tp;
1074     unsigned int Arity, i;
1075     Term out;
1076     char *tbase = CharP(dbr->DBT.Contents-1);
1077 
1078     if (IsPairTerm(dbr->DBT.Entry)) {
1079 
1080       out = AbsPair(x);
1081       Arity = 2;
1082       tp = (CELL *)(tbase + (CELL) RepPair(dbr->DBT.Entry));
1083     } else {
1084       Functor f;
1085 
1086       tp = (CELL *)(tbase + (CELL) RepAppl(dbr->DBT.Entry));
1087       f = (Functor)(*tp++);
1088       out = AbsAppl(x);
1089       Arity = ArityOfFunctor(f);
1090       *x++ = (CELL)f;
1091       if (Arity > 3) Arity = 3;
1092     }
1093     for (i = 0; i < Arity; i++) {
1094       register Term   tw = *tp++;
1095       if (IsVarTerm(tw)) {
1096 	RESET_VARIABLE(x);
1097       } else if (IsApplTerm(tw)) {
1098 	/* just fetch the functor from where it is in the data-base.
1099 	   This guarantees we have access to references and friends. */
1100 	CELL offset = (CELL)RepAppl(tw);
1101 	if (offset > dbr->DBT.NOfCells*sizeof(CELL))
1102 	  *x = tw;
1103 	else
1104 	  *x = AbsAppl((CELL *)(tbase + offset));
1105       } else if (IsAtomicTerm(tw)) {
1106 	*x = tw;
1107       } else if (IsPairTerm(tw)) {
1108 	*x = AbsPair(x);
1109       }
1110       x++;
1111     }
1112     dbr->Mask = Yap_EvalMasks(out, &(dbr->Key));
1113   }
1114 }
1115 
1116 #define HASH_SHIFT 6
1117 
1118 /*
1119  * This is used to make an hash table correct, after displacing its elements,
1120  * HCEnd should point to an area of free space, usually in the heap. The
1121  * routine is very dependent on the hash function used, and it destroys the
1122  * previous "hit" order
1123  */
1124 static void
1125 rehash(CELL *oldcode, int NOfE, int KindOfEntries)
1126 {
1127   register CELL  *savep, *basep;
1128   CELL           *oldp = oldcode;
1129   int             TableSize = NOfE - 1, NOfEntries;
1130   register int    i;
1131   int             hash;
1132   CELL            WorkTerm, failplace = 0;
1133   CELL           *Base = oldcode;
1134 
1135   if (HDiff == 0)
1136       return;
1137   basep = H;
1138   if (H + (NOfE*2) > ASP) {
1139     basep = (CELL *)TR;
1140     if (basep + (NOfE*2) > (CELL *)Yap_TrailTop) {
1141       if (!Yap_growtrail((ADDR)(basep + (NOfE*2))-Yap_TrailTop, TRUE)) {
1142 	Yap_Error(OUT_OF_TRAIL_ERROR, TermNil,
1143 	      "not enough space to restore hash tables for indexing");
1144 	Yap_exit(1);
1145       }
1146     }
1147   }
1148   for (i = 0; i < NOfE; ++i) {
1149     if (*oldp == 0) {
1150       failplace = oldp[1];
1151       break;
1152     }
1153     oldp += 2;
1154   }
1155   savep = basep;
1156   oldp = oldcode;
1157   for (i = 0; i < NOfE; ++i) {
1158     if (*oldp != 0) {
1159       savep[0] = oldp[0];
1160       savep[1] = oldp[1];
1161       oldp[0] = 0;
1162       oldp[1] = failplace;
1163       savep += 2;
1164     }
1165     oldp += 2;
1166   }
1167   NOfEntries = (savep - basep)/2;
1168   savep = basep;
1169   for (i = 0; i < NOfEntries; ++i) {
1170     register Int    d;
1171     CELL *hentry;
1172 
1173     WorkTerm = savep[i*2];
1174     hash = (Unsigned(WorkTerm) >> HASH_SHIFT) & TableSize;
1175     hentry = Base + hash * 2;
1176     d = TableSize & (Unsigned(WorkTerm) | 1);
1177     while (*hentry) {
1178 #ifdef DEBUG
1179 #ifdef CLASHES
1180       ++clashes;
1181 #endif /* CLASHES */
1182 #endif /* DEBUG */
1183       hash = (hash + d) & TableSize;
1184       hentry = Base + hash * 2;
1185     }
1186     hentry[0] = WorkTerm;
1187     hentry[1] = savep[i*2+1];
1188   }
1189 }
1190 
1191 static void
1192 RestoreSWIHash(void)
1193 {
1194   Yap_InitSWIHash();
1195 }
1196 
1197 
1198 #include "rheap.h"
1199 
1200 /* restore the atom entries which are invisible for the user */
1201 static void
1202 RestoreIOStructures(void)
1203 {
1204   Yap_InitStdStreams();
1205 }
1206 
1207 static void
1208 RestoreFreeSpace(void)
1209 {
1210 #if USE_DL_MALLOC
1211   Yap_av = (struct malloc_state *)AddrAdjust((ADDR)Yap_av);
1212   Yap_RestoreDLMalloc();
1213   if (AuxSp != NULL) {
1214     if (AuxBase < OldHeapBase || AuxBase > OldHeapTop) {
1215       AuxSp = NULL;
1216       AuxBase = NULL;
1217       AuxTop = NULL;
1218     } else {
1219       AuxSp = PtoHeapCellAdjust(AuxSp);
1220       AuxBase = AddrAdjust(AuxBase);
1221       AuxTop = AddrAdjust(AuxTop);
1222       ScratchPad.ptr = AddrAdjust(ScratchPad.ptr);
1223     }
1224   }
1225 #else
1226   /* restores the list of free space, with its curious structure */
1227   BlockHeader *bpt, *bsz;
1228 
1229   if (FreeBlocks != NULL)
1230     FreeBlocks = BlockAdjust(FreeBlocks);
1231   bpt = FreeBlocks;
1232   if (AuxSp != NULL)
1233     AuxSp = CellPtoHeapAdjust(AuxSp);
1234   if (AuxTop != NULL)
1235     AuxTop = AddrAdjust(AuxTop);
1236   while (bpt != NULL) {
1237     if (bpt->b_next != NULL) {
1238       bsz = bpt->b_next = BlockAdjust(bpt->b_next);
1239       while (bsz != NULL) {
1240 	if (bsz->b_next_size != NULL)
1241 	  bsz->b_next_size = BlockAdjust(bsz->b_next_size);
1242 	if (bsz->b_next != NULL)
1243 	  bsz->b_next = BlockAdjust(bsz->b_next);
1244 	bsz = bsz->b_next;
1245       }
1246     }
1247     if (bpt->b_next_size != NULL)
1248       bpt->b_next_size = BlockAdjust(bpt->b_next_size);
1249     bpt = bpt->b_next_size;
1250   }
1251   *((YAP_SEG_SIZE *) HeapTop) = InUseFlag;
1252 #endif
1253 }
1254 
1255 static void
1256 RestoreAtomList(Atom atm)
1257 {
1258   AtomEntry      *at;
1259 
1260   at = RepAtom(atm);
1261   if (EndOfPAEntr(at))
1262     return;
1263   do {
1264     RestoreAtom(at);
1265     at = RepAtom(at->NextOfAE);
1266   } while (!EndOfPAEntr(at));
1267 }
1268 
1269 
1270 static void
1271 RestoreHashPreds(void)
1272 {
1273   UInt size = PredHashTableSize;
1274   int malloced = FALSE;
1275   PredEntry **np;
1276   UInt i;
1277   PredEntry **oldp = PredHash;
1278 
1279   np = (PredEntry **) Yap_AllocAtomSpace(sizeof(PredEntry **)*size);
1280   if (!np) {
1281     if (!(np = (PredEntry **) malloc(sizeof(PredEntry **)*size))) {
1282 	Yap_Error(FATAL_ERROR,TermNil,"Could not allocate space for pred table");
1283 	return;
1284       }
1285     malloced = TRUE;
1286   }
1287   for (i = 0; i < size; i++) {
1288     np[i] = NULL;
1289   }
1290   for (i = 0; i < PredHashTableSize; i++) {
1291     PredEntry *p = oldp[i];
1292 
1293     if (p)
1294       p = PredEntryAdjust(p);
1295     while (p) {
1296       Prop nextp;
1297       UInt hsh;
1298 
1299       if (p->NextOfPE)
1300 	p->NextOfPE = PropAdjust(p->NextOfPE);
1301       nextp = p->NextOfPE;
1302       CleanCode(p);
1303       hsh = PRED_HASH(p->FunctorOfPred, p->ModuleOfPred, size);
1304       p->NextOfPE = AbsPredProp(np[hsh]);
1305       np[hsh] = p;
1306       p = RepPredProp(nextp);
1307     }
1308   }
1309   for (i = 0; i < size; i++) {
1310     PredHash[i] = np[i];
1311   }
1312   if (malloced)
1313     free((ADDR)np);
1314   else
1315     Yap_FreeAtomSpace((ADDR)np);
1316 }
1317 
1318 /*
1319  * This is the really tough part, to restore the whole of the heap
1320  */
1321 static void
1322 restore_heap(void)
1323 {
1324   restore_codes();
1325   RestoreIOStructures();
1326 }
1327 
1328 
1329 #ifdef DEBUG_RESTORE3
1330 static void
1331 ShowEntries(pp)
1332 	PropEntry      *pp;
1333 {
1334   while (!EndOfPAEntr(pp)) {
1335     fprintf(Yap_stderr,"Estou a ver a prop %x em %x\n", pp->KindOfPE, pp);
1336     pp = RepProp(pp->NextOfPE);
1337   }
1338 }
1339 
1340 static void
1341 ShowAtoms()
1342 {
1343   AtomHashEntry  *HashPtr = HashChain;
1344   register int    i;
1345   for (i = 0; i < AtomHashTableSize; ++i) {
1346     if (HashPtr->Entry != NIL) {
1347       AtomEntry      *at;
1348       at = RepAtom(HashPtr->Entry);
1349       do {
1350 	fprintf(Yap_stderr,"Passei ao %s em %x\n", at->StrOfAE, at);
1351 	ShowEntries(RepProp(at->PropsOfAE));
1352       } while (!EndOfPAEntr(at = RepAtom(at->NextOfAE)));
1353     }
1354     HashPtr++;
1355   }
1356   HashPtr = WideHashChain;
1357   for (i = 0; i < WideAtomHashTableSize; ++i) {
1358     if (HashPtr->Entry != NIL) {
1359       AtomEntry      *at;
1360       at = RepAtom(HashPtr->Entry);
1361       do {
1362 	fprintf(Yap_stderr,"Passei ao %s em %x\n", at->StrOfAE, at);
1363 	ShowEntries(RepProp(at->PropsOfAE));
1364       } while (!EndOfPAEntr(at = RepAtom(at->NextOfAE)));
1365     }
1366     HashPtr++;
1367   }
1368 }
1369 
1370 #endif /* DEBUG_RESTORE3 */
1371 
1372 #include <stdio.h>
1373 
1374 static int
1375 commit_to_saved_state(char *s, CELL *Astate, CELL *ATrail, CELL *AStack, CELL *AHeap) {
1376   int mode;
1377 
1378   if ((mode = check_header(Astate,ATrail,AStack,AHeap)) == FAIL_RESTORE)
1379     return(FAIL_RESTORE);
1380   Yap_PrologMode = BootMode;
1381   if (Yap_HeapBase) {
1382     if (!yap_flags[HALT_AFTER_CONSULT_FLAG] && !yap_flags[QUIET_MODE_FLAG]) {
1383       Yap_TrueFileName(s,Yap_FileNameBuf2, YAP_FILENAME_MAX);
1384       fprintf(stderr, "%% Restoring file %s\n", Yap_FileNameBuf2);
1385     }
1386     Yap_CloseStreams(TRUE);
1387   }
1388 #ifdef DEBUG_RESTORE4
1389   /*
1390    * This should be another file, like the log file
1391    */
1392   errout = Yap_stderr;
1393 #endif
1394   return mode;
1395 }
1396 
1397 static void
1398 cat_file_name(char *s, char *prefix, char *name, unsigned int max_length)
1399 {
1400   strncpy(s, prefix, max_length);
1401 #if _MSC_VER || defined(__MINGW32__)
1402   strncat(s,"\\", max_length);
1403 #else
1404   strncat(s,"/", max_length);
1405 #endif
1406   strncat(s, name, max_length-1);
1407 }
1408 
1409 static int try_open(char *inpf, CELL *Astate, CELL *ATrail, CELL *AStack, CELL *AHeap, char *buf) {
1410   int mode;
1411 
1412 
1413   if ((splfild = open_file(inpf, O_RDONLY)) < 0) {
1414     return FAIL_RESTORE;
1415   }
1416   if (buf[0] == '\0')
1417     strncpy(buf, inpf, YAP_FILENAME_MAX);
1418   if ((mode = commit_to_saved_state(inpf,Astate,ATrail,AStack,AHeap)) != FAIL_RESTORE) {
1419     Yap_ErrorMessage = NULL;
1420     return mode;
1421   }
1422   return mode;
1423 }
1424 
1425 static int
1426 OpenRestore(char *inpf, char *YapLibDir, CELL *Astate, CELL *ATrail, CELL *AStack, CELL *AHeap)
1427 {
1428   int mode = FAIL_RESTORE;
1429   char save_buffer[YAP_FILENAME_MAX+1];
1430 
1431   //  Yap_ErrorMessage = NULL;
1432   if (inpf == NULL) {
1433 #if _MSC_VER || defined(__MINGW32__)
1434     if (!(inpf = Yap_RegistryGetString("startup")))
1435 #endif
1436       inpf = StartUpFile;
1437   }
1438   /* careful it starts from the root */
1439   if (inpf[0] != '/') {
1440 #if __simplescalar__
1441     /* does not implement getcwd */
1442     strncpy(Yap_FileNameBuf,yap_pwd,YAP_FILENAME_MAX);
1443 #elif HAVE_GETCWD
1444     if (getcwd (Yap_FileNameBuf, YAP_FILENAME_MAX) == NULL)
1445       Yap_FileNameBuf[0] = '\0';
1446 #else
1447     if (getwd (Yap_FileNameBuf) == NULL)
1448       Yap_FileNameBuf[0] = '\0';
1449 #endif
1450     strncat(Yap_FileNameBuf, "/", YAP_FILENAME_MAX-1);
1451     strncat(Yap_FileNameBuf, inpf, YAP_FILENAME_MAX-1);
1452   } else {
1453     strncat(Yap_FileNameBuf, inpf, YAP_FILENAME_MAX-1);
1454   }
1455   if (inpf != NULL && (splfild = open_file(inpf, O_RDONLY)) > 0) {
1456     if ((mode = try_open(inpf,Astate,ATrail,AStack,AHeap,save_buffer)) != FAIL_RESTORE) {
1457       return mode;
1458     }
1459   }
1460   if (!Yap_dir_separator(inpf[0]) && !Yap_volume_header(inpf)) {
1461     /*
1462       we have a relative path for the file, try to do somewhat better
1463       using YAPLIBDIR or friends.
1464     */
1465     if (YapLibDir != NULL) {
1466       cat_file_name(Yap_FileNameBuf, Yap_LibDir, inpf, YAP_FILENAME_MAX);
1467       if ((mode = try_open(Yap_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer)) != FAIL_RESTORE) {
1468 	return mode;
1469       }
1470     } else {
1471       if ((mode = try_open(Yap_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer)) != FAIL_RESTORE) {
1472 	return mode;
1473       }
1474     }
1475 #if HAVE_GETENV
1476     {
1477       char *yap_env = getenv("YAPLIBDIR");
1478       if (yap_env != NULL) {
1479 	cat_file_name(Yap_FileNameBuf, yap_env, inpf, YAP_FILENAME_MAX);
1480 	if ((mode = try_open(Yap_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer)) != FAIL_RESTORE) {
1481 	  return mode;
1482 	}
1483       }
1484     }
1485 #endif
1486     if (YAP_LIBDIR != NULL) {
1487       cat_file_name(Yap_FileNameBuf, YAP_LIBDIR, inpf, YAP_FILENAME_MAX);
1488       if ((splfild = open_file(Yap_FileNameBuf, O_RDONLY)) > 0) {
1489 	if ((mode = try_open(Yap_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer)) != FAIL_RESTORE) {
1490 	  return mode;
1491 	}
1492       }
1493     }
1494   }
1495 #if _MSC_VER || defined(__MINGW32__)
1496   {
1497     DWORD fatts;
1498     int buflen;
1499     char *pt;
1500 
1501     /* try to get it from current executable */
1502     if ((fatts = GetFileAttributes(Yap_FileNameBuf)) == 0xFFFFFFFFL ||
1503 	!(fatts & FILE_ATTRIBUTE_DIRECTORY)) {
1504       /* couldn't find it where it was supposed to be,
1505 	 let's try using the executable */
1506       if (!GetModuleFileNameEx( GetCurrentProcess(), NULL, Yap_FileNameBuf, YAP_FILENAME_MAX)) {
1507 	/* do nothing */
1508 	goto end;
1509       }
1510       buflen = strlen(Yap_FileNameBuf);
1511       pt = Yap_FileNameBuf+strlen(Yap_FileNameBuf);
1512       while (*--pt != '\\') {
1513 	/* skip executable */
1514 	if (pt == Yap_FileNameBuf) {
1515 	  /* do nothing */
1516 	  goto end;
1517 	}
1518       }
1519       while (*--pt != '\\') {
1520 	/* skip parent directory "bin\\" */
1521 	if (pt == Yap_FileNameBuf) {
1522 	  goto end;
1523 	}
1524       }
1525       /* now, this is a possible location for the ROOT_DIR, let's look for a share directory here */
1526       pt[1] = '\0';
1527       strncat(Yap_FileNameBuf,"lib/Yap/startup.yss",YAP_FILENAME_MAX);
1528     }
1529     if ((mode = try_open(Yap_FileNameBuf,Astate,ATrail,AStack,AHeap,save_buffer)) != FAIL_RESTORE) {
1530       return mode;
1531     }
1532   }
1533  end:
1534 #endif
1535   /* try to open from current directory */
1536   /* could not open file */
1537   if (Yap_ErrorMessage == NULL) {
1538     if (save_buffer[0]) {
1539       strncpy(Yap_FileNameBuf, save_buffer, YAP_FILENAME_MAX-1);
1540       do_system_error(PERMISSION_ERROR_OPEN_SOURCE_SINK,"incorrect saved state");
1541     } else {
1542       strncpy(Yap_FileNameBuf, inpf, YAP_FILENAME_MAX-1);
1543       do_system_error(PERMISSION_ERROR_OPEN_SOURCE_SINK,"could not open saved state");
1544     }
1545   }
1546   return FAIL_RESTORE;
1547 }
1548 
1549 static void
1550 CloseRestore(void)
1551 {
1552 #ifdef DEBUG_RESTORE3
1553   ShowAtoms();
1554 #endif
1555   close_file();
1556   Yap_PrologMode = UserMode;
1557 }
1558 
1559 #if !defined(_WIN32)
1560 static int
1561 check_opcodes(OPCODE old_ops[])
1562 {
1563 #if USE_THREADED_CODE
1564   int have_shifted = FALSE;
1565   op_numbers op = _Ystop;
1566   for (op = _Ystop; op < _std_top; op++) {
1567     if (Yap_opcode(op) != old_ops[op]) {
1568       have_shifted = TRUE;
1569       break;
1570     }
1571   }
1572   return have_shifted;
1573 #else
1574   /* be conservative */
1575   return TRUE;
1576 #endif
1577 }
1578 #endif
1579 
1580 static void
1581 RestoreHeap(OPCODE old_ops[])
1582 {
1583   int heap_moved = (OldHeapBase != Yap_HeapBase ||
1584 		    XDiff), opcodes_moved;
1585   Term mod = CurrentModule;
1586 
1587   CurrentModule = PROLOG_MODULE;
1588 #if defined(_WIN32)
1589   /* It seems that under WIN32 opcodes may not have moved but the
1590      remaining code may have bmoved */
1591   opcodes_moved = TRUE;
1592 #else
1593   opcodes_moved = check_opcodes(old_ops);
1594 #endif
1595   /* opcodes_moved has side-effects and should be tried first */
1596   if (heap_moved) {
1597     opcodes_moved = TRUE;
1598     RestoreFreeSpace();
1599   }
1600   if (heap_moved || opcodes_moved) {
1601     restore_heap();
1602   }
1603   /* This must be done after restore_heap */
1604   Yap_InitAbsmi();
1605   if (opcodes_moved) {
1606     Yap_InitCPreds();
1607     Yap_InitBackCPreds();
1608   }
1609   if (!(Yap_ReInitConstExps() &&
1610 	Yap_ReInitUnaryExps() &&
1611 	Yap_ReInitBinaryExps())) {
1612     Yap_Error(SYSTEM_ERROR, TermNil, "arithmetic operator not in saved state");
1613   }
1614 #ifdef DEBUG_RESTORE1
1615   fprintf(errout, "phase 1 done\n");
1616 #endif
1617   CurrentModule = mod;
1618 }
1619 
1620 /*
1621  * This function is called to know about the parameters of the last saved
1622  * state
1623  */
1624 int
1625 Yap_SavedInfo(char *FileName, char *YapLibDir, CELL *ATrail, CELL *AStack, CELL *AHeap)
1626 {
1627   CELL MyTrail, MyStack, MyHeap, MyState;
1628   int             mode;
1629 
1630   mode = OpenRestore(FileName, YapLibDir, &MyState, &MyTrail, &MyStack, &MyHeap);
1631   if (mode == FAIL_RESTORE) {
1632     return -1;
1633   }
1634   close_file();
1635   if (! *AHeap)
1636     *AHeap = MyHeap / 1024;
1637   if (mode != DO_ONLY_CODE && *AStack)
1638     *AStack = MyStack / 1024;
1639   if (mode != DO_ONLY_CODE && *ATrail)
1640     *ATrail = MyTrail / 1024;
1641   return (MyState);
1642 }
1643 
1644 static void
1645 UnmarkTrEntries(void)
1646 {
1647   CELL           entry, *Entries;
1648 
1649   /* initialise a choice point */
1650   B = (choiceptr)LCL0;
1651   B--;
1652   B->cp_ap = NOCODE;
1653   Entries = (CELL *)Yap_TrailBase;
1654   while ((entry = *Entries++) != (CELL)NULL) {
1655     if (!IsVarTerm(entry)) {
1656       if(IsPairTerm(entry)) {
1657 	CELL *ent = CellPtoHeapAdjust(RepPair(entry));
1658 	register CELL flags;
1659 
1660 	flags = *ent;
1661 	ResetFlag(InUseMask, flags);
1662 	*ent = flags;
1663 	if (FlagOn((DirtyMask|ErasedMask), flags)) {
1664 	  if (FlagOn(DBClMask, flags)) {
1665 	    Yap_ErDBE(DBStructFlagsToDBStruct(ent));
1666 	  } else {
1667 	    if (flags & LogUpdMask) {
1668 	      if (flags & IndexMask) {
1669 		if (FlagOn(ErasedMask, flags))
1670 		  Yap_ErLogUpdIndex(ClauseFlagsToLogUpdIndex(ent));
1671 		else
1672 		  Yap_CleanUpIndex(ClauseFlagsToLogUpdIndex(ent));
1673 	      } else {
1674 		Yap_ErLogUpdCl(ClauseFlagsToLogUpdClause(ent));
1675 	      }
1676 	    } else {
1677 	      Yap_ErCl(ClauseFlagsToDynamicClause(ent));
1678 	    }
1679 	  }
1680 	}
1681 #ifdef MULTI_ASSIGNMENT_VARIABLES
1682       } else /* if (IsApplTerm(d1)) */ {
1683 	Entries += 2;
1684 #endif
1685       }
1686     }
1687   }
1688   B = NULL;
1689 }
1690 
1691 
1692 int in_limbo = FALSE;
1693 
1694 /* cleanup any records we had in the saved state. They are now inaccessible */
1695 static void
1696 FreeRecords(void) {
1697   struct record_list *ptr;
1698 
1699   ptr = Yap_Records;
1700   Yap_Records = NULL;
1701   while (ptr) {
1702     struct record_list *optr = ptr;
1703     Yap_ReleaseTermFromDB(ptr->dbrecord);
1704     ptr = ptr->next_rec;
1705     Yap_FreeCodeSpace((void *)optr);
1706   }
1707 }
1708 
1709 /*
1710  * This function is called when wanting only to restore the heap and
1711  * associated registers
1712  */
1713 static int
1714 Restore(char *s, char *lib_dir)
1715 {
1716   int restore_mode;
1717 
1718   OPCODE old_ops[_std_top+1];
1719   CELL MyTrail, MyStack, MyHeap, MyState;
1720 
1721   if ((restore_mode = OpenRestore(s, lib_dir, &MyState, &MyTrail, &MyStack, &MyHeap)) == FAIL_RESTORE)
1722     return(FALSE);
1723   Yap_ShutdownLoadForeign();
1724   in_limbo = TRUE;
1725   if (get_coded(restore_mode, old_ops) < 0)
1726      return FAIL_RESTORE;
1727   restore_regs(restore_mode);
1728   in_limbo = FALSE;
1729   /*#endif*/
1730   RestoreHeap(old_ops);
1731   switch(restore_mode) {
1732   case DO_EVERYTHING:
1733     if (OldHeapBase != Yap_HeapBase ||
1734 	OldLCL0 != LCL0 ||
1735 	OldGlobalBase != (CELL *)Yap_GlobalBase ||
1736 	OldTrailBase != Yap_TrailBase) {
1737       Yap_AdjustStacksAndTrail();
1738       if (which_save == 2) {
1739 	Yap_AdjustRegs(2);
1740       } else {
1741 	Yap_AdjustRegs(1);
1742       }
1743       break;
1744 #ifdef DEBUG_RESTORE2
1745       fprintf(errout, "phase 2 done\n");
1746 #endif
1747     }
1748     break;
1749   case DO_ONLY_CODE:
1750     UnmarkTrEntries();
1751     Yap_InitYaamRegs();
1752     break;
1753   }
1754 
1755   Yap_ReOpenLoadForeign();
1756   Yap_InitPlIO();
1757   /* reset time */
1758   Yap_ReInitWallTime();
1759   Yap_InitSysPath();
1760 #if USE_DL_MALLOC || USE_SYSTEM_MALLOC
1761   if (!AuxSp) {
1762     Yap_InitPreAllocCodeSpace();
1763   }
1764 #endif
1765   FreeRecords();
1766   CloseRestore();
1767   if (which_save == 2) {
1768     Yap_unify(ARG2, MkIntTerm(0));
1769   }
1770   return restore_mode;
1771 }
1772 
1773 int
1774 Yap_Restore(char *s, char *lib_dir)
1775 {
1776   return Restore(s, lib_dir);
1777 }
1778 
1779 static Int
1780 p_restore(void)
1781 {
1782   int mode;
1783   char s[YAP_FILENAME_MAX+1];
1784 
1785   Term t1 = Deref(ARG1);
1786 #if defined(YAPOR) && !defined(THREADS)
1787   if (number_workers != 1) {
1788     Yap_Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
1789     return(FALSE);
1790   }
1791 #elif defined(THREADS)
1792   if (NOfThreads != 1) {
1793     Yap_Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
1794     return(FALSE);
1795   }
1796 #endif
1797   if (!Yap_GetName(s, YAP_FILENAME_MAX, t1)) {
1798     Yap_Error(TYPE_ERROR_LIST,t1,"restore/1");
1799     return(FALSE);
1800   }
1801   if ((mode = Restore(s, NULL)) == DO_ONLY_CODE) {
1802 #if PUSH_REGS
1803     restore_absmi_regs(&Yap_standard_regs);
1804 #endif
1805     /* back to the top level we go */
1806     siglongjmp(Yap_RestartEnv,3);
1807   }
1808   return(mode != FAIL_RESTORE);
1809 }
1810 
1811 void
1812 Yap_InitSavePreds(void)
1813 {
1814   Yap_InitCPred("$save", 2, p_save2, SyncPredFlag|HiddenPredFlag);
1815   Yap_InitCPred("$save_program", 1, p_save_program, SyncPredFlag|HiddenPredFlag);
1816   Yap_InitCPred("$restore", 1, p_restore, SyncPredFlag|HiddenPredFlag);
1817 }
1818