YAP 7.1.0
heapgc.c
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: heapgc.c *
12* Last rev: *
13* mods: *
14* comments: Global Stack garbage collector *
15* *
16*************************************************************************/
17#ifdef SCCS
18static char SccsId[] = "%W% %G%";
19#endif /* SCCS */
20
21#include "absmi.h"
22#include "yapio.h"
23#include "alloc.h"
24#include "attvar.h"
25#if !defined(TABLING)
26//#define EASY_SHUNTING 1
27#endif /* !TABLING */
28#define HYBRID_SCHEME 1
29
30#define DEBUG_printf0(A,B)
31#define DEBUG_printf1(A,B,C)
32#define DEBUG_printf20(A,B)
33#define DEBUG_printf21(A,B,C)
34
35/* global variables for garbage collection */
36
37static Int p_inform_gc( CACHE_TYPE1 );
38static Int garbage_collect( CACHE_TYPE1 );
39static void init_dbtable(tr_fr_ptr CACHE_TYPE);
40static void mark_external_reference(CELL * CACHE_TYPE);
41static void mark_db_fixed(CELL * CACHE_TYPE);
42static void mark_trail(tr_fr_ptr, tr_fr_ptr, CELL *, choiceptr CACHE_TYPE);
43static void mark_environments(CELL *, yamop *,size_t, CELL * CACHE_TYPE);
44static void mark_choicepoints(choiceptr, tr_fr_ptr, bool CACHE_TYPE);
45static void into_relocation_chain(CELL *, CELL * CACHE_TYPE);
46static void sweep_environments(CELL *, yamop*, size_t, CELL * CACHE_TYPE);
47static void sweep_choicepoints(choiceptr CACHE_TYPE);
48static void compact_heap( CACHE_TYPE1 );
49static void update_relocation_chain(CELL *, CELL * CACHE_TYPE);
50static bool is_gc_verbose(void);
51static bool is_gc_very_verbose(void);
52static void LeaveGCMode( CACHE_TYPE1 );
53#ifdef EASY_SHUNTING
54static void set_conditionals(tr_fr_ptr CACHE_TYPE);
55#endif /* EASY_SHUNTING */
56
57#include "heapgc.h"
58
59typedef struct gc_mark_continuation {
60 CELL *v;
61 int nof;
62} cont;
63
64/* straightforward binary tree scheme that, given a key, finds a
65 matching dbref */
66
67typedef enum {
69 cl_entry,
70 lcl_entry,
71 li_entry,
72 dcl_entry
73} db_entry_type;
74
75typedef struct db_entry {
76 CODEADDR val;
77 db_entry_type db_type;
78 int in_use;
79 struct db_entry *left;
80 CODEADDR lim;
81 struct db_entry *right;
82} *dbentry;
83
84typedef struct RB_red_blk_node {
85 CODEADDR key;
86 CODEADDR lim;
87 db_entry_type db_type;
88 int in_use;
89 int red; /* if red=0 then the node is black */
90 struct RB_red_blk_node* left;
91 struct RB_red_blk_node* right;
92 struct RB_red_blk_node* parent;
94
95#ifdef EASY_SHUNTING
96#undef LOCAL_cont_top0
97#define LOCAL_cont_top0 (cont *)LOCAL_sTR
98#endif
99
100/* support for hybrid garbage collection scheme */
101
102yamop * Yap_gcP(void) {
103 CACHE_REGS
104 return gc_P(P,CP);
105}
106
107/* support for hybrid garbage collection scheme */
108
109static void
110gc_growtrail(int committed, tr_fr_ptr begsTR, cont *old_cont_top0 USES_REGS)
111{
112 UInt sz = LOCAL_TrailTop-(ADDR)LOCAL_OldTR;
113 /* ask for double the size */
114 sz = 2*sz;
115
116 if (!Yap_locked_growtrail(sz, TRUE)) {
117#ifdef EASY_SHUNTING
118 if (begsTR) {
119 LOCAL_sTR = (tr_fr_ptr)old_cont_top0;
120 while (begsTR != NULL) {
121 tr_fr_ptr newsTR = (tr_fr_ptr)TrailTerm(begsTR);
122 TrailTerm(LOCAL_sTR) = TrailTerm(begsTR+1);
123 TrailTerm(LOCAL_sTR+1) = TrailTerm(begsTR+2);
124 begsTR = newsTR;
125 LOCAL_sTR += 2;
126 }
127 }
128 set_conditionals(LOCAL_sTR PASS_REGS);
129#endif
130 /* could not find more trail */
131 save_machine_regs();
132 siglongjmp(LOCAL_gc_restore, 2);
133 }
134}
135
136inline static void
137PUSH_CONTINUATION(CELL *v, int nof USES_REGS) {
138 cont *x;
139 x = LOCAL_cont_top;
140 x++;
141 if ((ADDR)x > LOCAL_TrailTop-1024) {
142 gc_growtrail(TRUE, NULL, NULL PASS_REGS);
143 }
144 x->v = v;
145 x->nof = nof;
146 LOCAL_cont_top = x;
147}
148
149#define POP_CONTINUATION() { \
150 if (LOCAL_cont_top == LOCAL_cont_top0) \
151 return; \
152 else { \
153 int nof = LOCAL_cont_top->nof; \
154 cont *x = LOCAL_cont_top; \
155 \
156 current = x->v; \
157 if (nof == 1) \
158 LOCAL_cont_top = --x; \
159 else { \
160 x->nof = nof-1; \
161 x->v = current+1; \
162 } \
163 } \
164 goto begin; }
165
166#ifdef HYBRID_SCHEME
167
168inline void
169PUSH_POINTER(CELL *v USES_REGS) {
170 if (LOCAL_iptop >= (CELL_PTR *)ASP) return;
171 *LOCAL_iptop++ = v;
172}
173
174#ifdef EASY_SHUNTING
175inline static void
176POP_POINTER( USES_REGS1 ) {
177 if (LOCAL_iptop >= (CELL_PTR *)ASP) return;
178 --LOCAL_iptop;
179}
180#endif
181
182inline static void
183POPSWAP_POINTER(CELL_PTR *vp, CELL_PTR v USES_REGS) {
184 if (LOCAL_iptop >= (CELL_PTR *)ASP || LOCAL_iptop == vp) return;
185 if (*vp != v)
186 return;
187 --LOCAL_iptop;
188 if (vp != LOCAL_iptop)
189 *vp = *LOCAL_iptop;
190}
191
192/*
193 original code from In Hyuk Choi,
194 found at http://userpages.umbc.edu/~ichoi1/project/cs441.htm
195*/
196static inline void
197exchange(CELL_PTR * b, Int i, Int j)
198{
199 CELL *t = b[j];
200
201 b[j] = b[i];
202 b[i] = t;
203}
204
205static UInt
206partition(CELL *a[], Int p, Int r)
207{
208 CELL *x;
209 UInt i, j;
210
211 x = a[p];
212 i = p+1;
213 j = r;
214
215 while (a[j] > x && i < j) {
216 j--;
217 }
218 while (a[i] < x && i < j) {
219 i++;
220 }
221 while(i < j) {
222 exchange(a, i, j);
223 i++;
224 j--;
225 while (a[j] > x && i < j) {
226 j--;
227 }
228 while (a[i] < x && i < j) {
229 i++;
230 }
231 }
232 if (a[i] > x)
233 i--;
234 exchange(a, p, i);
235 return(i);
236}
237
238static void
239insort(CELL *a[], Int p, Int q)
240{
241 Int j;
242
243 for (j = p+1; j <= q; j ++) {
244 CELL *key;
245 Int i;
246
247 key = a[j];
248 i = j;
249
250 while (i > p && a[i-1] > key) {
251 a[i] = a[i-1];
252 i --;
253 }
254 a[i] = key;
255 }
256}
257
258
259static void
260quicksort(CELL *a[], Int p, Int r)
261{
262 Int q;
263 if (p < r) {
264 if (r - p < 100) {
265 insort(a, p, r);
266 return;
267 }
268 exchange(a, p, (p+r)/2);
269 q = partition (a, p, r);
270 quicksort(a, p, q-1);
271 quicksort(a, q + 1, r);
272 }
273}
274
275#else
276
277#define PUSH_POINTER(P PASS_REGS)
278#define POP_POINTER( PASS_REGS1 )
279#define POPSWAP_POINTER(P)
280
281#endif /* HYBRID_SCHEME */
282
283
284#ifdef MULTI_ASSIGNMENT_VARIABLES
285/*
286 Based in opt.mavar.h. This is a set of routines to find out if a
287 ma trail entry has appeared before in the same trail segment. All ma
288 entries for the same cell are then linked. At the end of mark_trail() only
289t one will remain.
290*/
291
292static inline unsigned int
293GC_MAVAR_HASH(CELL *addr) {
294#if SIZEOF_INT_P==8
295 return((((unsigned int)((CELL)(addr)))>>3)%GC_MAVARS_HASH_SIZE);
296#else
297 return((((unsigned int)((CELL)(addr)))>>2)%GC_MAVARS_HASH_SIZE);
298#endif
299}
300
301static inline gc_ma_hash_entry *
302GC_ALLOC_NEW_MASPACE( USES_REGS1 )
303{
304 gc_ma_hash_entry *new = LOCAL_gc_ma_h_top;
305 if ((char *)LOCAL_gc_ma_h_top > LOCAL_TrailTop-1024)
306 gc_growtrail(FALSE, NULL, NULL PASS_REGS);
307 LOCAL_gc_ma_h_top++;
308 LOCAL_cont_top = (cont *)LOCAL_gc_ma_h_top;
309#ifdef EASY_SHUNTING
310 LOCAL_sTR = LOCAL_sTR0 = (tr_fr_ptr)LOCAL_cont_top;
311#else
312 LOCAL_cont_top0 = LOCAL_cont_top;
313#endif
314 return new;
315}
316
317static inline gc_ma_hash_entry*
318gc_lookup_ma_var(CELL *addr, tr_fr_ptr trp USES_REGS) {
319 unsigned int i = GC_MAVAR_HASH(addr);
320 gc_ma_hash_entry *nptr, *optr = NULL;
321
322 if (LOCAL_gc_ma_hash_table[i].timestmp != LOCAL_gc_timestamp) {
323 LOCAL_gc_ma_hash_table[i].timestmp = LOCAL_gc_timestamp;
324 LOCAL_gc_ma_hash_table[i].addr = addr;
325#if TABLING
326 LOCAL_gc_ma_hash_table[i].loc = trp;
327 LOCAL_gc_ma_hash_table[i].more = LOCAL_gc_ma_h_list;
328 LOCAL_gc_ma_h_list = LOCAL_gc_ma_hash_table+i;
329#endif /* TABLING */
330 LOCAL_gc_ma_hash_table[i].next = NULL;
331 return NULL;
332 }
333 nptr = LOCAL_gc_ma_hash_table+i;
334 while (nptr) {
335 optr = nptr;
336 if (nptr->addr == addr) {
337#if TABLING
338 /*
339 we're moving from oldest to more recent, so only a new entry
340 has the correct new value
341 */
342 TrailVal(nptr->loc+1) = TrailVal(trp+1);
343#endif /* TABLING */
344 return nptr;
345 }
346 nptr = nptr->next;
347 }
348 nptr = GC_ALLOC_NEW_MASPACE( PASS_REGS1 );
349 optr->next = nptr;
350 nptr->addr = addr;
351#if TABLING
352 nptr->loc = trp;
353 nptr->more = LOCAL_gc_ma_h_list;
354#endif /* TABLING */
355 nptr->next = NULL;
356 LOCAL_gc_ma_h_list = nptr;
357 return NULL;
358}
359
360static inline void
361GC_NEW_MAHASH(gc_ma_hash_entry *top USES_REGS) {
362 UInt time = ++LOCAL_gc_timestamp;
363
364 LOCAL_gc_ma_h_list = NULL;
365 if (time == 0) {
366 unsigned int i;
367
368 /* damn, we overflowed */
369 for (i = 0; i < GC_MAVARS_HASH_SIZE; i++)
370 LOCAL_gc_ma_hash_table[i].timestmp = 0L;
371 time = ++LOCAL_gc_timestamp;
372 }
373 LOCAL_gc_ma_h_top = top;
374 LOCAL_cont_top = (cont *)LOCAL_gc_ma_h_top;
375#ifdef EASY_SHUNTING
376 LOCAL_sTR = (tr_fr_ptr)LOCAL_cont_top;
377#else
378 LOCAL_cont_top0 = LOCAL_cont_top;
379#endif
380}
381
382#endif
383
384/* find all accessible objects on the heap and squeeze out all the rest */
385
386static void count(Term t, Term *p) {
387 TrailTerm(TR++) = t;
388 if ((tr_fr_ptr)LOCAL_TrailTop-TR < 1024) {
389 save_machine_regs();
390 siglongjmp( LOCAL_gc_restore, 2);
391 }
392}
393
394static void mark(Term t, Term *p) {
395 mark_external_reference(&TrailTerm(TR) PASS_REGS);
396 TR++;
397}
398
399static void sweep(Term t, Term *o) {
400 Term *ptr =&(TrailTerm(TR)) ;
401 if (HEAP_PTR(*ptr)) {
402 into_relocation_chain(ptr, GET_NEXT(*ptr) PASS_REGS);
403 }
404 TR++;
405}
406
407
408static void pop(Term t, Term *o) {
409 Term *ptr = &(TrailTerm(TR));
410 TR++;
411 *o = *ptr;
412}
413
414
415/*
416* push the active registers onto the trail for inclusion during gc */
417
418
419#define PUSH(X) PUSH__((X),&(X))
420
421static tr_fr_ptr
422push_registers(Int num_regs, void PUSH__(Term, Term *), yamop *nextop USES_REGS)
423{
424 int i;
425 StaticArrayEntry *sal = LOCAL_StaticArrays;
426 tr_fr_ptr tr0 = TR;
427 /* push array entries first */
428 ArrayEntry *al = LOCAL_DynamicArrays;
429 GlobalEntry *gl = LOCAL_GlobalVariables;
430 for (i = 1; i <= num_regs; i++) {
431 PUSH( XREGS[i] );
432 }
433
434 PUSH( LOCAL_GlobalArena );
435 //PUSH( LOCAL_GcGeneration );
436// PUSH( LOCAL_GcPhase );
437 PUSH( LOCAL_WokenGoals );
438 PUSH( LOCAL_AttsMutableList );
439 while (al) {
440 PUSH( al->ValueOfVE );
441al = al->NextAE;
442 }
443 while (gl) {
444 Term t = gl->global;
445 if (!IsUnboundVar(&gl->global) &&
446 !IsAtomTerm(t) &&
447 !IsIntTerm(t)
448 ) {
449 PUSH( gl->global );
450// fprintf(stderr,"in=%s %p\n", gl->AtomOfGE->StrOfAE, gl->global);
451}
452 gl = gl->NextGE;
453 }
454 while (sal) {
455 if (sal->ArrayType == array_of_nb_terms) {
456 UInt arity = -sal->ArrayEArity, i;
457 for (i=0; i < arity; i++) {
458 Term tlive = sal->ValueOfVE.lterms[i].tlive;
459 if (!IsVarTerm(tlive) || !IsUnboundVar(&sal->ValueOfVE.lterms[i].tlive)) {
460 PUSH( sal->ValueOfVE.lterms[i].tlive );
461 }
462 }
463 }
464 sal = sal->NextAE;
465 }
466 {
467 CELL *curslot = LOCAL_SlotBase,
468 *topslot = LOCAL_SlotBase + LOCAL_CurSlot;
469 while (curslot < topslot) {
470 // printf("%p <- %p\n", TR, topslot);
471 if (false && !IsVarTerm(*curslot) &&
472 (
473 (*curslot < (CELL)LOCAL_GlobalBase &&
474 *curslot > (CELL)HR))) {
475 *curslot++ = TermFreeTerm;
476 }
477 PUSH( curslot[0]);
478 curslot++;
479 }
480 }
481 /* push any live registers we might have hanging around */
482 if (nextop->opc == Yap_opcode(_move_back) ||
483 nextop->opc == Yap_opcode(_skip)) {
484 CELL *lab = (CELL *)(nextop->y_u.l.l);
485 CELL max = lab[0];
486 Int curr = lab[1];
487 lab += 2;
488 if (max) {
489 CELL i;
490 for (i=0L; i <= max; i++) {
491 if (i == 8*CellSize) {
492 curr = lab[0];
493 lab++;
494 }
495 if (curr & 1) {
496 PUSH( XREGS[i] );
497 }
498 curr >>= 1;
499 }
500 }
501 }
502 return tr0;
503}
504
505
506static tr_fr_ptr
507mark_regs(int num_regs, tr_fr_ptr old_TR, yamop *nextop USES_REGS)
508{
509 tr_fr_ptr oTR = TR;
510 TR = old_TR;
511 push_registers(num_regs, mark, nextop USES_REGS);
512 TR = oTR;
513 return old_TR;
514}
515
516static tr_fr_ptr
517sweep_regs(int num_regs, tr_fr_ptr old_TR, yamop *nextop USES_REGS)
518{
519 tr_fr_ptr oTR = TR;
520 TR = old_TR;
521 push_registers(num_regs, sweep, nextop PASS_REGS);
522 TR = oTR;
523 return old_TR;
524 }
525#undef PUSH
526
527/* pop the corrected register values from the trail and update the registers */
528
529static void
530pop_registers(Int num_regs, tr_fr_ptr old_TR, yamop *nextop USES_REGS)
531{
532 /* pop info on opaque variables */
533 while (LOCAL_extra_gc_cells > LOCAL_extra_gc_cells_base) {
534 YAP_Opaque_CallOnGCRelocate f;
535 CELL *ptr = LOCAL_extra_gc_cells-1;
536 size_t n = ptr[0], t = ptr[-1];
537
538 LOCAL_extra_gc_cells -= (n+1);
539 if ( (f = Yap_blob_gc_relocate_handler(t)) ) {
540 int out = (f)(Yap_BlobTag(t), Yap_BlobInfo(t), LOCAL_extra_gc_cells, n);
541 if (out < 0) {
542 /* error: we don't have enough room */
543 /* could not find more trail */
544 save_machine_regs();
545 siglongjmp(LOCAL_gc_restore, 4);
546 }
547 }
548 }
549
550 tr_fr_ptr trnow = TR;
551 TR = old_TR;
552 push_registers(num_regs, pop,nextop PASS_REGS);
553 TR = trnow;
554}
555#if DEBUG && COUNT_CELLS_MARKED
556static int
557count_cells_marked(void)
558{
559 CELL *current;
560 int found_marked = 0;
561
562 for (current = H - 1; current >= H0; current--) {
563 if (MARKED_PTR(current)) {
564 found_marked++;
565 }
566 }
567 return(found_marked);
568}
569#endif
570
571
572static rb_red_blk_node *
573RBMalloc(UInt size USES_REGS)
574{
575 ADDR new = LOCAL_db_vec;
576
577 LOCAL_db_vec += size;
578 if ((ADDR)LOCAL_db_vec > LOCAL_TrailTop-1024) {
579 gc_growtrail(FALSE, NULL, NULL PASS_REGS);
580 }
581 return (rb_red_blk_node *)new;
582}
583
584static rb_red_blk_node *
585RBTreeCreate(void) {
586 CACHE_REGS
587 rb_red_blk_node* temp;
588
589 /* see the comment in the rb_red_blk_tree structure in red_black_tree.h */
590 /* for information on nil and root */
591 temp=LOCAL_db_nil= RBMalloc(sizeof(rb_red_blk_node) PASS_REGS);
592 temp->parent=temp->left=temp->right=temp;
593 temp->red=0;
594 temp->key=NULL;
595 temp = RBMalloc(sizeof(rb_red_blk_node) PASS_REGS);
596 temp->parent=temp->left=temp->right=LOCAL_db_nil;
597 temp->key=NULL;
598 temp->red=0;
599 return temp;
600}
601
602/* This is code originally written by Emin Martinian */
603
604/***********************************************************************/
605/* FUNCTION: LeftRotate */
606
607/* INPUTS: This takes a tree so that it can access the appropriate */
608/* root and nil pointers, and the node to rotate on. */
609
610/* OUTPUT: None */
611
612/* Modifies Input: tree, x */
613
614/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
615/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
616/* makes the parent of x be to the left of x, x the parent of */
617/* its parent before the rotation and fixes other pointers */
618/* accordingly. */
619/***********************************************************************/
620
621static void
622LeftRotate(rb_red_blk_node* x USES_REGS) {
624 rb_red_blk_node* rb_nil=LOCAL_db_nil;
625
626 /* I originally wrote this function to use the sentinel for */
627 /* nil to avoid checking for nil. However this introduces a */
628 /* very subtle bug because sometimes this function modifies */
629 /* the parent pointer of nil. This can be a problem if a */
630 /* function which calls LeftRotate also uses the nil sentinel */
631 /* and expects the nil sentinel's parent pointer to be unchanged */
632 /* after calling this function. For example, when RBDeleteFixUP */
633 /* calls LeftRotate it expects the parent pointer of nil to be */
634 /* unchanged. */
635
636 y=x->right;
637 x->right=y->left;
638
639 if (y->left != rb_nil) y->left->parent=x; /* used to use sentinel here */
640 /* and do an unconditional assignment instead of testing for nil */
641
642 y->parent=x->parent;
643
644 /* instead of checking if x->parent is the root as in the book, we */
645 /* count on the root sentinel to implicitly take care of this case */
646 if( x == x->parent->left) {
647 x->parent->left=y;
648 } else {
649 x->parent->right=y;
650 }
651 y->left=x;
652 x->parent=y;
653
654#ifdef DEBUG_ASSERT
655 Assert(!LOCAL_db_nil->red,"nil not red in LeftRotate");
656#endif
657}
658
659
660/***********************************************************************/
661/* FUNCTION: RighttRotate */
662
663/* INPUTS: This takes a tree so that it can access the appropriate */
664/* root and nil pointers, and the node to rotate on. */
665
666/* OUTPUT: None */
667
668/* Modifies Input?: tree, y */
669
670/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
671/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
672/* makes the parent of x be to the left of x, x the parent of */
673/* its parent before the rotation and fixes other pointers */
674/* accordingly. */
675/***********************************************************************/
676
677static void
678RightRotate(rb_red_blk_node* y USES_REGS) {
680 rb_red_blk_node* rb_nil=LOCAL_db_nil;
681
682 /* I originally wrote this function to use the sentinel for */
683 /* nil to avoid checking for nil. However this introduces a */
684 /* very subtle bug because sometimes this function modifies */
685 /* the parent pointer of nil. This can be a problem if a */
686 /* function which calls LeftRotate also uses the nil sentinel */
687 /* and expects the nil sentinel's parent pointer to be unchanged */
688 /* after calling this function. For example, when RBDeleteFixUP */
689 /* calls LeftRotate it expects the parent pointer of nil to be */
690 /* unchanged. */
691
692 x=y->left;
693 y->left=x->right;
694
695 if (rb_nil != x->right) x->right->parent=y; /*used to use sentinel here */
696 /* and do an unconditional assignment instead of testing for nil */
697
698 /* instead of checking if x->parent is the root as in the book, we */
699 /* count on the root sentinel to implicitly take care of this case */
700 x->parent=y->parent;
701 if( y == y->parent->left) {
702 y->parent->left=x;
703 } else {
704 y->parent->right=x;
705 }
706 x->right=y;
707 y->parent=x;
708
709#ifdef DEBUG_ASSERT
710 Assert(!LOCAL_db_nil->red,"nil not red in RightRotate");
711#endif
712}
713
714/***********************************************************************/
715/* FUNCTION: TreeInsertHelp */
716
717/* INPUTS: tree is the tree to insert into and z is the node to insert */
718
719/* OUTPUT: none */
720
721/* Modifies Input: tree, z */
722
723/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */
724/* using the algorithm described in _Introduction_To_Algorithms_ */
725/* by Cormen et al. This funciton is only intended to be called */
726/* by the RBTreeInsert function and not by the user */
727/***********************************************************************/
728
729static void
730TreeInsertHelp(rb_red_blk_node* z USES_REGS) {
731 /* This function should only be called by InsertRBTree (see above) */
734 rb_red_blk_node* rb_nil=LOCAL_db_nil;
735
736 z->left=z->right=rb_nil;
737 y=LOCAL_db_root;
738 x=LOCAL_db_root->left;
739 while( x != rb_nil) {
740 y=x;
741 if (x->key < z->key) { /* x.key > z.key */
742 x=x->left;
743 } else { /* x,key <= z.key */
744 x=x->right;
745 }
746 }
747 z->parent=y;
748 if ( (y == LOCAL_db_root) ||
749 (y->key < z->key)) { /* y.key > z.key */
750 y->left=z;
751 } else {
752 y->right=z;
753 }
754
755#ifdef DEBUG_ASSERT
756 Assert(!LOCAL_db_nil->red,"nil not red in TreeInsertHelp");
757#endif
758}
759
760/* Before calling Insert RBTree the node x should have its key set */
761
762/***********************************************************************/
763/* FUNCTION: RBTreeInsert */
764
765/* INPUTS: tree is the red-black tree to insert a node which has a key */
766/* pointed to by key and info pointed to by info. */
767
768/* OUTPUT: This function returns a pointer to the newly inserted node */
769/* which is guarunteed to be valid until this node is deleted. */
770/* What this means is if another data structure stores this */
771/* pointer then the tree does not need to be searched when this */
772/* is to be deleted. */
773
774/* Modifies Input: tree */
775
776/* EFFECTS: Creates a node node which contains the appropriate key and */
777/* info pointers and inserts it into the tree. */
778/***********************************************************************/
779
780static rb_red_blk_node *
781RBTreeInsert(CODEADDR key, CODEADDR end, db_entry_type db_type USES_REGS) {
782 rb_red_blk_node * y;
783 rb_red_blk_node * x;
784 rb_red_blk_node * newNode;
785
786 x=(rb_red_blk_node*) RBMalloc(sizeof(rb_red_blk_node) PASS_REGS);
787 x->key=key;
788 x->lim=end;
789 x->db_type=db_type;
790 x->in_use = FALSE;
791
792 TreeInsertHelp(x PASS_REGS);
793 newNode=x;
794 x->red=1;
795 while(x->parent->red) { /* use sentinel instead of checking for root */
796 if (x->parent == x->parent->parent->left) {
797 y=x->parent->parent->right;
798 if (y->red) {
799 x->parent->red=0;
800 y->red=0;
801 x->parent->parent->red=1;
802 x=x->parent->parent;
803 } else {
804 if (x == x->parent->right) {
805 x=x->parent;
806 LeftRotate(x PASS_REGS);
807 }
808 x->parent->red=0;
809 x->parent->parent->red=1;
810 RightRotate(x->parent->parent PASS_REGS);
811 }
812 } else { /* case for x->parent == x->parent->parent->right */
813 y=x->parent->parent->left;
814 if (y->red) {
815 x->parent->red=0;
816 y->red=0;
817 x->parent->parent->red=1;
818 x=x->parent->parent;
819 } else {
820 if (x == x->parent->left) {
821 x=x->parent;
822 RightRotate(x PASS_REGS);
823 }
824 x->parent->red=0;
825 x->parent->parent->red=1;
826 LeftRotate(x->parent->parent PASS_REGS);
827 }
828 }
829 }
830 LOCAL_db_root->left->red=0;
831 return newNode;
832
833#ifdef DEBUG_ASSERT
834 Assert(!LOCAL_db_nil->red,"nil not red in RBTreeInsert");
835 Assert(!LOCAL_db_root->red,"root not red in RBTreeInsert");
836#endif
837}
838
839
840/* init the table */
841static void
842store_in_dbtable(CODEADDR entry, CODEADDR end, db_entry_type db_type USES_REGS)
843{
844 RBTreeInsert(entry, end, db_type PASS_REGS);
845}
846
847/* find an element in the dbentries table */
848static rb_red_blk_node *
849find_ref_in_dbtable(CODEADDR entry USES_REGS)
850{
851 rb_red_blk_node *current = LOCAL_db_root->left;
852
853 while (current != LOCAL_db_nil) {
854 if (current->key <= entry && current->lim > entry) {
855 return current;
856 }
857 if (entry < current->key)
858 current = current->right;
859 else
860 current = current->left;
861 }
862 return current;
863}
864
865/* find an element in the dbentries table */
866static void
867mark_ref_in_use(DBRef ref USES_REGS)
868{
869 rb_red_blk_node *el = find_ref_in_dbtable((CODEADDR)ref PASS_REGS);
870 el->in_use = TRUE;
871}
872
873static int
874ref_in_use(DBRef ref USES_REGS)
875{
876 rb_red_blk_node *el = find_ref_in_dbtable((CODEADDR)ref PASS_REGS);
877 return el->in_use;
878}
879
880static void
881mark_db_fixed(CELL *ptr USES_REGS) {
882 rb_red_blk_node *el;
883
884 el = find_ref_in_dbtable((CODEADDR)ptr PASS_REGS);
885 if (el != LOCAL_db_nil) {
886 el->in_use = TRUE;
887 }
888}
889
890static void
891init_dbtable(tr_fr_ptr trail_ptr USES_REGS) {
892 StaticClause *sc = DeadStaticClauses;
893 MegaClause *mc = DeadMegaClauses;
894 StaticIndex *si = DeadStaticIndices;
895
896 LOCAL_extra_gc_cells =
897 LOCAL_extra_gc_cells_base = (CELL *)TR;
898 LOCAL_extra_gc_cells_top = LOCAL_extra_gc_cells_base+
899 LOCAL_extra_gc_cells_size;
900 if ((char *)LOCAL_extra_gc_cells_top > LOCAL_TrailTop-1024)
901 gc_growtrail(FALSE, NULL, NULL PASS_REGS);
902 LOCAL_db_vec0 = LOCAL_db_vec = (ADDR)LOCAL_extra_gc_cells_top;
903 LOCAL_db_root = RBTreeCreate();
904 while (trail_ptr > (tr_fr_ptr)LOCAL_TrailBase) {
905 register CELL trail_cell;
906
907 trail_ptr--;
908
909 trail_cell = TrailTerm(trail_ptr);
910
911 if (!IsVarTerm(trail_cell) && IsPairTerm(trail_cell)) {
912 CELL *pt0 = RepPair(trail_cell);
913 /* DB pointer */
914 CELL flags;
915
916#ifdef FROZEN_STACKS /* TRAIL */
917 /* avoid frozen segments */
918 if (
919#ifdef YAPOR_SBA
920 (ADDR) pt0 >= HeapTop
921#else
922 (ADDR) pt0 >= LOCAL_TrailBase && (ADDR) pt0 < LOCAL_TrailTop
923#endif
924 ) {
925 continue;
926 }
927#endif /* FROZEN_STACKS */
928
929 flags = *pt0;
930 /* for the moment, if all references to the term in the stacks
931 are only pointers, reset the flag */
932 if (FlagOn(DBClMask, flags)) {
933 DBRef dbr = DBStructFlagsToDBStruct(pt0);
934 store_in_dbtable((CODEADDR)dbr,
935 (CODEADDR)dbr+sizeof(DBStruct)+sizeof(CELL)*dbr->DBT.NOfCells,
936 db_entry PASS_REGS);
937 } else if (flags & LogUpdMask) {
938 if (flags & IndexMask) {
939 LogUpdIndex *li = ClauseFlagsToLogUpdIndex(pt0);
940 store_in_dbtable((CODEADDR)li, (CODEADDR)li+li->ClSize, li_entry PASS_REGS);
941 } else {
942 LogUpdClause *cli = ClauseFlagsToLogUpdClause(pt0);
943 store_in_dbtable((CODEADDR)cli, (CODEADDR)cli+cli->ClSize, lcl_entry PASS_REGS);
944 }
945 } else {
946 DynamicClause *dcl = ClauseFlagsToDynamicClause(pt0);
947 store_in_dbtable((CODEADDR)dcl, (CODEADDR)dcl+dcl->ClSize, dcl_entry PASS_REGS);
948 }
949 }
950 }
951 while (sc) {
952 store_in_dbtable((CODEADDR)sc, (CODEADDR)sc+sc->ClSize, dcl_entry PASS_REGS);
953 sc = sc->ClNext;
954 }
955 while (si) {
956 store_in_dbtable((CODEADDR)si, (CODEADDR)si+si->ClSize, dcl_entry PASS_REGS);
957 si = si->SiblingIndex;
958 }
959 while (mc) {
960 store_in_dbtable((CODEADDR)mc, (CODEADDR)mc+mc->ClSize, dcl_entry PASS_REGS);
961 mc = mc->ClNext;
962 }
963 if (LOCAL_db_vec == LOCAL_db_vec0) {
964 /* could not find any entries: probably using LOG UPD semantics */
965 LOCAL_db_vec0 = NULL;
966 }
967}
968
969#ifdef DEBUG
970
971/* #define INSTRUMENT_GC 1 */
972
973#ifdef INSTRUMENT_GC
974typedef enum {
975 gc_var,
976 gc_ref,
977 gc_atom,
978 gc_int,
979 gc_num,
980 gc_list,
981 gc_appl,
982 gc_func,
983 gc_susp
984} gc_types;
985unsigned long chain[16];
986unsigned long env_vars;
987unsigned long vars[gc_susp+1];
988
989unsigned long num_bs;
990unsigned long old_vars, new_vars;
991
992static CELL *TrueHB;
993
994static void
995inc_vars_of_type(CELL *curr,gc_types val) {
996 if (curr >= H0 && curr < TrueHB) {
997 old_vars++;
998 } else if (curr >= TrueHB && curr < HR) {
999 new_vars++;
1000 } else {
1001 return;
1002 }
1003 vars[val]++;
1004}
1005
1006static void
1007put_type_info(unsigned long total)
1008{
1009 fprintf(stderr,"%% type info for %lu cells\n", total);
1010 fprintf(stderr,"%% %lu vars\n", vars[gc_var]);
1011 fprintf(stderr,"%% %lu refs\n", vars[gc_ref]);
1012 fprintf(stderr,"%% %lu references from env\n", env_vars);
1013 fprintf(stderr,"%% %lu atoms\n", vars[gc_atom]);
1014 fprintf(stderr,"%% %lu small ints\n", vars[gc_int]);
1015 fprintf(stderr,"%% %lu other numbers\n", vars[gc_num]);
1016 fprintf(stderr,"%% %lu lists\n", vars[gc_list]);
1017 fprintf(stderr,"%% %lu compound terms\n", vars[gc_appl]);
1018 fprintf(stderr,"%% %lu functors\n", vars[gc_func]);
1019 fprintf(stderr,"%% %lu suspensions\n", vars[gc_susp]);
1020}
1021
1022static void
1023inc_var(CELL *current, CELL *next)
1024{
1025 int len = 1;
1026 CELL *mynext=next;
1027
1028 if (ONHEAP(current)) {
1029 if (next == current) {
1030 inc_vars_of_type(current,gc_var);
1031 chain[0]++;
1032 } else {
1033 inc_vars_of_type(current,gc_ref);
1034 while(ONHEAP(mynext) && IsVarTerm(*mynext)) {
1035 CELL *prox = GET_NEXT(*mynext);
1036 if (prox == mynext) {
1037 chain[0]++;
1038 break;
1039 }
1040 len++;
1041 mynext = prox;
1042 }
1043 if (len>=15)
1044 (chain[15])++;
1045 else
1046 (chain[len])++;
1047 }
1048 }
1049}
1050#endif /* INSTRUMENT_GC */
1051
1052int vsc_stop(void);
1053
1054int
1055vsc_stop(void) {
1056 return(1);
1057}
1058
1059#endif
1060
1061#ifdef CHECK_GLOBAL
1062static void
1063check_global(void) {
1064 CELL *current;
1065
1066#ifdef INSTRUMENT_GC
1067 vars[gc_var] = 0;
1068 vars[gc_ref] = 0;
1069 vars[gc_atom] = 0;
1070 vars[gc_int] = 0;
1071 vars[gc_num] = 0;
1072 vars[gc_list] = 0;
1073 vars[gc_appl] = 0;
1074 vars[gc_func] = 0;
1075 vars[gc_susp] = 0;
1076#endif
1077 for (current = H - 1; current >= H0; current--) {
1078 CELL ccurr = *current;
1079
1080 if (MARKED_PTR(current)) {
1081 CELL ccell = UNMARK_CELL(ccurr);
1082 if (ccell == ES) {
1083 /* oops, we found a blob */
1084 CELL *ptr = current-1;
1085 UInt nofcells;
1086
1087 while (!MARKED_PTR(ptr)) ptr--;
1088 nofcells = current-ptr;
1089 current = ptr;
1090 ccurr = *current;
1091 /* process the functor next */
1092 }
1093 }
1094#if INSTRUMENT_GC
1095 if (IsVarTerm(ccurr)) {
1096 if (IsBlobFunctor((Functor)ccurr)) vars[gc_num]++;
1097 else if (ccurr != 0 && (ccurr < (CELL)LOCAL_GlobalBase || ccurr > (CELL)LOCAL_TrailTop)) {
1098 /* printf("%p: %s/%d\n", current,
1099 RepAtom(NameOfFunctor((Functor)ccurr))->StrOfAE,
1100 ArityOfFunctor((Functor)ccurr));*/
1101 vars[gc_func]++;
1102 }
1103 else if (IsUnboundVar(current)) vars[gc_var]++;
1104 else vars[gc_ref]++;
1105 } else if (IsApplTerm(ccurr)) {
1106 /* printf("%p: f->%p\n",current,RepAppl(ccurr)); */
1107 vars[gc_appl]++;
1108 } else if (IsPairTerm(ccurr)) {
1109 /* printf("%p: l->%p\n",current,RepPair(ccurr)); */
1110 vars[gc_list]++;
1111 } else if (IsAtomTerm(ccurr)) {
1112 /* printf("%p: %s\n",current,RepAtom(AtomOfTerm(ccurr))->StrOfAE); */
1113 vars[gc_atom]++;
1114 } else if (IsIntTerm(ccurr)) {
1115 /* printf("%p: %d\n",current,IntOfTerm(ccurr)); */
1116 vars[gc_int]++;
1117 }
1118#endif
1119 }
1120#if INSTRUMENT_GC
1121 put_type_info(H-H0);
1122 vars[gc_var] = 0;
1123 vars[gc_ref] = 0;
1124 vars[gc_atom] = 0;
1125 vars[gc_int] = 0;
1126 vars[gc_num] = 0;
1127 vars[gc_list] = 0;
1128 vars[gc_appl] = 0;
1129 vars[gc_func] = 0;
1130 vars[gc_susp] = 0;
1131#endif
1132}
1133#else
1134#define check_global()
1135#endif /* CHECK_GLOBAL */
1136
1137/* mark a heap object and all heap objects accessible from it */
1138
1139static void
1140mark_variable(CELL_PTR current USES_REGS)
1141{
1142 CELL_PTR next;
1143 register CELL ccur;
1144 unsigned int arity;
1145 char *local_bp = LOCAL_bp;
1146
1147 begin:
1148 if (current == 0 || UNMARKED_MARK(current,local_bp)) {
1149 POP_CONTINUATION();
1150 }
1151 if (current >= H0 && current < HR) {
1152 //fprintf(stderr,"%p M\n", current);
1153 LOCAL_total_marked++;
1154 if (current < LOCAL_HGEN) {
1155 LOCAL_total_oldies++;
1156 } else {
1157 DEBUG_printf0("%p 1\n", current);
1158 }
1159 }
1160 PUSH_POINTER(current PASS_REGS);
1161 ccur = *current;
1162 next = GET_NEXT(ccur);
1163
1164 if (IsVarTerm(ccur)) {
1165 if (IN_BETWEEN(LOCAL_GlobalBase,current,HR) && GlobalIsAttVar(current) && current==next) {
1166 if (next < H0) POP_CONTINUATION();
1167 if (!UNMARKED_MARK(next-1,local_bp)) {
1168 //fprintf(stderr,"%p M\n", next-1);
1169 LOCAL_total_marked++;
1170 if (next-1 < LOCAL_HGEN) {
1171 LOCAL_total_oldies++;
1172 } else {
1173 DEBUG_printf0("%p 1\n", next-1);
1174 }
1175 PUSH_POINTER(next-1 PASS_REGS);
1176 }
1177 PUSH_CONTINUATION(next+1,2 PASS_REGS);
1178 current = next;
1179 goto begin;
1180 } else if (ONHEAP(next)) {
1181#ifdef EASY_SHUNTING
1182 CELL cnext;
1183 /* do variable shunting between variables in the global */
1184 cnext = *next;
1185
1186 if (!MARKED_PTR(next)) {
1187 if (IsVarTerm(cnext) && (CELL)next == cnext) {
1188 /* new global variable to new global variable */
1189 if (next > current && current < LOCAL_prev_HB && current >= HB && next >= HB && next < LOCAL_prev_HB) {
1190#ifdef INSTRUMENT_GC
1191 inc_var(current, current);
1192#endif
1193 *next = (CELL)current;
1194 UNMARK(next);
1195 MARK(current);
1196 *current = (CELL)current;
1197 POP_CONTINUATION();
1198 } else {
1199 /* can't help here */
1200#ifdef INSTRUMENT_GC
1201 inc_var(current, next);
1202#endif
1203 current = next;
1204 }
1205 } else {
1206 /* binding to a determinate reference */
1207 if (next >= HB && current < LCL0 && cnext != TermFoundVar) {
1208 UNMARK(current);
1209 *current = cnext;
1210 if (current >= H0 && current < HR) {
1211 //fprintf(stderr,"%p M\n", current-1);
1212 LOCAL_total_marked--;
1213 if (current < LOCAL_HGEN) {
1214 LOCAL_total_oldies--;
1215 } else {
1216 DEBUG_printf0("%p-1\n", next-1);
1217 }
1218 }
1219 POP_POINTER( PASS_REGS1 );
1220 } else {
1221#ifdef INSTRUMENT_GC
1222 inc_var(current, next);
1223#endif
1224 current = next;
1225 }
1226 }
1227 /* try to shorten chains if they go through the current CP */
1228 } else if (next > HB &&
1229 IsVarTerm(cnext) &&
1230 UNMARK_CELL(cnext) != (CELL)next &&
1231 current < LCL0) {
1232 /* This step is possible because we clean up the trail */
1233 *current = UNMARK_CELL(cnext);
1234 UNMARK(current);
1235 if (current >= H0 && current < HR ) {
1236 //fprintf(stderr,"%p M\n", current);
1237 LOCAL_total_marked--;
1238 if (current < LOCAL_HGEN) {
1239 LOCAL_total_oldies--;
1240 } else {
1241 DEBUG_printf0("%p-1\n", next-1);
1242 }
1243 }
1244 POP_POINTER( PASS_REGS1 );
1245 } else
1246#endif
1247 /* what I'd do without variable shunting */
1248 {
1249#ifdef INSTRUMENT_GC
1250 inc_var(current, next);
1251#endif
1252 current = next;
1253 }
1254 goto begin;
1255#ifdef DEBUG
1256 } else if (next < (CELL *)LOCAL_GlobalBase || next > (CELL *)LOCAL_TrailTop) {
1257 fprintf(stderr,
1258 "OOPS in GC: marking, TR=%p, current=%p, *current=" UInt_FORMAT " next=%p\n", TR, current, ccur, next);
1259#endif
1260 } else {
1261#ifdef COROUTING
1262 LOCAL_total_smarked++;
1263#endif
1264#ifdef INSTRUMENT_GC
1265 inc_var(current, next);
1266#endif
1267 }
1268 POP_CONTINUATION();
1269 } else if (IsAtomOrIntTerm(ccur)) {
1270#ifdef INSTRUMENT_GC
1271 if (IsAtomTerm(ccur))
1272 inc_vars_of_type(current,gc_atom);
1273 else
1274 inc_vars_of_type(current, gc_int);
1275#endif
1276 POP_CONTINUATION();
1277 } else if (IsPairTerm(ccur)) {
1278#ifdef INSTRUMENT_GC
1279 inc_vars_of_type(current,gc_list);
1280#endif
1281 if (ONHEAP(next)) {
1282 /* speedup for strings */
1283 if (IsAtomOrIntTerm(*next)) {
1284 if (!UNMARKED_MARK(next,local_bp)) {
1285 //fprintf(stderr,"%p M\n", next);
1286 LOCAL_total_marked++;
1287 if (next < LOCAL_HGEN) {
1288 LOCAL_total_oldies++;
1289 } else {
1290 DEBUG_printf0("%p 1\n", next);
1291 }
1292 PUSH_POINTER(next PASS_REGS);
1293 }
1294 current = next+1;
1295 goto begin;
1296 } else {
1297 PUSH_CONTINUATION(next+1,1 PASS_REGS);
1298 current = next;
1299 goto begin;
1300 }
1301 } else if (ONCODE(next)) {
1302 mark_db_fixed(RepPair(ccur) PASS_REGS);
1303 }
1304 POP_CONTINUATION();
1305 } else if (IsApplTerm(ccur)) {
1306 register CELL cnext = *next;
1307
1308#ifdef INSTRUMENT_GC
1309 if (!IsExtensionFunctor((Functor)cnext))
1310 inc_vars_of_type(current,gc_appl);
1311 else
1312 inc_vars_of_type(current,gc_num);
1313#endif
1314 if (ONCODE(next)) {
1315 if ((Functor)cnext == FunctorDBRef) {
1316 DBRef tref = DBRefOfTerm(ccur);
1317
1318 /* make sure the reference is marked as in use */
1319 if ((tref->Flags & (ErasedMask|LogUpdMask)) == (ErasedMask|LogUpdMask)) {
1320 *current = MkDBRefTerm((DBRef)LogDBErasedMarker);
1321 MARK(current);
1322 } else {
1323 mark_ref_in_use(tref PASS_REGS);
1324 }
1325 } else {
1326 mark_db_fixed(next PASS_REGS);
1327 }
1328 POP_CONTINUATION();
1329 }
1330 if ( MARKED_PTR(next) || !ONHEAP(next) )
1331 POP_CONTINUATION();
1332
1333 if (next < H0) POP_CONTINUATION();
1334 if (IsExtensionFunctor((Functor)cnext)) {
1335 size_t sz = SizeOfOpaqueTerm(next,cnext);
1336
1337 // fprintf(stderr,"found %p: %lx %lx %lx %p: %lx %p\n ", next, next[0], next[1], next[2], next+sz-1,next[sz-1], next+sz);
1338
1339 MARK(next);
1340 XMARK(next);
1341 MARK(next+(sz-1));
1342 XMARK(next+(sz-1));
1343 if (next < LOCAL_HGEN) {
1344 LOCAL_total_oldies+=sz;
1345 }
1346 //fprintf(stderr,"MRW %p<->%p: %lx %lx %ld\n ", next, next+(sz-1), *next, next[1], sz);
1347 //fprintf(stderr,"%p M 3\n", next);
1348 LOCAL_total_marked += sz;
1349 PUSH_POINTER(next PASS_REGS);
1350 PUSH_POINTER(next+(sz-1) PASS_REGS);
1351 YAP_Opaque_CallOnGCMark f;
1352 Term t = AbsAppl(next);
1353 if ((Functor)next[0] == FunctorBlob &&
1354 (f = Yap_blob_gc_mark_handler(t))) {
1355 Int n = f(Yap_BlobTag(t), Yap_BlobInfo(t), LOCAL_extra_gc_cells,
1356 LOCAL_extra_gc_cells_top - (LOCAL_extra_gc_cells + 2));
1357 if (n < 0) {
1358 /* error: we don't have enough room */
1359 /* could not find more trail */
1360 save_machine_regs();
1361 siglongjmp(LOCAL_gc_restore, 3);
1362 } else if (n > 0) {
1363 CELL *ptr = LOCAL_extra_gc_cells;
1364
1365 LOCAL_extra_gc_cells += n + 2;
1366 PUSH_CONTINUATION(ptr, n + 1 PASS_REGS);
1367 ptr += n;
1368 ptr[0] = t;
1369 ptr[1] = n + 1;
1370 }
1371 }
1372
1373#if DEBUG
1374 if (next[sz-1] != CloseExtension(next)) {
1375 fprintf(stderr,"[ Error: could not find ES at blob %p type " UInt_FORMAT " ]\n", next, next[1]);
1376 }
1377#endif
1378 POP_CONTINUATION();
1379 }
1380 if (next < H0) POP_CONTINUATION();
1381#ifdef INSTRUMENT_GC
1382 inc_vars_of_type(next,gc_func);
1383#endif
1384 arity = ArityOfFunctor((Functor)(cnext));
1385 MARK(next);
1386 //fprintf(stderr,"%p M\n", next);
1387 ++LOCAL_total_marked;
1388 if (next < LOCAL_HGEN) {
1389 ++LOCAL_total_oldies;
1390 } else {
1391 DEBUG_printf0("%p 1\n", next);
1392 }
1393 PUSH_POINTER(next PASS_REGS);
1394 next++;
1395 /* speedup for leaves */
1396 while (arity && IsAtomOrIntTerm(*next)) {
1397 if (!UNMARKED_MARK(next,local_bp)) {
1398 //fprintf(stderr,"%p M\n", next);
1399 LOCAL_total_marked++;
1400 if (next < LOCAL_HGEN) {
1401 LOCAL_total_oldies++;
1402 } else {
1403 DEBUG_printf0("%p 1\n", next);
1404 }
1405 PUSH_POINTER(next PASS_REGS);
1406 }
1407 next++;
1408 arity--;
1409 }
1410 if (!arity) POP_CONTINUATION();
1411 current = next;
1412 if (arity == 1) goto begin;
1413 PUSH_CONTINUATION(current+1,arity-1 PASS_REGS);
1414 goto begin;
1415 }
1416}
1417
1418void
1419Yap_mark_variable(CELL_PTR current)
1420{
1421 CACHE_REGS
1422 mark_variable(current PASS_REGS);
1423}
1424
1425static void
1426mark_code(CELL_PTR ptr, CELL *next USES_REGS)
1427{
1428 if (ONCODE(next)) {
1429 CELL reg = *ptr;
1430 if (IsApplTerm(reg) && (Functor)(*next) == FunctorDBRef) {
1431 DBRef tref = DBRefOfTerm(reg);
1432 /* make sure the reference is marked as in use */
1433 if ((tref->Flags & (LogUpdMask|ErasedMask)) == (LogUpdMask|ErasedMask)) {
1434 *ptr = MkDBRefTerm((DBRef)LogDBErasedMarker);
1435 } else {
1436 mark_ref_in_use(tref PASS_REGS);
1437 }
1438 } else {
1439 mark_db_fixed(next PASS_REGS);
1440 }
1441 }
1442}
1443
1444static void
1445mark_external_reference(CELL *ptr USES_REGS) {
1446 CELL *next = GET_NEXT(*ptr);
1447
1448 if (ONHEAP(next)) {
1449#ifdef HYBRID_SCHEME
1450 CELL_PTR *old = LOCAL_iptop;
1451#endif
1452 mark_variable(ptr PASS_REGS);
1453 MARK(ptr);
1454 POPSWAP_POINTER(old, ptr PASS_REGS);
1455 } else if (ptr < H0 || ptr > (CELL*)LOCAL_TrailTop) {
1456 mark_code(ptr, next PASS_REGS);
1457 }
1458}
1459
1460/*
1461 * mark all heap objects accessible from the trail (which includes the active
1462 * general purpose registers)
1463 */
1464
1465void
1466Yap_mark_external_reference(CELL *ptr) {
1467 CACHE_REGS
1468 mark_external_reference(ptr PASS_REGS);
1469}
1470
1471
1472/* mark all heap objects accessible from a chain of environments */
1473
1474static void
1475mark_environments(CELL_PTR gc_ENV, yamop *pc, size_t size, CELL *pvbmap USES_REGS)
1476{
1477 CELL_PTR saved_var;
1478 bool very_verbose = is_gc_very_verbose();
1479 while (gc_ENV != NULL) { /* no more environments */
1480 Int bmap = 0;
1481 int currv = 0;
1482
1483 if (very_verbose) {
1484 if (size > 0) {
1485 PredEntry *pe = EnvPreg((yamop*)gc_ENV[E_CP]);
1486 op_numbers op = Yap_op_from_opcode(ENV_ToOp((yamop*)gc_ENV[E_CP]));
1487#if defined(ANALYST) || defined(DEBUG)
1488 fprintf(stderr,"ENV %p-%p(%ld) %s\n", gc_ENV, pvbmap, size-EnvSizeInCells, Yap_op_names[op]);
1489#else
1490 fprintf(stderr,"ENV %p-%p(%ld) %d\n", gc_ENV, pvbmap, size-EnvSizeInCells, (int)op);
1491#endif
1492 if (pe->ArityOfPE)
1493 fprintf(stderr," %s/%ld\n", RepAtom(NameOfFunctor(pe->FunctorOfPred))->StrOfAE, pe->ArityOfPE);
1494 else
1495 fprintf(stderr," %s\n", RepAtom((Atom)(pe->FunctorOfPred))->StrOfAE);
1496 }
1497 }
1498 if (pc->opc== FAIL_OPCODE)
1499 return;
1500
1501 //fprintf(stderr,"ENV %p %ld\n", gc_ENV, size);
1502#ifdef DEBUG
1503 if (/* size < 0 || */ size > 512)
1504 fprintf(stderr,"OOPS in GC: env size for %p is " UInt_FORMAT "\n", gc_ENV, (CELL)size);
1505#endif
1506 mark_db_fixed((CELL *)gc_ENV[E_CP] PASS_REGS);
1507 /* for each saved variable */
1508 if (size > EnvSizeInCells) {
1509 int tsize = size - EnvSizeInCells;
1510
1511 currv = sizeof(CELL)*8-tsize%(sizeof(CELL)*8);
1512 if (pvbmap != NULL) {
1513 pvbmap += tsize/(sizeof(CELL)*8);
1514 bmap = *pvbmap;
1515 } else {
1516 bmap = ((CELL)-1);
1517 }
1518 bmap = (Int)(((CELL)bmap) << currv);
1519 }
1520
1521 for (saved_var = gc_ENV - size; saved_var < gc_ENV - EnvSizeInCells; saved_var++) {
1522 if (currv == sizeof(CELL)*8) {
1523 if (pvbmap) {
1524 pvbmap--;
1525 bmap = *pvbmap;
1526 } else {
1527 bmap = ((CELL)-1);
1528 }
1529 currv = 0;
1530 }
1531 /* we may have already been here */
1532 if (bmap < 0 && !MARKED_PTR(saved_var)) {
1533#ifdef INSTRUMENT_GC
1534 Term ccur = *saved_var;
1535
1536 if (IsVarTerm(ccur)) {
1537 int len = 1;
1538 CELL *mynext= GET_NEXT(ccur);
1539
1540 if (ONHEAP(mynext)) {
1541 env_vars++;
1542 while(ONHEAP(mynext) && IsVarTerm(*mynext)) {
1543 CELL *prox = GET_NEXT(*mynext);
1544 if (prox == mynext) {
1545 chain[0]++;
1546 break;
1547 }
1548 len++;
1549 mynext = prox;
1550 }
1551 if (len>=15) {
1552 (chain[15])++;
1553 } else {
1554 (chain[len])++;
1555 }
1556 }
1557 }
1558#endif
1559 mark_external_reference(saved_var PASS_REGS);
1560 }
1561 bmap <<= 1;
1562 currv++;
1563 }
1564 /* have we met this environment before?? */
1565 /* we use the B field in the environment to tell whether we have
1566 been here before or not.
1567
1568 We do it at the end because we don't want to lose any variables
1569 that would have been trimmed at the first environment visit.
1570 */
1571 if (MARKED_PTR(gc_ENV+E_CB))
1572 return;
1573 MARK(gc_ENV+E_CB);
1574 pc = (yamop *) (gc_ENV[E_CP]);
1575 size = EnvSize( pc );
1576 pvbmap = EnvBMap( pc );
1577
1578 gc_ENV = (CELL_PTR) gc_ENV[E_E]; /* link to prev
1579 * environment */
1580 }
1581}
1582
1583/*
1584 Cleaning the trail should be quick and simple, right? Well, not
1585 really :-(. The problem is that the trail includes a dumping ground
1586 of the WAM registers and of extra choice-point fields, which need
1587 to be cleaned from somewhere.
1588
1589 And cleaning the trail itself is not easy. The problem is that we
1590 may not have cleaned the trail after cuts. If we naively followed
1591 these pointers, we could have direct references to the global
1592 stack! A solution is to verify whether we are poiting at a
1593 legitimate trail entry. Unfortunately this requires some extra work
1594 following choice-points.
1595
1596*/
1597
1598
1599static void
1600mark_trail(tr_fr_ptr trail_ptr, tr_fr_ptr trail_base, CELL *gc_H, choiceptr gc_B USES_REGS)
1601{
1602#ifdef EASY_SHUNTING
1603 tr_fr_ptr begsTR = NULL, endsTR = NULL;
1604 tr_fr_ptr OldsTR0 = LOCAL_sTR0;
1605#endif
1606#ifdef COROUTINING
1607 CELL *detatt = NULL;
1608#endif
1609 cont *old_cont_top0 = LOCAL_cont_top0;
1610
1611 if (trail_ptr == trail_base)
1612 return;
1613
1614 GC_NEW_MAHASH((gc_ma_hash_entry *)LOCAL_cont_top0 PASS_REGS);
1615 while (trail_base < trail_ptr) {
1616 register CELL trail_cell;
1617
1618 trail_cell = TrailTerm(trail_base);
1619 if (IsVarTerm(trail_cell)) {
1620 CELL *hp = (CELL *)trail_cell;
1621 /* if a variable older than the current CP has not been marked yet,
1622 than its new binding is not accessible and we can reset it. Note
1623 we must use gc_H to avoid trouble with dangling variables
1624 in the heap */
1625 if ((hp < gc_H && hp >= H0 ) && !MARKED_PTR(hp)) {
1626 /* perform early reset */
1627 /* reset term to be a variable */
1628 RESET_VARIABLE(hp);
1629 LOCAL_discard_trail_entries++;
1630 RESET_VARIABLE(&TrailTerm(trail_base));
1631#ifdef FROZEN_STACKS
1632 RESET_VARIABLE(&TrailVal(trail_base));
1633#endif
1634 } else if (hp < (CELL *)LOCAL_GlobalBase || hp > (CELL *)LOCAL_TrailTop) {
1635 /* pointers from the Heap back into the trail are process in mark_regs. */
1636 /* do nothing !!! */
1637 } else if ((hp < (CELL *)gc_B && hp >= gc_H) || hp > (CELL *)LOCAL_TrailBase) {
1638 /* clean the trail, avoid dangling pointers! */
1639 RESET_VARIABLE(&TrailTerm(trail_base));
1640#ifdef FROZEN_STACKS
1641 RESET_VARIABLE(&TrailVal(trail_base));
1642#endif
1643 LOCAL_discard_trail_entries++;
1644 } else {
1645 if (trail_cell == (CELL)trail_base)
1646 LOCAL_discard_trail_entries++;
1647 else {
1648 /* This is a bit of a mess: when I find an attributed variable that was bound
1649 nondeterministically, I know that after backtracking it will be back to be an unbound variable.
1650 The ideal solution would be to unbind all variables. The current solution is to
1651 remark it as an attributed variable */
1652 if (IN_BETWEEN(LOCAL_GlobalBase,hp,HR) && GlobalIsAttVar(hp) && !UNMARKED_MARK(hp-1,LOCAL_bp)) {
1653 //fprintf(stderr,"%p M\n", hp);
1654 LOCAL_total_marked++;
1655 PUSH_POINTER(hp-1 PASS_REGS);
1656 if (hp-1 < LOCAL_HGEN) {
1657 LOCAL_total_oldies++;
1658 } else {
1659 DEBUG_printf0("%p 1\n", hp-1);
1660 }
1661 mark_variable(hp+1 PASS_REGS);
1662 mark_variable(hp+2 PASS_REGS);
1663 }
1664#ifdef FROZEN_STACKS
1665 mark_external_reference(&TrailVal(trail_base) PASS_REGS);
1666#endif
1667 }
1668#ifdef EASY_SHUNTING
1669 if (hp < gc_H && hp >= H0 && !MARKED_PTR(hp)) {
1670 tr_fr_ptr nsTR = (tr_fr_ptr)LOCAL_cont_top0;
1671 CELL *cptr = (CELL *)trail_cell;
1672
1673 if ((ADDR)nsTR > LOCAL_TrailTop-1024) {
1674 gc_growtrail(TRUE, begsTR, old_cont_top0 PASS_REGS);
1675 }
1676 TrailTerm(nsTR) = (CELL)NULL;
1677 TrailTerm(nsTR+1) = *hp;
1678 TrailTerm(nsTR+2) = trail_cell;
1679 if (begsTR == NULL)
1680 begsTR = nsTR;
1681 else
1682 TrailTerm(endsTR) = (CELL)nsTR;
1683 endsTR = nsTR;
1684 LOCAL_cont_top = (cont *)(nsTR+3);
1685 LOCAL_sTR = (tr_fr_ptr)LOCAL_cont_top;
1686 LOCAL_gc_ma_h_top = (gc_ma_hash_entry *)(nsTR+3);
1687 RESET_VARIABLE(cptr);
1688 MARK(cptr);
1689 }
1690#endif
1691 }
1692 } else if (IsPairTerm(trail_cell)) {
1693 /* cannot safely ignore this */
1694 CELL *cptr = RepPair(trail_cell);
1695 if (IN_BETWEEN(LOCAL_GlobalBase,cptr,HR)) {
1696 if (GlobalIsAttVar(cptr)) {
1697 TrailTerm(trail_base) = (CELL)cptr;
1698 mark_external_reference(&TrailTerm(trail_base) PASS_REGS);
1699 TrailTerm(trail_base) = trail_cell;
1700 } else {
1701 mark_external_reference(&TrailTerm(trail_base) PASS_REGS);
1702 }
1703 }
1704 }
1705#if MULTI_ASSIGNMENT_VARIABLES
1706 else {
1707 CELL *cptr = RepAppl(trail_cell);
1708 /* This is a bit complex. The idea is that we may have several
1709 trailings for the same mavar in the same trail segment. Essentially,
1710 the problem arises because of !. What we want is to ignore all but
1711 the last entry, or in this case, all but the first entry with the last
1712 value.
1713
1714 */
1715 if (cptr < (CELL *)gc_B && cptr >= gc_H) {
1716 goto remove_trash_entry;
1717 } else if (IsAttVar(cptr)) {
1718 /* MABINDING that should be recovered */
1719 if (detatt && cptr < detatt) {
1720 goto remove_trash_entry;
1721 } else {
1722 /* This attributed variable is still in play */
1723 mark_variable(cptr PASS_REGS);
1724 }
1725 }
1726 if (!gc_lookup_ma_var(cptr, trail_base PASS_REGS)) {
1727 /* check whether this is the first time we see it*/
1728 Term t0 = TrailTerm(trail_base+1);
1729
1730 if (!IsAtomicTerm(t0)) {
1731 CELL *next = GET_NEXT(t0);
1732 /* check if we have a garbage entry, where we are setting a
1733 pointer to ourselves. */
1734 if (next < (CELL *)gc_B && next >= gc_H) {
1735 goto remove_trash_entry;
1736 }
1737 }
1738 if (HEAP_PTR(trail_cell)) {
1739 /* fool the gc into thinking this is a variable */
1740 TrailTerm(trail_base) = (CELL)cptr;
1741 mark_external_reference(&(TrailTerm(trail_base)) PASS_REGS);
1742 /* reset the gc to believe the original tag */
1743 TrailTerm(trail_base) = AbsAppl((CELL *)TrailTerm(trail_base));
1744 }
1745#ifdef FROZEN_STACKS
1746 mark_external_reference(&(TrailVal(trail_base)) PASS_REGS);
1747 trail_base++;
1748 if (HEAP_PTR(trail_cell)) {
1749 TrailTerm(trail_base) = (CELL)cptr;
1750 mark_external_reference(&(TrailTerm(trail_base)) PASS_REGS);
1751 /* reset the gc to believe the original tag */
1752 TrailTerm(trail_base) = AbsAppl((CELL *)TrailTerm(trail_base));
1753 }
1754 /* don't need to mark the next TrailVal, this is done at the end
1755 of segment */
1756#else
1757 trail_base++;
1758 mark_external_reference(&(TrailTerm(trail_base)) PASS_REGS);
1759 trail_base ++;
1760 if (HEAP_PTR(trail_cell)) {
1761 /* fool the gc into thinking this is a variable */
1762 TrailTerm(trail_base) = (CELL)cptr;
1763 mark_external_reference(&(TrailTerm(trail_base)) PASS_REGS);
1764 /* reset the gc to believe the original tag */
1765 TrailTerm(trail_base) = AbsAppl((CELL *)TrailTerm(trail_base));
1766 }
1767#endif /* TABLING */
1768 } else {
1769 remove_trash_entry:
1770 /* we can safely ignore this little monster */
1771#ifdef FROZEN_STACKS
1772 LOCAL_discard_trail_entries += 2;
1773 RESET_VARIABLE(&TrailTerm(trail_base));
1774 RESET_VARIABLE(&TrailVal(trail_base));
1775#else
1776 LOCAL_discard_trail_entries += 3;
1777 RESET_VARIABLE(&TrailTerm(trail_base));
1778 trail_base++;
1779 RESET_VARIABLE(&TrailTerm(trail_base));
1780#endif
1781 trail_base++;
1782 RESET_VARIABLE(&TrailTerm(trail_base));
1783#ifdef FROZEN_STACKS
1784 RESET_VARIABLE(&TrailVal(trail_base));
1785#endif
1786 }
1787 }
1788#endif
1789 trail_base++;
1790 }
1791#if TABLING
1792 /*
1793 Ugly, but needed: we're not really sure about what were the new
1794 values until the very end
1795 */
1796 {
1797 gc_ma_hash_entry *gl = LOCAL_gc_ma_h_list;
1798 while (gl) {
1799 mark_external_reference(&(TrailVal(gl->loc+1)) PASS_REGS);
1800 gl = gl->more;
1801 }
1802 }
1803#endif /* TABLING */
1804#ifdef EASY_SHUNTING
1805 /* set back old variables */
1806 LOCAL_sTR = (tr_fr_ptr)old_cont_top0;
1807 while (begsTR != NULL) {
1808 tr_fr_ptr newsTR = (tr_fr_ptr)TrailTerm(begsTR);
1809 TrailTerm(LOCAL_sTR) = TrailTerm(begsTR+1);
1810 TrailTerm(LOCAL_sTR+1) = TrailTerm(begsTR+2);
1811 begsTR = newsTR;
1812 LOCAL_sTR += 2;
1813 }
1814 LOCAL_sTR0 = OldsTR0;
1815#else
1816 LOCAL_cont_top0 = old_cont_top0;
1817#endif
1818 LOCAL_cont_top = LOCAL_cont_top0;
1819}
1820
1821/*
1822 * mark all heap objects accessible from each choicepoint & its chain of
1823 * environments
1824 */
1825
1826#ifdef TABLING
1827#define init_substitution_pointer(GCB, SUBS_PTR, DEP_FR) \
1828 if (DepFr_leader_cp(DEP_FR) == GCB) { \
1829 /* GCB is a generator-consumer node */ \
1830 /* never here if batched scheduling */ \
1831 SUBS_PTR = (CELL *) (GEN_CP(GCB) + 1); \
1832 SUBS_PTR += SgFr_arity(GEN_CP(GCB)->cp_sg_fr); \
1833 } else { \
1834 SUBS_PTR = (CELL *) (CONS_CP(GCB) + 1); \
1835 }
1836#endif /* TABLING */
1837
1838
1839#ifdef TABLING
1840static choiceptr
1841youngest_cp(choiceptr gc_B, dep_fr_ptr *depfrp)
1842{
1843 dep_fr_ptr depfr = *depfrp;
1844 choiceptr min = gc_B;
1845
1846 if (!gc_B) {
1847 return gc_B;
1848 }
1849 if (depfr && min > DepFr_cons_cp(depfr)) {
1850 min = DepFr_cons_cp(depfr);
1851 }
1852 if (depfr && min == DepFr_cons_cp(depfr)) {
1853 *depfrp = DepFr_next(depfr);
1854 }
1855 return min;
1856}
1857#endif /* TABLING */
1858
1859
1860static void
1861mark_choicepoints(register choiceptr gc_B, tr_fr_ptr saved_TR, bool very_verbose USES_REGS)
1862{
1863 OPCODE
1864 trust_lu = Yap_opcode(_trust_logical),
1865 count_trust_lu = Yap_opcode(_count_trust_logical),
1866 profiled_trust_lu = Yap_opcode(_profiled_trust_logical);
1867
1868 yamop *lu_cl0 = NEXTOP(PredLogUpdClause0->CodeOfPred,Otapl),
1869 *lu_cl = NEXTOP(PredLogUpdClause->CodeOfPred,Otapl),
1870 *lu_cle = NEXTOP(PredLogUpdClauseErase->CodeOfPred,Otapl),
1871 *su_cl = NEXTOP(PredStaticClause->CodeOfPred,Otapl);
1872#ifdef TABLING
1873 dep_fr_ptr depfr = LOCAL_top_dep_fr;
1874 sg_fr_ptr aux_sg_fr = LOCAL_top_sg_fr;
1875
1876 gc_B = youngest_cp(gc_B, &depfr);
1877#endif /* TABLING */
1878 while (gc_B != NULL) {
1879 op_numbers opnum;
1880 register OPCODE op;
1881 yamop *rtp = gc_B->cp_ap;
1882
1883 /* if (gc_B->cp_ap) */
1884 /* fprintf(stderr,"B %p->%p %s\n", gc_B, gc_B->cp_b, Yap_op_names[Yap_op_from_opcode(gc_B->cp_ap->opc)]) ; */
1885 /* else */
1886 /* fprintf(stderr,"B %p->%p\n", gc_B, gc_B->cp_b); */
1887 mark_db_fixed((CELL *)rtp PASS_REGS);
1888#ifdef DETERMINISTIC_TABLING
1889 if (!IS_DET_GEN_CP(gc_B))
1890#endif /* DETERMINISTIC_TABLING */
1891 mark_db_fixed((CELL *)(gc_B->cp_cp) PASS_REGS);
1892#ifdef EASY_SHUNTING
1893 LOCAL_current_B = gc_B;
1894 LOCAL_prev_HB = HB;
1895#endif
1896 HB = gc_B->cp_h;
1897#ifdef INSTRUMENT_GC
1898 num_bs++;
1899#endif
1900#ifdef TABLING
1901 if (rtp == NULL) {
1902 if (aux_sg_fr && gc_B == SgFr_gen_cp(aux_sg_fr)) {
1903 /* found generator */
1904 opnum = _table_completion;
1905 } else {
1906 /* found sld node is done */
1907 opnum = _trust_fail;
1908 }
1909 } else {
1910#endif /* TABLING */
1911 op = rtp->opc;
1912 opnum = Yap_op_from_opcode(op);
1913 // fprintf(stderr, "%s\n", Yap_op_names[opnum]);
1914#ifdef TABLING
1915 }
1916 // printf("MARK CP %p (%d)\n", gc_B, opnum);
1917 if (aux_sg_fr && gc_B == SgFr_gen_cp(aux_sg_fr)) {
1918 aux_sg_fr = SgFr_next(aux_sg_fr);
1919 }
1920#endif /* TABLING */
1921 if (very_verbose) {
1922 PredEntry *pe = Yap_PredForChoicePt(gc_B, NULL);
1923#if defined(ANALYST)
1924 if (pe == NULL) {
1925 fprintf(stderr,"%% marked " UInt_FORMAT " (%s)\n", LOCAL_total_marked, Yap_op_names[opnum]);
1926 } else if (pe->ArityOfPE) {
1927 fprintf(stderr,"%% %s/" UInt_FORMAT " marked " UInt_FORMAT " (%s)\n", RepAtom(NameOfFunctor(pe->FunctorOfPred))->StrOfAE, pe->ArityOfPE, LOCAL_total_marked, Yap_op_names[opnum]);
1928 } else {
1929 fprintf(stderr,"%% %s marked " UInt_FORMAT " (%s)\n", RepAtom((Atom)(pe->FunctorOfPred))->StrOfAE, LOCAL_total_marked, Yap_op_names[opnum]);
1930 }
1931#else
1932 if (pe == NULL) {
1933 fprintf(stderr,"%% marked " Int_FORMAT " (%u)\n", LOCAL_total_marked, (unsigned int)opnum);
1934 } else if (pe->ArityOfPE) {
1935 fprintf(stderr,"%% %s/%lu marked " Int_FORMAT " (%u)\n", RepAtom(NameOfFunctor(pe->FunctorOfPred))->StrOfAE, (unsigned long int)pe->ArityOfPE, LOCAL_total_marked, (unsigned int)opnum);
1936 } else {
1937 fprintf(stderr,"%% %s marked " Int_FORMAT " (%u)\n", RepAtom((Atom)(pe->FunctorOfPred))->StrOfAE, LOCAL_total_marked, (unsigned int)opnum);
1938 }
1939#endif
1940 }
1941 {
1942 /* find out how many cells are still alive in the trail */
1943 mark_trail(saved_TR, gc_B->cp_tr, gc_B->cp_h, gc_B PASS_REGS);
1944 saved_TR = gc_B->cp_tr;
1945 }
1946 if (opnum == _or_else || opnum == _or_last) {
1947 /* ; choice point */
1948 mark_environments((CELL_PTR) (gc_B->cp_a1),gc_B->cp_cp,
1949 -gc_B->cp_cp->y_u.Osblp.s / ((OPREG)sizeof(CELL)),
1950 gc_B->cp_cp->y_u.Osblp.bmap
1951 PASS_REGS);
1952 } else {
1953 /* choicepoint with arguments */
1954 register CELL_PTR saved_reg;
1955 OPREG nargs;
1956
1957 //printf("gc_B=%p %ld\n", gc_B, opnum);
1958 if (opnum == _Nstop)
1959 mark_environments((CELL_PTR) gc_B->cp_env,NOCODE,
1960 EnvSizeInCells,
1961 NULL PASS_REGS);
1962 else if (opnum != _trust_fail) {
1963 Int mark = TRUE;
1964#ifdef DETERMINISTIC_TABLING
1965 mark &= !IS_DET_GEN_CP(gc_B);
1966#endif /* DETERMINISTIC_TABLING */
1967 if (mark)
1968 mark_environments((CELL_PTR) gc_B->cp_env,gc_B->cp_cp,
1969 EnvSize((yamop *) (gc_B->cp_cp)),
1970 EnvBMap((yamop *) (gc_B->cp_cp)) PASS_REGS);
1971 }
1972 /* extended choice point */
1973 restart_cp:
1974 switch (opnum) {
1975 case _Nstop:
1976 if (gc_B->cp_env == LCL0) {
1977 return;
1978 } else {
1979 // This must be a border choicepoint, just move up
1980 gc_B = (choiceptr)(gc_B->cp_env[E_B]);
1981 continue;
1982 }
1983 case _retry_c:
1984 case _retry_userc:
1985 if (gc_B->cp_ap == RETRY_C_RECORDED_K_CODE
1986 || gc_B->cp_ap == RETRY_C_RECORDEDP_CODE) {
1987 /* we have a reference from the choice-point stack to a term */
1988 choiceptr old_b = B;
1989 DBRef ref;
1990 B = gc_B;
1991 ref = (DBRef)EXTRA_CBACK_ARG(3,1);
1992 if (IsVarTerm((CELL)ref)) {
1993 mark_ref_in_use(ref PASS_REGS);
1994 } else {
1995 if (ONCODE((CELL *)ref)) {
1996 mark_db_fixed(RepAppl((CELL)ref) PASS_REGS);
1997 }
1998 }
1999 B = old_b;
2000 }
2001 nargs = rtp->y_u.OtapFs.s+rtp->y_u.OtapFs.extra;
2002 break;
2003 case _jump:
2004 rtp = rtp->y_u.l.l;
2005 op = rtp->opc;
2006 opnum = Yap_op_from_opcode(op);
2007 goto restart_cp;
2008 case _retry_profiled:
2009 case _count_retry:
2010 rtp = NEXTOP(rtp,l);
2011 op = rtp->opc;
2012 opnum = Yap_op_from_opcode(op);
2013 goto restart_cp;
2014 case _trust_fail:
2015 nargs = 0;
2016 break;
2017#ifdef TABLING
2018 case _table_load_answer:
2019 {
2020 CELL *vars_ptr, vars;
2021 vars_ptr = (CELL *) (LOAD_CP(gc_B) + 1);
2022 vars = *vars_ptr++;
2023 while (vars--) {
2024 mark_external_reference(vars_ptr PASS_REGS);
2025 vars_ptr++;
2026 }
2027 }
2028 nargs = 0;
2029 break;
2030 case _table_try_answer:
2031 case _table_retry_me:
2032 case _table_trust_me:
2033 case _table_retry:
2034 case _table_trust:
2035 {
2036 CELL *vars_ptr, vars;
2037 vars_ptr = (CELL *)(GEN_CP(gc_B) + 1);
2038 nargs = rtp->y_u.Otapl.s;
2039 while (nargs--) {
2040 mark_external_reference(vars_ptr PASS_REGS);
2041 vars_ptr++;
2042 }
2043 vars = *vars_ptr++;
2044 while (vars--) {
2045 mark_external_reference(vars_ptr PASS_REGS);
2046 vars_ptr++;
2047 }
2048 }
2049 nargs = 0;
2050 break;
2051 case _table_completion:
2052#ifdef THREADS_CONSUMER_SHARING
2053 case _table_answer_resolution_completion:
2054#endif /* THREADS_CONSUMER_SHARING */
2055 {
2056 CELL *vars_ptr, vars;
2057#ifdef DETERMINISTIC_TABLING
2058 if (IS_DET_GEN_CP(gc_B))
2059 vars_ptr = (CELL *)(DET_GEN_CP(gc_B) + 1);
2060 else
2061#endif /* DETERMINISTIC_TABLING */
2062 {
2063 vars_ptr = (CELL *)(GEN_CP(gc_B) + 1);
2064 nargs = SgFr_arity(GEN_CP(gc_B)->cp_sg_fr);
2065 while (nargs--) {
2066 mark_external_reference(vars_ptr PASS_REGS);
2067 vars_ptr++;
2068 }
2069 }
2070 vars = *vars_ptr++;
2071 while (vars--) {
2072 mark_external_reference(vars_ptr PASS_REGS);
2073 vars_ptr++;
2074 }
2075 }
2076 nargs = 0;
2077 break;
2078 case _table_answer_resolution:
2079 {
2080 CELL *vars_ptr, vars;
2081 dep_fr_ptr dep_fr = CONS_CP(gc_B)->cp_dep_fr;
2082 ans_node_ptr ans_node = DepFr_last_answer(dep_fr);
2083 if (TRUE || TrNode_child(ans_node)) {
2084 /* unconsumed answers */
2085#ifdef MODE_DIRECTED_TABLING
2086 if (TrNode_child(ans_node) && IS_ANSWER_INVALID_NODE(TrNode_child(ans_node))) {
2087 ans_node_ptr old_ans_node;
2088 old_ans_node = ans_node;
2089 ans_node = TrNode_child(ans_node);
2090 do {
2091 ans_node = TrNode_child(ans_node);
2092 } while (IS_ANSWER_INVALID_NODE(ans_node));
2093 TrNode_child(old_ans_node) = ans_node;
2094 } else
2095#endif /* MODE_DIRECTED_TABLING */
2096 ans_node = TrNode_child(ans_node);
2097 if (gc_B == DepFr_leader_cp(dep_fr)) {
2098 /* gc_B is a generator-consumer node */
2099 /* never here if batched scheduling */
2100 TABLING_ERROR_CHECKING(generator_consumer, IS_BATCHED_GEN_CP(gc_B));
2101 vars_ptr = (CELL *) (GEN_CP(gc_B) + 1);
2102 vars_ptr += SgFr_arity(GEN_CP(gc_B)->cp_sg_fr);
2103 } else {
2104 vars_ptr = (CELL *) (CONS_CP(gc_B) + 1);
2105 }
2106
2107 vars = *vars_ptr++;
2108 while (vars--) {
2109 mark_external_reference(vars_ptr PASS_REGS);
2110 vars_ptr++;
2111 }
2112 }
2113 }
2114 nargs = 0;
2115 break;
2116 case _trie_trust_var:
2117 case _trie_retry_var:
2118 case _trie_trust_var_in_pair:
2119 case _trie_retry_var_in_pair:
2120 case _trie_trust_val:
2121 case _trie_retry_val:
2122 case _trie_trust_val_in_pair:
2123 case _trie_retry_val_in_pair:
2124 case _trie_trust_atom:
2125 case _trie_retry_atom:
2126 case _trie_trust_atom_in_pair:
2127 case _trie_retry_atom_in_pair:
2128 case _trie_trust_null:
2129 case _trie_retry_null:
2130 case _trie_trust_null_in_pair:
2131 case _trie_retry_null_in_pair:
2132 case _trie_trust_pair:
2133 case _trie_retry_pair:
2134 case _trie_trust_appl:
2135 case _trie_retry_appl:
2136 case _trie_trust_appl_in_pair:
2137 case _trie_retry_appl_in_pair:
2138 case _trie_trust_extension:
2139 case _trie_retry_extension:
2140 case _trie_trust_double:
2141 case _trie_retry_double:
2142 case _trie_trust_longint:
2143 case _trie_retry_longint:
2144 case _trie_trust_gterm:
2145 case _trie_retry_gterm:
2146 {
2147 CELL *vars_ptr;
2148 int heap_arity, vars_arity, subs_arity;
2149 vars_ptr = (CELL *)(gc_B + 1);
2150 heap_arity = vars_ptr[0];
2151 vars_arity = vars_ptr[1 + heap_arity];
2152 subs_arity = vars_ptr[2 + heap_arity + vars_arity];
2153 vars_ptr += 2 + heap_arity + subs_arity + vars_arity;
2154 if (subs_arity) {
2155 while (subs_arity--) {
2156 mark_external_reference(vars_ptr PASS_REGS);
2157 vars_ptr--;
2158 }
2159 }
2160 vars_ptr--; /* skip subs_arity entry */
2161 if (vars_arity) {
2162 while (vars_arity--) {
2163 mark_external_reference(vars_ptr PASS_REGS);
2164 vars_ptr--;
2165 }
2166 }
2167 vars_ptr--; /* skip vars_arity entry */
2168 if (heap_arity) {
2169 while (heap_arity--) {
2170 if (*vars_ptr == 0) /* double/longint extension mark */
2171 break;
2172 mark_external_reference(vars_ptr PASS_REGS);
2173 vars_ptr--;
2174 }
2175 }
2176 }
2177 nargs = 0;
2178 break;
2179#endif /* TABLING */
2180 case _profiled_retry_and_mark:
2181 case _count_retry_and_mark:
2182 case _retry_and_mark:
2183 mark_ref_in_use((DBRef)ClauseCodeToDynamicClause(gc_B->cp_ap) PASS_REGS);
2184 case _retry2:
2185 nargs = 2;
2186 break;
2187 case _retry3:
2188 nargs = 3;
2189 break;
2190 case _retry4:
2191 nargs = 4;
2192 break;
2193 case _try_logical:
2194 case _retry_logical:
2195 {
2196 /* find out who owns this sequence of try-retry-trust */
2197 /* I don't like this code, it's a bad idea to do a linear scan,
2198 on the other hand it's the only way we can be sure we can reclaim
2199 space
2200 */
2201 yamop *end = rtp->y_u.OtaLl.n;
2202 while (end->opc != trust_lu &&
2203 end->opc != count_trust_lu &&
2204 end->opc != profiled_trust_lu )
2205 end = end->y_u.OtaLl.n;
2206 mark_ref_in_use((DBRef)end->y_u.OtILl.block PASS_REGS);
2207 }
2208 /* mark timestamp */
2209 nargs = rtp->y_u.OtaLl.s+1;
2210 break;
2211 case _count_retry_logical:
2212 {
2213 /* find out who owns this sequence of try-retry-trust */
2214 /* I don't like this code, it's a bad idea to do a linear scan,
2215 on the other hand it's the only way we can be sure we can reclaim
2216 space
2217 */
2218 yamop *end = rtp->y_u.OtaLl.n;
2219 while (Yap_op_from_opcode(end->opc) != _count_trust_logical)
2220 end = end->y_u.OtaLl.n;
2221 mark_ref_in_use((DBRef)end->y_u.OtILl.block PASS_REGS);
2222 }
2223 /* mark timestamp */
2224 nargs = rtp->y_u.OtaLl.s+1;
2225 break;
2226 case _profiled_retry_logical:
2227 {
2228 /* find out who owns this sequence of try-retry-trust */
2229 /* I don't like this code, it's a bad idea to do a linear scan,
2230 on the other hand it's the only way we can be sure we can reclaim
2231 space
2232 */
2233 yamop *end = rtp->y_u.OtaLl.n;
2234 while (Yap_op_from_opcode(end->opc) != _profiled_trust_logical)
2235 end = end->y_u.OtaLl.n;
2236 mark_ref_in_use((DBRef)end->y_u.OtILl.block PASS_REGS);
2237 }
2238 /* mark timestamp */
2239 nargs = rtp->y_u.OtaLl.s+1;
2240 break;
2241 case _trust_logical:
2242 case _count_trust_logical:
2243 case _profiled_trust_logical:
2244 /* mark timestamp */
2245 mark_ref_in_use((DBRef)rtp->y_u.OtILl.block PASS_REGS);
2246 nargs = rtp->y_u.OtILl.d->ClPred->ArityOfPE+1;
2247 break;
2248 case _retry_exo:
2249 case _retry_exo_udi:
2250 case _retry_all_exo:
2251 nargs = rtp->y_u.lp.p->ArityOfPE;
2252 break;
2253 case _retry_udi:
2254 nargs = rtp->y_u.p.p->ArityOfPE;
2255 break;
2256#ifdef DEBUG
2257 case _retry_me:
2258 case _trust_me:
2259 case _profiled_retry_me:
2260 case _profiled_trust_me:
2261 case _count_retry_me:
2262 case _count_trust_me:
2263 case _retry:
2264 case _trust:
2265 if (IN_BETWEEN(H0,(CELL *)(gc_B->cp_ap),HR)) {
2266 fprintf(stderr,"OOPS in GC: gc not supported in this case!!!\n");
2267 exit(1);
2268 }
2269 nargs = rtp->y_u.Otapl.s;
2270 break;
2271 default:
2272 fprintf(stderr, "OOPS in GC: Unexpected opcode: %d\n", opnum);
2273 nargs = 0;
2274#else
2275 default:
2276 nargs = rtp->y_u.Otapl.s;
2277#endif
2278 }
2279
2280
2281 if (gc_B->cp_ap == lu_cl0 ||
2282 gc_B->cp_ap == lu_cl ||
2283 gc_B->cp_ap == lu_cle ||
2284 gc_B->cp_ap == su_cl) {
2285 yamop *pt = (yamop *)IntegerOfTerm(gc_B->cp_args[1]);
2286 if (gc_B->cp_ap == su_cl) {
2287 mark_db_fixed((CELL *)pt PASS_REGS);
2288 } else {
2289 while (pt->opc != trust_lu &&
2290 pt->opc != count_trust_lu &&
2291 pt->opc != profiled_trust_lu
2292 )
2293 pt = pt->y_u.OtaLl.n;
2294 mark_ref_in_use((DBRef)pt->y_u.OtILl.block PASS_REGS);
2295 }
2296 }
2297 /* for each saved register */
2298 for (saved_reg = &gc_B->cp_a1;
2299 /* assumes we can count registers in CP this
2300 way */
2301 saved_reg < &gc_B->cp_a1 + nargs;
2302 saved_reg++) {
2303 mark_external_reference(saved_reg PASS_REGS);
2304 }
2305 }
2306#if TABLING
2307 gc_B = youngest_cp(gc_B->cp_b, &depfr);
2308#else
2309 gc_B = gc_B->cp_b;
2310#endif /* TABLING */
2311 }
2312}
2313
2314
2315
2316
2317/*
2318 * insert a cell which points to a heap object into relocation chain of that
2319 * object
2320 */
2321
2322static inline void
2323into_relocation_chain(CELL_PTR current, CELL_PTR next USES_REGS)
2324{
2325 CELL current_tag;
2326
2327 current_tag = TAG(*current);
2328 if (RMARKED(next))
2329 RMARK(current);
2330 else {
2331 UNRMARK(current);
2332 RMARK(next);
2333 }
2334 *current = *next;
2335 *next = (CELL) current | current_tag;
2336}
2337
2338
2339static void
2340CleanDeadClauses( USES_REGS1 )
2341{
2342 {
2343 StaticClause **cptr;
2344 StaticClause *cl;
2345
2346 cptr = &(DeadStaticClauses);
2347 cl = DeadStaticClauses;
2348 while (cl) {
2349 if (!ref_in_use((DBRef)cl PASS_REGS)) {
2350 char *ocl = (char *)cl;
2351 Yap_ClauseSpace -= cl->ClSize;
2352 cl = cl->ClNext;
2353 *cptr = cl;
2354 Yap_FreeCodeSpace(ocl);
2355 } else {
2356 cptr = &(cl->ClNext);
2357 cl = cl->ClNext;
2358 }
2359 }
2360 }
2361 {
2362 StaticIndex **cptr;
2363 StaticIndex *cl;
2364
2365 cptr = &(DeadStaticIndices);
2366 cl = DeadStaticIndices;
2367 while (cl) {
2368 if (!ref_in_use((DBRef)cl PASS_REGS)) {
2369 char *ocl = (char *)cl;
2370 if (cl->ClFlags & SwitchTableMask)
2371 Yap_IndexSpace_SW -= cl->ClSize;
2372 else
2373 Yap_IndexSpace_Tree -= cl->ClSize;
2374 cl = cl->SiblingIndex;
2375 *cptr = cl;
2376 Yap_FreeCodeSpace(ocl);
2377 } else {
2378 cptr = &(cl->SiblingIndex);
2379 cl = cl->SiblingIndex;
2380 }
2381 }
2382 }
2383 {
2384 MegaClause **cptr;
2385 MegaClause *cl;
2386
2387 cptr = &(DeadMegaClauses);
2388 cl = DeadMegaClauses;
2389 while (cl) {
2390 if (!ref_in_use((DBRef)cl PASS_REGS)) {
2391 char *ocl = (char *)cl;
2392 Yap_ClauseSpace -= cl->ClSize;
2393 cl = cl->ClNext;
2394 *cptr = cl;
2395 Yap_FreeCodeSpace(ocl);
2396 } else {
2397 cptr = &(cl->ClNext);
2398 cl = cl->ClNext;
2399 }
2400 }
2401 }
2402}
2403
2404/* insert trail cells which point to heap objects into relocation chains */
2405
2406static void
2407sweep_trail(choiceptr gc_B, tr_fr_ptr old_TR, gc_entry_info_t *info USES_REGS)
2408{
2409 tr_fr_ptr trail_ptr, dest;
2410 Int OldHeapUsed = HeapUsed;
2411
2412 sweep_regs(info->a, old_TR, info->p_env PASS_REGS);
2413
2414#ifndef FROZEN_STACKS
2415 {
2416 choiceptr current = gc_B;
2417 choiceptr next = gc_B->cp_b;
2418 tr_fr_ptr source, dest;
2419
2420 /* invert cp ptrs */
2421 current->cp_b = NULL;
2422 while (next) {
2423 choiceptr n = next;
2424 next = n->cp_b;
2425 n->cp_b = current;
2426 current = n;
2427 }
2428
2429 next = current;
2430 current = NULL;
2431 /* next, clean trail */
2432 source = dest = (tr_fr_ptr)LOCAL_TrailBase;
2433 while (source < old_TR) {
2434 CELL trail_cell;
2435
2436 while (next && source == next->cp_tr) {
2437 choiceptr b = next;
2438 b->cp_tr = dest;
2439 next = b->cp_b;
2440 b->cp_b = current;
2441 current = b;
2442 }
2443 trail_cell = TrailTerm(source);
2444 if (trail_cell != (CELL)source) {
2445 dest++;
2446 }
2447 source++;
2448 }
2449 while (next) {
2450 choiceptr b = next;
2451 b->cp_tr = dest;
2452 next = b->cp_b;
2453 b->cp_b = current;
2454 current = b;
2455 }
2456 }
2457#endif /* FROZEN_STACKS */
2458
2459 /* next, follows the real trail entries */
2460 trail_ptr = (tr_fr_ptr)LOCAL_TrailBase;
2461 dest = trail_ptr;
2462 while (trail_ptr < old_TR) {
2463 register CELL trail_cell;
2464
2465 trail_cell = TrailTerm(trail_ptr);
2466
2467#ifndef FROZEN_STACKS
2468 /* recover a trail cell */
2469 if (trail_cell == (CELL)trail_ptr) {
2470 TrailTerm(dest) = trail_cell;
2471 trail_ptr++;
2472 /* just skip cell */
2473 } else
2474#endif
2475 {
2476 TrailTerm(dest) = trail_cell;
2477 if (IsVarTerm(trail_cell)) {
2478 /* we need to check whether this is a honest to god trail entry */
2479 /* make sure it is a heap cell before we test whether it has been marked */
2480 if ((CELL *)trail_cell < HR && (CELL *)trail_cell >= H0 && MARKED_PTR((CELL *)trail_cell)) {
2481 if (HEAP_PTR(trail_cell)) {
2482 into_relocation_chain(&TrailTerm(dest), GET_NEXT(trail_cell) PASS_REGS);
2483 }
2484 }
2485#ifdef FROZEN_STACKS
2486 /* it is complex to recover cells with frozen segments */
2487 TrailVal(dest) = TrailVal(trail_ptr);
2488 if (MARKED_PTR(&TrailVal(dest))) {
2489 if (HEAP_PTR(TrailVal(dest))) {
2490 into_relocation_chain(&TrailVal(dest), GET_NEXT(TrailVal(dest)) PASS_REGS);
2491 }
2492 }
2493#endif
2494 } else if (IsPairTerm(trail_cell)) {
2495 CELL *pt0 = RepPair(trail_cell);
2496 CELL flags;
2497
2498 if (IN_BETWEEN(LOCAL_GlobalBase, pt0, HR)) {
2499 if (GlobalIsAttVar(pt0)) {
2500 TrailTerm(dest) = trail_cell;
2501 /* be careful with partial gc */
2502 if (HEAP_PTR(TrailTerm(dest))) {
2503 into_relocation_chain(&TrailTerm(dest), GET_NEXT(trail_cell) PASS_REGS);
2504 }
2505 } else {
2506 TrailTerm(dest) = trail_cell;
2507 /* be careful with partial gc */
2508 if (HEAP_PTR(TrailTerm(dest))) {
2509 into_relocation_chain(&TrailTerm(dest), GET_NEXT(trail_cell) PASS_REGS);
2510 }
2511 }
2512 dest++;
2513 trail_ptr++;
2514 continue;
2515 }
2516#ifdef FROZEN_STACKS /* TRAIL */
2517 /* process all segments */
2518 if (
2519#ifdef YAPOR_SBA
2520 (ADDR) pt0 >= LOCAL_GlobalBase
2521#else
2522 (ADDR) pt0 >= LOCAL_TrailBase
2523#endif
2524 ) {
2525 trail_ptr++;
2526 dest++;
2527 continue;
2528 }
2529#endif /* FROZEN_STACKS */
2530 flags = *pt0;
2531#ifdef DEBUG0
2532 hp_entrs++;
2533 if (!ref_in_use((DBRef)pt0 PASS_REGS)) {
2534 hp_not_in_use++;
2535 if (!FlagOn(DBClMask, flags)) {
2536 code_entries++;
2537 }
2538 if (FlagOn(ErasedMask, flags)) {
2539 hp_erased++;
2540 }
2541 } else {
2542 if (FlagOn(ErasedMask, flags)) {
2543 hp_in_use_erased++;
2544 }
2545 }
2546#endif
2547 if (!ref_in_use((DBRef)pt0 PASS_REGS)) {
2548 if (FlagOn(DBClMask, flags)) {
2549 DBRef dbr = (DBRef) ((CELL)pt0 - (CELL) &(((DBRef) NIL)->Flags));
2550 dbr->Flags &= ~InUseMask;
2551 DEC_DBREF_COUNT(dbr);
2552 if (dbr->Flags & ErasedMask) {
2553 Yap_ErDBE(dbr);
2554 }
2555 } else {
2556 if (flags & LogUpdMask) {
2557 if (flags & IndexMask) {
2558 LogUpdIndex *indx = ClauseFlagsToLogUpdIndex(pt0);
2559 int erase;
2560#if defined(YAPOR) || defined(THREADS)
2561 /*
2562 gc may be called when executing a dynamic goal,
2563 check PP to avoid deadlock
2564 */
2565 PredEntry *ap = indx->ClPred;
2566 if (ap != PP)
2567 PELOCK(85,ap);
2568#endif
2569 DEC_CLREF_COUNT(indx);
2570 indx->ClFlags &= ~InUseMask;
2571 erase = (indx->ClFlags & ErasedMask
2572 && !indx->ClRefCount);
2573 if (erase) {
2574 /* at this point,
2575 no one is accessing the clause */
2576 Yap_ErLogUpdIndex(indx);
2577 }
2578#if defined(YAPOR) || defined(THREADS)
2579 if (ap != PP)
2580 UNLOCK(ap->PELock);
2581#endif
2582 } else {
2583 LogUpdClause *cl = ClauseFlagsToLogUpdClause(pt0);
2584#if defined(YAPOR) || defined(THREADS)
2585 PredEntry *ap = cl->ClPred;
2586#endif
2587 int erase;
2588
2589#if defined(YAPOR) || defined(THREADS)
2590 if (ap != PP)
2591 PELOCK(86,ap);
2592#endif
2593 DEC_CLREF_COUNT(cl);
2594 cl->ClFlags &= ~InUseMask;
2595 erase = ((cl->ClFlags & ErasedMask) && !cl->ClRefCount);
2596 if (erase) {
2597 /* at this point,
2598 no one is accessing the clause */
2599 Yap_ErLogUpdCl(cl);
2600 }
2601#if defined(YAPOR) || defined(THREADS)
2602 if (ap != PP)
2603 UNLOCK(ap->PELock);
2604#endif
2605 }
2606 } else {
2607 DynamicClause *cl = ClauseFlagsToDynamicClause(pt0);
2608 int erase;
2609 DEC_CLREF_COUNT(cl);
2610 cl->ClFlags &= ~InUseMask;
2611 erase = (cl->ClFlags & ErasedMask)
2612#if defined(YAPOR) || defined(THREADS)
2613 && (cl->ClRefCount == 0)
2614#endif
2615 ;
2616 if (erase) {
2617 /* at this point,
2618 no one is accessing the clause */
2619 Yap_ErCl(cl);
2620 }
2621 }
2622 }
2623 RESET_VARIABLE(&TrailTerm(dest));
2624#ifdef FROZEN_STACKS
2625 RESET_VARIABLE(&TrailVal(dest));
2626#endif
2627 LOCAL_discard_trail_entries++;
2628 }
2629#if MULTI_ASSIGNMENT_VARIABLES
2630 } else {
2631#ifdef FROZEN_STACKS
2632 CELL trail_cell = TrailTerm(trail_ptr+1);
2633 CELL old = TrailVal(trail_ptr);
2634 CELL old1 = TrailVal(trail_ptr+1);
2635 Int marked_ptr = MARKED_PTR(&TrailTerm(trail_ptr+1));
2636 Int marked_val_old = MARKED_PTR(&TrailVal(trail_ptr));
2637 Int marked_val_ptr = MARKED_PTR(&TrailVal(trail_ptr+1));
2638
2639 TrailTerm(dest+1) = TrailTerm(dest) = trail_cell;
2640 TrailVal(dest) = old;
2641 TrailVal(dest+1) = old1;
2642 if (marked_ptr) {
2643 UNMARK(&TrailTerm(dest));
2644 UNMARK(&TrailTerm(dest+1));
2645 if (HEAP_PTR(trail_cell)) {
2646 into_relocation_chain(&TrailTerm(dest), GET_NEXT(trail_cell) PASS_REGS);
2647 into_relocation_chain(&TrailTerm(dest+1), GET_NEXT(trail_cell) PASS_REGS);
2648 }
2649 }
2650 if (marked_val_old) {
2651 UNMARK(&TrailVal(dest));
2652 if (HEAP_PTR(old)) {
2653 into_relocation_chain(&TrailVal(dest), GET_NEXT(old) PASS_REGS);
2654 }
2655 }
2656 if (marked_val_ptr) {
2657 UNMARK(&TrailVal(dest+1));
2658 if (HEAP_PTR(old1)) {
2659 into_relocation_chain(&TrailVal(dest+1), GET_NEXT(old1) PASS_REGS);
2660 }
2661 }
2662 trail_ptr ++;
2663 dest ++;
2664#else
2665 CELL trail_cell = TrailTerm(trail_ptr+2);
2666 CELL old = TrailTerm(trail_ptr+1);
2667 Int marked_ptr = MARKED_PTR(&TrailTerm(trail_ptr+2));
2668 Int marked_old = MARKED_PTR(&TrailTerm(trail_ptr+1));
2669 CELL *ptr;
2670 /* be sure we don't overwrite before we read */
2671
2672 if (marked_ptr)
2673 ptr = RepAppl(UNMARK_CELL(trail_cell));
2674 else
2675 ptr = RepAppl(trail_cell);
2676
2677 TrailTerm(dest+1) = old;
2678 if (marked_old) {
2679 UNMARK(&TrailTerm(dest+1));
2680 if (HEAP_PTR(old)) {
2681 into_relocation_chain(&TrailTerm(dest+1), GET_NEXT(old) PASS_REGS);
2682 }
2683 }
2684 TrailTerm(dest+2) = TrailTerm(dest) = trail_cell;
2685 if (marked_ptr) {
2686 UNMARK(&TrailTerm(dest));
2687 UNMARK(&TrailTerm(dest+2));
2688 if (HEAP_PTR(trail_cell)) {
2689 into_relocation_chain(&TrailTerm(dest), GET_NEXT(trail_cell) PASS_REGS);
2690 into_relocation_chain(&TrailTerm(dest+2), GET_NEXT(trail_cell) PASS_REGS);
2691 }
2692 }
2693 trail_ptr += 2;
2694 dest += 2;
2695#endif
2696#endif
2697 }
2698 trail_ptr++;
2699 dest++;
2700 }
2701 }
2702 LOCAL_new_TR = dest;
2703 if (is_gc_verbose()) {
2704 if (old_TR != (tr_fr_ptr)LOCAL_TrailBase)
2705 fprintf(stderr,
2706 "%% Trail: discarded %d (%ld%%) cells out of %ld\n",
2707 LOCAL_discard_trail_entries,
2708 (unsigned long int)(LOCAL_discard_trail_entries*100/(old_TR-(tr_fr_ptr)LOCAL_TrailBase)),
2709 (unsigned long int)(old_TR-(tr_fr_ptr)LOCAL_TrailBase));
2710#ifdef DEBUG0
2711 if (hp_entrs > 0)
2712 fprintf(stderr,
2713 "%% Trail: unmarked %ld dbentries (%ld%%) out of %ld\n",
2714 (long int)hp_not_in_use,
2715 (long int)(hp_not_in_use*100/hp_entrs),
2716 (long int)hp_entrs);
2717 if (hp_in_use_erased > 0 && hp_erased > 0)
2718 fprintf(stderr,
2719 "%% Trail: deleted %ld dbentries (%ld%%) out of %ld\n",
2720 (long int)hp_erased,
2721 (long int)(hp_erased*100/(hp_erased+hp_in_use_erased)),
2722 (long int)(hp_erased+hp_in_use_erased));
2723#endif
2724 if (OldHeapUsed) {
2725 fprintf(stderr,
2726 "%% Heap: recovered %ld bytes (%ld%%) out of %ld\n",
2727 (unsigned long int)(OldHeapUsed-HeapUsed),
2728 (unsigned long int)((OldHeapUsed-HeapUsed)/(OldHeapUsed/100)),
2729 (unsigned long int)OldHeapUsed);
2730 }
2731 }
2732 CleanDeadClauses( PASS_REGS1 );
2733}
2734
2735
2736/*
2737 * insert cells of a chain of environments which point to heap objects into
2738 * relocation chains
2739 */
2740
2741static void
2742sweep_environments(CELL_PTR gc_ENV,yamop *pc, size_t size, CELL *pvbmap USES_REGS)
2743{
2744 CELL_PTR saved_var;
2745 bool very_verbose = is_gc_very_verbose();
2746
2747 while (gc_ENV != NULL) { /* no more environments */
2748 Int bmap = 0;
2749 int currv = 0;
2750 if (very_verbose) {
2751 if (size > 0) {
2752 PredEntry *pe = EnvPreg((yamop*)gc_ENV[E_CP]);
2753 op_numbers op = Yap_op_from_opcode(ENV_ToOp((yamop*)gc_ENV[E_CP]));
2754#if defined(ANALYST) || defined(DEBUG)
2755 fprintf(stderr,"sweep env %p-%p(%ld) %s\n", gc_ENV
2756 , pvbmap, size-EnvSizeInCells, Yap_op_names[op]);
2757#else
2758 fprintf(stderr,"sweep env %p-%p(%ld) %ld\n", gc_ENV, pvbmap, size-EnvSizeInCells, (int)op);
2759#endif
2760 if (pe->ArityOfPE)
2761 fprintf(stderr," %s/%ld\n", RepAtom(NameOfFunctor(pe->FunctorOfPred))->StrOfAE, pe->ArityOfPE);
2762 else
2763 fprintf(stderr," %s\n", RepAtom((Atom)(pe->FunctorOfPred))->StrOfAE);
2764 }
2765 }
2766 if (pc->opc == Yap_opcode(_op_fail))
2767 return;
2768 // printf("SWEEP %p--%p\n", gc_ENV, gc_ENV-size);
2769
2770 /* for each saved variable */
2771
2772 if (size > EnvSizeInCells) {
2773 int tsize = size - EnvSizeInCells;
2774
2775
2776 currv = sizeof(CELL)*8-tsize%(sizeof(CELL)*8);
2777 if (pvbmap != NULL) {
2778 pvbmap += tsize/(sizeof(CELL)*8);
2779 bmap = *pvbmap;
2780 } else {
2781 bmap = ((CELL)-1);
2782 }
2783 bmap = (Int)(((CELL)bmap) << currv);
2784 }
2785 for (saved_var = gc_ENV - size; saved_var < gc_ENV - EnvSizeInCells; saved_var++) {
2786 if (currv == sizeof(CELL)*8) {
2787 if (pvbmap != NULL) {
2788 pvbmap--;
2789 bmap = *pvbmap;
2790 } else {
2791 bmap = ((CELL)-1);
2792 }
2793 currv = 0;
2794 }
2795 if (bmap < 0&& MARKED_PTR(saved_var)) {
2796 CELL env_cell = *saved_var;
2797 if (MARKED_PTR(saved_var)) {
2798 UNMARK(saved_var);
2799 if (HEAP_PTR(env_cell)) {
2800 into_relocation_chain(saved_var, GET_NEXT(env_cell) PASS_REGS);
2801 }
2802 }
2803 }
2804 bmap <<= 1;
2805 currv++;
2806 }
2807 /* have we met this environment before?? */
2808 /* we use the B field in the environment to tell whether we have
2809 been here before or not
2810 */
2811 if (!MARKED_PTR(gc_ENV+E_CB))
2812 return;
2813 UNMARK(gc_ENV+E_CB);
2814 pc= (yamop *) (gc_ENV[E_CP]);
2815
2816 size = EnvSize(pc); /* size = EnvSize(CP) */
2817 pvbmap = EnvBMap(pc);
2818 gc_ENV = (CELL_PTR) gc_ENV[E_E]; /* link to prev
2819 * environment */
2820 }
2821}
2822
2823static void
2824sweep_b(choiceptr gc_B, UInt arity USES_REGS)
2825{
2826 register CELL_PTR saved_reg;
2827
2828 sweep_environments(gc_B->cp_env,gc_B->cp_cp,
2829 EnvSize((yamop *) (gc_B->cp_cp)),
2830 EnvBMap((yamop *) (gc_B->cp_cp)) PASS_REGS);
2831
2832 /* for each saved register */
2833 for (saved_reg = &gc_B->cp_a1;
2834 saved_reg < &gc_B->cp_a1 + arity;
2835 saved_reg++) {
2836 CELL cp_cell = *saved_reg;
2837 if (MARKED_PTR(saved_reg)) {
2838 UNMARK(saved_reg);
2839 if (HEAP_PTR(cp_cell)) {
2840 into_relocation_chain(saved_reg, GET_NEXT(cp_cell) PASS_REGS);
2841 }
2842 }
2843 }
2844}
2845
2846
2847/*
2848 * insert cells of each choicepoint & its chain of environments which point
2849 * to heap objects into relocation chains
2850 */
2851static void
2852sweep_choicepoints(choiceptr gc_B USES_REGS)
2853{
2854#ifdef TABLING
2855 dep_fr_ptr depfr = LOCAL_top_dep_fr;
2856 sg_fr_ptr aux_sg_fr = LOCAL_top_sg_fr;
2857#endif /* TABLING */
2858
2859#ifdef TABLING
2860 gc_B = youngest_cp(gc_B, &depfr);
2861#endif /* TABLING */
2862 while (gc_B != NULL) {
2863 yamop *rtp = gc_B->cp_ap;
2864 register OPCODE op;
2865 op_numbers opnum;
2866
2867#ifdef TABLING
2868 if (rtp == NULL) {
2869 if (aux_sg_fr && gc_B == SgFr_gen_cp(aux_sg_fr)) {
2870 /* found generator */
2871 opnum = _table_completion;
2872 } else {
2873 /* found sld node is done */
2874 opnum = _trust_fail;
2875 }
2876 } else {
2877#endif /* TABLING */
2878 op = rtp->opc;
2879 opnum = Yap_op_from_opcode(op);
2880#ifdef TABLING
2881 }
2882 if (aux_sg_fr && gc_B == SgFr_gen_cp(aux_sg_fr)) {
2883 aux_sg_fr = SgFr_next(aux_sg_fr);
2884 }
2885#endif /* TABLING */
2886
2887 restart_cp:
2888 /*
2889 * fprintf(stderr,"sweeping cps: %x, %x, %x\n",
2890 * *gc_B,CP_Extra(gc_B),CP_Nargs(gc_B));
2891 */
2892 /* any choice point */
2893 switch (opnum) {
2894 case _Nstop:
2895 /* end of the road, say bye bye! */
2896 if (gc_B->cp_env == LCL0) {
2897 return;
2898 } else {
2899 // This must be a border choicepoint, just move up
2900 gc_B = (choiceptr)(gc_B->cp_env[E_B]);
2901 continue;
2902 }
2903 case _trust_fail:
2904 break;
2905 case _or_else:
2906 case _or_last:
2907
2908 sweep_environments((CELL_PTR)(gc_B->cp_a1),gc_B->cp_cp,
2909 -gc_B->cp_cp->y_u.Osblp.s / ((OPREG)sizeof(CELL)),
2910 gc_B->cp_cp->y_u.Osblp.bmap
2911 PASS_REGS);
2912 break;
2913 case _retry_profiled:
2914 case _count_retry:
2915 rtp = NEXTOP(rtp,l);
2916 op = rtp->opc;
2917 opnum = Yap_op_from_opcode(op);
2918 goto restart_cp;
2919 case _jump:
2920 rtp = rtp->y_u.l.l;
2921 op = rtp->opc;
2922 opnum = Yap_op_from_opcode(op);
2923 goto restart_cp;
2924#ifdef TABLING
2925 case _table_load_answer:
2926 {
2927 CELL *vars_ptr, vars;
2928 sweep_environments(gc_B->cp_env, gc_B->cp_cp, EnvSize(gc_B->cp_cp), EnvBMap(gc_B->cp_cp) PASS_REGS);
2929 vars_ptr = (CELL *) (LOAD_CP(gc_B) + 1);
2930 vars = *vars_ptr++;
2931 while (vars--) {
2932 CELL cp_cell = *vars_ptr;
2933 if (MARKED_PTR(vars_ptr)) {
2934 UNMARK(vars_ptr);
2935 if (HEAP_PTR(cp_cell)) {
2936 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
2937 }
2938 }
2939 vars_ptr++;
2940 }
2941 }
2942 break;
2943 case _table_try_answer:
2944 case _table_retry_me:
2945 case _table_trust_me:
2946 case _table_retry:
2947 case _table_trust:
2948 {
2949 int nargs;
2950 CELL *vars_ptr, vars;
2951 sweep_environments(gc_B->cp_env,gc_B->cp_cp, EnvSize(gc_B->cp_cp), EnvBMap(gc_B->cp_cp) PASS_REGS);
2952 vars_ptr = (CELL *)(GEN_CP(gc_B) + 1);
2953 nargs = rtp->y_u.Otapl.s;
2954 while(nargs--) {
2955 CELL cp_cell = *vars_ptr;
2956 if (MARKED_PTR(vars_ptr)) {
2957 UNMARK(vars_ptr);
2958 if (HEAP_PTR(cp_cell)) {
2959 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
2960 }
2961 }
2962 vars_ptr++;
2963 }
2964 vars = *vars_ptr++;
2965 while (vars--) {
2966 CELL cp_cell = *vars_ptr;
2967 if (MARKED_PTR(vars_ptr)) {
2968 UNMARK(vars_ptr);
2969 if (HEAP_PTR(cp_cell)) {
2970 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
2971 }
2972 }
2973 vars_ptr++;
2974 }
2975 }
2976 break;
2977 case _table_completion:
2978#ifdef THREADS_CONSUMER_SHARING
2979 case _table_answer_resolution_completion:
2980#endif /* THREADS_CONSUMER_SHARING */
2981 {
2982 int nargs;
2983 CELL *vars_ptr, vars;
2984#ifdef DETERMINISTIC_TABLING
2985 if (IS_DET_GEN_CP(gc_B))
2986 vars_ptr = (CELL *)(DET_GEN_CP(gc_B) + 1);
2987 else
2988#endif /* DETERMINISTIC_TABLING */
2989 {
2990 sweep_environments(gc_B->cp_env,gc_B->cp_cp, EnvSize(gc_B->cp_cp), EnvBMap(gc_B->cp_cp) PASS_REGS);
2991 vars_ptr = (CELL *)(GEN_CP(gc_B) + 1);
2992 nargs = SgFr_arity(GEN_CP(gc_B)->cp_sg_fr);
2993 while(nargs--) {
2994 CELL cp_cell = *vars_ptr;
2995 if (MARKED_PTR(vars_ptr)) {
2996 UNMARK(vars_ptr);
2997 if (HEAP_PTR(cp_cell)) {
2998 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
2999 }
3000 }
3001 vars_ptr++;
3002 }
3003 }
3004 vars = *vars_ptr++;
3005 while (vars--) {
3006 CELL cp_cell = *vars_ptr;
3007 if (MARKED_PTR(vars_ptr)) {
3008 UNMARK(vars_ptr);
3009 if (HEAP_PTR(cp_cell)) {
3010 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
3011 }
3012 }
3013 vars_ptr++;
3014 }
3015 }
3016 break;
3017 case _table_answer_resolution:
3018 {
3019 CELL *vars_ptr, vars;
3020 dep_fr_ptr dep_fr = CONS_CP(gc_B)->cp_dep_fr;
3021 ans_node_ptr ans_node = DepFr_last_answer(dep_fr);
3022 if (TRUE || TrNode_child(ans_node)) {
3023 /* unconsumed answers */
3024#ifdef MODE_DIRECTED_TABLING
3025 if (TrNode_child(ans_node) && IS_ANSWER_INVALID_NODE(TrNode_child(ans_node))) {
3026 ans_node_ptr old_ans_node;
3027 old_ans_node = ans_node;
3028 ans_node = TrNode_child(ans_node);
3029 do {
3030 ans_node = TrNode_child(ans_node);
3031 } while (IS_ANSWER_INVALID_NODE(ans_node));
3032 TrNode_child(old_ans_node) = ans_node;
3033 } else
3034#endif /* MODE_DIRECTED_TABLING */
3035 ans_node = TrNode_child(ans_node);
3036 if (gc_B == DepFr_leader_cp(dep_fr)) { \
3037 /* gc_B is a generator-consumer node */
3038 /* never here if batched scheduling */
3039 TABLING_ERROR_CHECKING(generator_consumer, IS_BATCHED_GEN_CP(gc_B));
3040 vars_ptr = (CELL *) (GEN_CP(gc_B) + 1);
3041 vars_ptr += SgFr_arity(GEN_CP(gc_B)->cp_sg_fr);
3042 } else {
3043 vars_ptr = (CELL *) (CONS_CP(gc_B) + 1); \
3044 }
3045 sweep_environments(gc_B->cp_env, gc_B->cp_cp,EnvSize(gc_B->cp_cp), EnvBMap(gc_B->cp_cp) PASS_REGS);
3046 vars = *vars_ptr++;
3047 while (vars--) {
3048 CELL cp_cell = *vars_ptr;
3049 if (MARKED_PTR(vars_ptr)) {
3050 UNMARK(vars_ptr);
3051 if (HEAP_PTR(cp_cell)) {
3052 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
3053 }
3054 }
3055 vars_ptr++;
3056 }
3057 }
3058 }
3059 break;
3060 case _trie_trust_var:
3061 case _trie_retry_var:
3062 case _trie_trust_var_in_pair:
3063 case _trie_retry_var_in_pair:
3064 case _trie_trust_val:
3065 case _trie_retry_val:
3066 case _trie_trust_val_in_pair:
3067 case _trie_retry_val_in_pair:
3068 case _trie_trust_atom:
3069 case _trie_retry_atom:
3070 case _trie_trust_atom_in_pair:
3071 case _trie_retry_atom_in_pair:
3072 case _trie_trust_null:
3073 case _trie_retry_null:
3074 case _trie_trust_null_in_pair:
3075 case _trie_retry_null_in_pair:
3076 case _trie_trust_pair:
3077 case _trie_retry_pair:
3078 case _trie_trust_appl:
3079 case _trie_retry_appl:
3080 case _trie_trust_appl_in_pair:
3081 case _trie_retry_appl_in_pair:
3082 case _trie_trust_extension:
3083 case _trie_retry_extension:
3084 case _trie_trust_double:
3085 case _trie_retry_double:
3086 case _trie_trust_longint:
3087 case _trie_retry_longint:
3088 case _trie_trust_gterm:
3089 case _trie_retry_gterm:
3090 {
3091 CELL *vars_ptr;
3092 int heap_arity, vars_arity, subs_arity;
3093 sweep_environments(gc_B->cp_env,gc_B->cp_cp, EnvSize(gc_B->cp_cp), EnvBMap(gc_B->cp_cp) PASS_REGS);
3094 vars_ptr = (CELL *)(gc_B + 1);
3095 heap_arity = vars_ptr[0];
3096 vars_arity = vars_ptr[1 + heap_arity];
3097 subs_arity = vars_ptr[2 + heap_arity + vars_arity];
3098 vars_ptr += 2 + heap_arity + subs_arity + vars_arity;
3099 if (subs_arity) {
3100 while (subs_arity--) {
3101 CELL cp_cell = *vars_ptr;
3102 if (MARKED_PTR(vars_ptr)) {
3103 UNMARK(vars_ptr);
3104 if (HEAP_PTR(cp_cell)) {
3105 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
3106 }
3107 }
3108 vars_ptr--;
3109 }
3110 }
3111 vars_ptr--; /* skip subs_arity entry */
3112 if (vars_arity) {
3113 while (vars_arity--) {
3114 CELL cp_cell = *vars_ptr;
3115 if (MARKED_PTR(vars_ptr)) {
3116 UNMARK(vars_ptr);
3117 if (HEAP_PTR(cp_cell)) {
3118 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
3119 }
3120 }
3121 vars_ptr--;
3122 }
3123 }
3124 vars_ptr--; /* skip vars_arity entry */
3125 if (heap_arity) {
3126 while (heap_arity--) {
3127 CELL cp_cell = *vars_ptr;
3128 if (*vars_ptr == 0) /* double/longint extension mark */
3129 break;
3130 if (MARKED_PTR(vars_ptr)) {
3131 UNMARK(vars_ptr);
3132 if (HEAP_PTR(cp_cell)) {
3133 into_relocation_chain(vars_ptr, GET_NEXT(cp_cell) PASS_REGS);
3134 }
3135 }
3136 vars_ptr--;
3137 }
3138 }
3139 }
3140 break;
3141#endif /* TABLING */
3142 case _try_logical:
3143 case _retry_logical:
3144 case _count_retry_logical:
3145 case _profiled_retry_logical:
3146 /* sweep timestamp */
3147 sweep_b(gc_B, rtp->y_u.OtaLl.s+1 PASS_REGS);
3148 break;
3149 case _trust_logical:
3150 case _count_trust_logical:
3151 case _profiled_trust_logical:
3152 sweep_b(gc_B, rtp->y_u.OtILl.d->ClPred->ArityOfPE+1 PASS_REGS);
3153 break;
3154 case _retry2:
3155 sweep_b(gc_B, 2 PASS_REGS);
3156 break;
3157 case _retry3:
3158 sweep_b(gc_B, 3 PASS_REGS);
3159 break;
3160 case _retry4:
3161 sweep_b(gc_B, 4 PASS_REGS);
3162 break;
3163 case _retry_udi:
3164 sweep_b(gc_B, rtp->y_u.p.p->ArityOfPE PASS_REGS);
3165 break;
3166 case _retry_exo:
3167 case _retry_exo_udi:
3168 case _retry_all_exo:
3169 sweep_b(gc_B, rtp->y_u.lp.p->ArityOfPE PASS_REGS);
3170 break;
3171 case _retry_c:
3172 case _retry_userc:
3173 {
3174 register CELL_PTR saved_reg;
3175
3176 /* for each extra saved register */
3177 for (saved_reg = &(gc_B->cp_a1)+rtp->y_u.OtapFs.s;
3178 saved_reg < &(gc_B->cp_a1)+rtp->y_u.OtapFs.s+rtp->y_u.OtapFs.extra;
3179 saved_reg++) {
3180 CELL cp_cell = *saved_reg;
3181 if (MARKED_PTR(saved_reg)) {
3182 UNMARK(saved_reg);
3183 if (HEAP_PTR(cp_cell)) {
3184 into_relocation_chain(saved_reg, GET_NEXT(cp_cell) PASS_REGS);
3185 }
3186 }
3187 }
3188 }
3189 /* continue to clean environments and arguments */
3190 default:
3191 sweep_b(gc_B,rtp->y_u.Otapl.s PASS_REGS);
3192 }
3193
3194 /* link to prev choicepoint */
3195#if TABLING
3196 gc_B = youngest_cp(gc_B->cp_b, &depfr);
3197#else
3198 gc_B = gc_B->cp_b;
3199#endif /* TABLING */
3200 }
3201}
3202
3203
3204
3205
3206/* update a relocation chain to point all its cells to new location of object */
3207static void
3208update_relocation_chain(CELL_PTR current, CELL_PTR dest USES_REGS)
3209{
3210 CELL_PTR next;
3211 CELL ccur = *current;
3212
3213 int rmarked = RMARKED(current);
3214
3215 UNRMARK(current);
3216 while (rmarked) {
3217 CELL current_tag;
3218 next = GET_NEXT(ccur);
3219 current_tag = TAG(ccur);
3220 ccur = *next;
3221 rmarked = RMARKED(next);
3222 UNRMARK(next);
3223 *next = (CELL) dest | current_tag;
3224 }
3225 *current = ccur;
3226}
3227
3228static inline choiceptr
3229update_B_H( choiceptr gc_B, CELL *current, CELL *dest, CELL *odest
3230#ifdef TABLING
3231 , dep_fr_ptr *depfrp
3232#endif /* TABLING */
3233 ) {
3234 /* also make the value of H in a choicepoint
3235 coherent with the new global
3236 */
3237#ifdef TABLING
3238 dep_fr_ptr depfr = *depfrp;
3239#endif /* TABLING */
3240
3241 while (gc_B && current <= gc_B->cp_h) {
3242 if (gc_B->cp_h == current) {
3243 gc_B->cp_h = dest;
3244 } else {
3245 gc_B->cp_h = odest;
3246 }
3247 gc_B = gc_B->cp_b;
3248#ifdef TABLING
3249 /* make sure we include consumers */
3250 if (depfr && gc_B >= DepFr_cons_cp(depfr)) {
3251 gc_B = DepFr_cons_cp(depfr);
3252 *depfrp = depfr = DepFr_next(depfr);
3253 }
3254#endif /* TABLING */
3255 }
3256 return gc_B;
3257}
3258
3259static inline CELL *
3260set_next_hb(choiceptr gc_B USES_REGS)
3261{
3262 if (gc_B) {
3263 return gc_B->cp_h;
3264 } else {
3265 return H0;
3266 }
3267}
3268
3269/*
3270 * move marked objects on the heap upwards over unmarked objects, and reset
3271 * all pointers to point to new locations
3272 */
3273static void
3274compact_heap( USES_REGS1 )
3275{
3276 CELL_PTR dest, current, next;
3277#ifdef DEBUG
3278 Int found_marked = 0;
3279#endif /* DEBUG */
3280 choiceptr gc_B = B;
3281 CELL *next_hb;
3282 CELL *start_from = H0;
3283#ifdef TABLING
3284 dep_fr_ptr depfr = LOCAL_top_dep_fr;
3285#endif /* TABLING */
3286 CELL *previous;
3287
3288
3289 /*
3290 * upward phase - scan heap from high to low, setting marked upward
3291 * ptrs to point to what will be the new locations of the
3292 * objects pointed to
3293 */
3294
3295#ifdef TABLING
3296 if (depfr && gc_B >= DepFr_cons_cp(depfr)) {
3297 gc_B = DepFr_cons_cp(depfr);
3298 depfr = DepFr_next(depfr);
3299 }
3300#endif /* TABLING */
3301 next_hb = set_next_hb(gc_B PASS_REGS);
3302 dest = H0 + LOCAL_total_marked-1 ;
3303
3304 gc_B = update_B_H(gc_B, HR, dest+1, dest+2
3305#ifdef TABLING
3306 , &depfr
3307#endif /* TABLING */
3308 );
3309 for (current = HR - 1, previous=HR-1; current >= start_from; current--) {
3310 if (MARKED_PTR(current)) {
3311 if (current <= next_hb) {
3312 gc_B = update_B_H(gc_B, current, dest, dest + 1
3313#ifdef TABLING
3314 , &depfr
3315#endif /* TABLING */
3316 );
3317 next_hb = set_next_hb(gc_B PASS_REGS);
3318 }
3319
3320 if (XMARKED(current)) {
3321 /* oops, we found a blob */
3322 previous = current;
3323 current = (CELL *)AtomOfTerm(*current);
3324 UInt nofcells = (previous - current);
3325 // fprintf(stderr, "UPW %p/%p: %lx %ld\n ", current, current + (nofcells + 1),
3326 // current[0], nofcells);
3327#ifdef DEBUG
3328 // fprintf(stderr,"%p U\n", current);
3329 found_marked+=nofcells;
3330#endif /* DEBUG */
3331
3332 dest -= nofcells;
3333 }
3334 update_relocation_chain(current, dest PASS_REGS);
3335 if (HEAP_PTR(*current)) {
3336 next = GET_NEXT(*current);
3337 if (next < current) /* push into reloc.
3338 * chain */
3339 into_relocation_chain(current, next PASS_REGS);
3340 else if (current == next) { /* cell pointing to
3341 * itself */
3342 UNRMARK(current);
3343 *current = (CELL) dest; /* no tag */
3344 }
3345 }
3346#ifdef DEBUG
3347 // fprintf(stderr,"%p U\n", current);
3348 found_marked++;
3349#endif /* DEBUG */
3350 dest--;
3351 previous = current;
3352 }
3353 }
3354
3355#ifdef DEBUG
3356 if (dest != start_from-1)
3357 fprintf(stderr,"%% Bad Dest (%lu): %p should be %p\n",
3358 (unsigned long int)LOCAL_GcCalls,
3359 dest,
3360 start_from-1);
3361 if (LOCAL_total_marked != found_marked)
3362 fprintf(stderr,"%% Upward (%lu): %lu total against %lu found\n",
3363 (unsigned long int)LOCAL_GcCalls,
3364 (unsigned long int)LOCAL_total_marked,
3365 (unsigned long int)found_marked);
3366 found_marked = start_from-H0;
3367#endif
3368
3369
3370 /*
3371 * downward phase - scan heap from low to high, moving marked objects
3372 * to their new locations & setting downward pointers to pt to new
3373 * locations
3374 */
3375
3376#if DEBUG
3377 found_marked= LOCAL_total_marked;
3378#endif
3379 dest = H0;
3380previous = NULL;
3381 for (current = H0; current < HR; current++) {
3382 if (MARKED_PTR(current)) {
3383 bool xmark = XMARKED(current);
3384 update_relocation_chain(current, dest PASS_REGS);
3385 CELL ccur = *current;
3386 next = GET_NEXT(ccur);
3387 if (HEAP_PTR(ccur) &&
3388 (next = GET_NEXT(ccur)) < HR && /* move current cell &
3389 * push */
3390 next > current) { /* into relocation chain */
3391 *dest = ccur;
3392 into_relocation_chain(dest, next PASS_REGS);
3393 UNMARK(dest);
3394 } else {
3395 /* just move current cell */
3396 *dest = ccur = UNMARK_CELL(ccur);
3397 }
3398 if (xmark) {
3399 UNXMARK(current);
3400 CELL *dest0 = dest++;
3401 CELL *previous = current++;
3402
3403
3404 while (!XMARKED(current))
3405 *dest++ = *current++;
3406 if (LOCAL_OpenArray) {
3407 if (LOCAL_OpenArray < current &&
3408 LOCAL_OpenArray > previous) {
3409 UInt off = LOCAL_OpenArray - previous;
3410 LOCAL_OpenArray = dest + off;
3411 }
3412 /* if we have are calling from the C-interface,
3413 we may have an open array when we start the gc */
3414 }
3415
3416#ifdef DEBUG
3417
3418 found_marked -=
3419 (dest-dest0) ;
3420#endif
3421 *dest = CloseExtension(dest0);
3422 }
3423 #ifdef DEBUG
3424 found_marked--;
3425#endif
3426 dest++;
3427
3428 }
3429}
3430#ifdef DEBUG
3431 if (0 != found_marked)
3432 fprintf(stderr,"%% Downward (%lu): %lu total against %lu found\n",
3433 (unsigned long int)LOCAL_GcCalls,
3434 (unsigned long int)LOCAL_total_marked,
3435 (unsigned long int)(LOCAL_total_marked-found_marked));
3436#endif
3437
3438 HR = dest; /* reset H */
3439 HB = B->cp_h;
3440#ifdef TABLING
3441 if (B_FZ == (choiceptr)LCL0)
3442 H_FZ = H0;
3443 else
3444 H_FZ = B_FZ->cp_h;
3445#endif /* TABLING */
3446
3447}
3448
3449#ifdef HYBRID_SCHEME
3450/*
3451 * move marked objects on the heap upwards over unmarked objects, and reset
3452 * all pointers to point to new locations
3453 */
3454static void
3455icompact_heap( USES_REGS1 )
3456{
3457 CELL_PTR *iptr, *ibase = (CELL_PTR *)HR;
3458 CELL_PTR dest;
3459 CELL *next_hb;
3460#ifdef DEBUG
3461 Int found_marked = 0;
3462#endif /* DEBUG */
3463#ifdef TABLING
3464 dep_fr_ptr depfr = LOCAL_top_dep_fr;
3465#endif /* TABLING */
3466 choiceptr gc_B = B;
3467
3468 /*
3469 * upward phase - scan heap from high to low, setting marked upward
3470 * ptrs to point to what will be the new locations of the
3471 * objects pointed to
3472 */
3473
3474#ifdef TABLING
3475 if (depfr && gc_B >= DepFr_cons_cp(depfr)) {
3476 gc_B = DepFr_cons_cp(depfr);
3477 depfr = DepFr_next(depfr);
3478 }
3479#endif /* TABLING */
3480 next_hb = set_next_hb(gc_B PASS_REGS);
3481 dest = (CELL_PTR) H0 + LOCAL_total_marked - 1;
3482 gc_B = update_B_H(gc_B, HR, dest+1, dest+2
3483#ifdef TABLING
3484 , &depfr
3485#endif /* TABLING */
3486 );
3487 for (iptr = LOCAL_iptop - 1; iptr >= ibase; iptr--) {
3488
3489 CELL_PTR current;
3490
3491 current = *iptr;
3492 //ccell = UNMARK_CELL(*current);
3493 if (current <= next_hb) {
3494 gc_B = update_B_H(gc_B, current, dest, dest+1
3495#ifdef TABLING
3496 , &depfr
3497#endif /* TABLING */
3498 );
3499 next_hb = set_next_hb(gc_B PASS_REGS);
3500 }
3501 if (IsEndExtension(current)) {
3502 /* oops, we found a blob */
3503 CELL_PTR ptr;
3504 UInt nofcells;
3505
3506 /* use the first cell after the functor for all our dirty tricks */
3507 ptr = iptr[-1]+1;
3508 nofcells = current-ptr;
3509#ifdef DEBUG
3510 found_marked+=(nofcells+1);
3511#endif /* DEBUG */
3512 dest -= nofcells+1;
3513 /* this one's being used */
3514 /* make the second step see the EndSpecial tag */
3515 current[0] = ptr[0];
3516 ptr[0] = CloseExtension(current);
3517 iptr[0] = ptr;
3518 continue;
3519 }
3520#ifdef DEBUG
3521 found_marked++;
3522#endif /* DEBUG */
3523 update_relocation_chain(current, dest PASS_REGS);
3524 if (HEAP_PTR(*current)) {
3525 CELL_PTR next;
3526 next = GET_NEXT(*current);
3527 if (next < current) /* push into reloc.
3528 * chain */
3529 into_relocation_chain(current, next PASS_REGS);
3530 else if (current == next) { /* cell pointing to
3531 * itself */
3532 UNRMARK(current);
3533 *current = (CELL) dest; /* no tag */
3534 }
3535 }
3536 dest--;
3537 }
3538
3539#ifdef DEBUG
3540 if (dest != H0-1)
3541 fprintf(stderr,"%% Bad Dest (%lu): %p should be %p\n",
3542 (unsigned long int)LOCAL_GcCalls,
3543 dest,
3544 H0-1);
3545 if (LOCAL_total_marked != found_marked)
3546 fprintf(stderr,"%% Upward (%lu): %lu total against %lu found\n",
3547 (unsigned long int)LOCAL_GcCalls,
3548 (unsigned long int)LOCAL_total_marked,
3549 (unsigned long int)found_marked);
3550 found_marked = 0;
3551#endif
3552
3553
3554 /*
3555 * downward phase - scan heap from low to high, moving marked objects
3556 * to their new locations & setting downward pointers to pt to new
3557 * locations
3558 */
3559
3560 dest = H0;
3561 for (iptr = ibase; iptr < LOCAL_iptop; iptr++) {
3562 CELL_PTR next;
3563 CELL *current = *iptr;
3564 CELL ccur = *current;
3565
3566 if (IsEndExtension(current)) {
3567 CELL *old_dest = dest;
3568
3569 /* leave a hole */
3570 dest++;
3571 current++;
3572 while (!MARKED_PTR(current)) {
3573 *dest++ = *current++;
3574 }
3575 /* fill in hole */
3576 *old_dest = *current;
3577 *dest++ = CloseExtension(old_dest);
3578#ifdef DEBUG
3579 found_marked += dest-old_dest;
3580#endif
3581 continue;
3582 }
3583#ifdef DEBUG
3584 found_marked++;
3585#endif
3586 update_relocation_chain(current, dest PASS_REGS);
3587 ccur = *current;
3588 next = GET_NEXT(ccur);
3589 if (HEAP_PTR(ccur) && /* move current cell &
3590 * push */
3591 next > current) { /* into relocation chain */
3592 *dest = ccur;
3593 into_relocation_chain(dest, next PASS_REGS);
3594 UNMARK(dest);
3595 dest++;
3596 } else {
3597 /* just move current cell */
3598 *dest++ = ccur = UNMARK_CELL(ccur);
3599 }
3600 }
3601#ifdef DEBUG
3602 if (H0+LOCAL_total_marked != dest)
3603 fprintf(stderr,"%% Downward (%lu): %p total against %p found\n",
3604 (unsigned long int)LOCAL_GcCalls,
3605 H0+LOCAL_total_marked,
3606 dest);
3607 if (LOCAL_total_marked != found_marked)
3608 fprintf(stderr,"%% Downward (%lu): %lu total against %lu found\n",
3609 (unsigned long int)LOCAL_GcCalls,
3610 (unsigned long int)LOCAL_total_marked,
3611 (unsigned long int)found_marked);
3612#endif
3613
3614 HR = dest; /* reset H */
3615 HB = B->cp_h;
3616#ifdef TABLING
3617 if (B_FZ == (choiceptr)LCL0)
3618 H_FZ = H0;
3619 else
3620 H_FZ = B_FZ->cp_h;
3621#endif /* TABLING */
3622
3623}
3624#endif /* HYBRID_SCHEME */
3625
3626
3627#ifdef EASY_SHUNTING
3628static void
3629set_conditionals(tr_fr_ptr str USES_REGS) {
3630 while (str != LOCAL_sTR0) {
3631 CELL *cptr;
3632 str -= 2;
3633 cptr = (CELL *)TrailTerm(str+1);
3634 *cptr = TrailTerm(str);
3635 }
3636 LOCAL_sTR = LOCAL_sTR0 = NULL;
3637}
3638#endif
3639
3640
3641/*
3642 * mark all objects on the heap that are accessible from active registers,
3643 * the trail, environments, and choicepoints
3644 */
3645
3646static void
3647marking_phase(tr_fr_ptr old_TR, gc_entry_info_t *info USES_REGS)
3648{
3649
3650#ifdef EASY_SHUNTING
3651 LOCAL_current_B = B;
3652 LOCAL_prev_HB = H;
3653#endif
3654 init_dbtable(old_TR PASS_REGS);
3655#ifdef EASY_SHUNTING
3656 LOCAL_sTR0 = (tr_fr_ptr)LOCAL_db_vec;
3657 LOCAL_sTR = (tr_fr_ptr)LOCAL_db_vec;
3658 /* make sure we set HB before we do any variable shunting!!! */
3659#else
3660 LOCAL_cont_top0 = (cont *)LOCAL_db_vec;
3661#endif
3662 LOCAL_cont_top = (cont *)LOCAL_db_vec;
3663 /* These two must be marked first so that our trail optimisation won't lose
3664 values */
3665 mark_regs(info->a, old_TR, info->p_env PASS_REGS); /* active registers & trail */
3666 /* active environments */
3667 mark_environments(info->env, info->p_env, info->env_size, EnvBMap(info->p_env) PASS_REGS);
3668 mark_choicepoints(B, old_TR, is_gc_very_verbose() PASS_REGS); /* choicepoints, and environs */
3669#ifdef EASY_SHUNTING
3670 set_conditionals(LOCAL_sTR PASS_REGS);
3671#endif
3672}
3673
3674static void
3675sweep_oldgen(CELL *max, CELL *base USES_REGS)
3676{
3677 CELL *ptr = base;
3678 char *bpb = LOCAL_bp+(base-(CELL*)LOCAL_GlobalBase);
3679
3680 while (ptr < max) {
3681 if (*bpb) {
3682 if (HEAP_PTR(*ptr)) {
3683 into_relocation_chain(ptr, GET_NEXT(*ptr) PASS_REGS);
3684 }
3685 }
3686 ptr++;
3687 bpb++;
3688 }
3689}
3690
3691
3692/*
3693 * move marked heap objects upwards over unmarked objects, and reset all
3694 * pointers to point to new locations
3695 */
3696
3697static void
3698compaction_phase(tr_fr_ptr old_TR, gc_entry_info_t *info USES_REGS)
3699{
3700 CELL *CurrentH0 = H0;
3701
3702 int icompact = false && (LOCAL_iptop < (CELL_PTR *)ASP && 10*LOCAL_total_marked < HR-H0);
3703
3704 if (icompact) {
3705 /* we are going to reuse the total space */
3706 if (LOCAL_HGEN != H0) {
3707 /* undo optimisation */
3708 LOCAL_total_marked += LOCAL_total_oldies;
3709 }
3710 } else {
3711 LOCAL_HGEN = H0;
3712 if (LOCAL_HGEN != H0) {
3713 CurrentH0 = H0;
3714 H0 = LOCAL_HGEN;
3715 sweep_oldgen(LOCAL_HGEN, CurrentH0 PASS_REGS);
3716 }
3717 }
3718 sweep_environments(info->env, info->p_env, info->env_size, EnvBMap(info->p_env) PASS_REGS);
3719 sweep_choicepoints(B PASS_REGS);
3720 sweep_trail(B, old_TR, info PASS_REGS);
3721#ifdef HYBRID_SCHEME
3722 if (false && icompact) {
3723#ifdef DEBUG
3724 /*
3725 if (LOCAL_total_marked
3726#ifdef COROUTINING
3727 -LOCAL_total_smarked
3728#endif
3729 != LOCAL_iptop-(CELL_PTR *)H && LOCAL_iptop < (CELL_PTR *)ASP -1024)
3730 fprintf(stderr,"%% Oops on LOCAL_iptop-H (%ld) vs %ld\n", (unsigned long int)(LOCAL_iptop-(CELL_PTR *)HR), LOCAL_total_marked);
3731 */
3732#endif
3733#if DEBUGX
3734 int effectiveness = (((H-H0)-LOCAL_total_marked)*100)/(H-H0);
3735 fprintf(stderr,"%% using pointers (%d)\n", effectiveness);
3736#endif
3737 if (CurrentH0) {
3738 H0 = CurrentH0;
3739 LOCAL_HGEN = H0;
3740 LOCAL_total_marked += LOCAL_total_oldies;
3741 CurrentH0 = NULL;
3742 }
3743 quicksort((CELL_PTR *)HR, 0, (LOCAL_iptop-(CELL_PTR *)HR)-1);
3744 icompact_heap( PASS_REGS1 );
3745 } else
3746#endif /* HYBRID_SCHEME */
3747 {
3748#ifdef DEBUG
3749 /*
3750#ifdef HYBRID_SCHEME
3751 int effectiveness = (((H-H0)-LOCAL_total_marked)*100)/(H-H0);
3752 fprintf(stderr,"%% not using pointers (%d) ASP: %p, ip %p (expected %p) \n", effectiveness, ASP, LOCAL_iptop, H+LOCAL_total_marked);
3753
3754#endif
3755 */
3756#endif
3757 compact_heap( PASS_REGS1 );
3758 }
3759 if (CurrentH0) {
3760 H0 = CurrentH0;
3761#ifdef TABLING
3762 /* make sure that we havce the correct H_FZ if we're not tabling */
3763 if (B_FZ == (choiceptr)LCL0)
3764 H_FZ = H0;
3765#endif /* TABLING */
3766 }
3767}
3768
3769static int
3770do_gc(gc_entry_info_t *info USES_REGS)
3771{
3772 Int heap_cells;
3773 int gc_verbose;
3774 volatile tr_fr_ptr old_TR = NULL;
3775 UInt m_time, c_time, time_start, gc_time;
3776 Int effectiveness, tot;
3777 bool gc_trace;
3778 UInt gc_phase=0;
3779 UInt alloc_sz;
3780 int jmp_res;
3781 sigjmp_buf jmp;
3782Int predarity = info->a;
3783CELL *current_env = info->env;
3784yamop *nextop = info->p_env;
3785
3786 heap_cells = HR-H0;
3787 gc_verbose = is_gc_verbose();
3788 effectiveness = 0;
3789 gc_trace = false;
3790 LOCAL_GcCalls++;
3791 #ifdef INSTRUMENT_GC
3792 {
3793 int i;
3794 for (i=0; i<16; i++)
3795 chain[i]=0;
3796 vars[gc_var] = 0;
3797 vars[gc_ref] = 0;
3798 vars[gc_atom] = 0;
3799 vars[gc_int] = 0;
3800 vars[gc_num] = 0;
3801 vars[gc_list] = 0;
3802 vars[gc_appl] = 0;
3803 vars[gc_func] = 0;
3804 vars[gc_susp] = 0;
3805 env_vars = 0;
3806 old_vars = new_vars = 0;
3807 TrueHB = HB;
3808 num_bs = 0;
3809 }
3810#endif
3811#ifdef DEBUG
3812 check_global();
3813#endif
3814 if (gcTrace() != TermOff)
3815 gc_trace = true;
3816 if (gc_trace) {
3817 fprintf(stderr, "%% gc\n");
3818 } else if (gc_verbose) {
3819#if defined(YAPOR) || defined(THREADS)
3820 fprintf(stderr, "%% Worker Id %d:\n", worker_id);
3821#endif
3822 fprintf(stderr, "%% Start of garbage collection %lu:\n", (unsigned long int)LOCAL_GcCalls);
3823 fprintf(stderr, "%% Global: %8ld cells (%p-%p)\n", (long int)heap_cells,H0,HR);
3824 fprintf(stderr, "%% Local:%8ld cells (%p-%p)\n", (unsigned long int)(LCL0-ASP),LCL0,ASP);
3825 fprintf(stderr, "%% Trail:%8ld cells (%p-%p)\n",
3826 (unsigned long int)(TR-(tr_fr_ptr)LOCAL_TrailBase),LOCAL_TrailBase,TR);
3827 }
3828#if !USE_SYSTEM_MALLOC
3829 if (HeapTop >= LOCAL_GlobalBase - MinHeapGap) {
3830 *H++ = (CELL)current_env;
3831 if (!Yap_locked_growheap(FALSE, MinHeapGap, NULL)) {
3832 Yap_Error(RESOURCE_ERROR_HEAP, TermNil, LOCAL_ErrorMessage);
3833 return -1;
3834 }
3835 current_env = (CELL *)*--HR;
3836 }
3837#endif
3838 time_start = Yap_cputime();
3839 jmp_res = sigsetjmp(jmp, 0);
3840 if (jmp_res == 2) {
3841 UInt sz;
3842
3843 /* we cannot recover, fail system */
3844 restore_machine_regs();
3845 sz = LOCAL_TrailTop-(ADDR)LOCAL_OldTR;
3846 /* ask for double the size */
3847 sz = 2*sz;
3848 TR = LOCAL_OldTR;
3849
3850 *HR++ = (CELL)current_env;
3851 if (
3852 !Yap_locked_growtrail(sz, FALSE)
3853 ) {
3854 Yap_Error(RESOURCE_ERROR_TRAIL,TermNil,"out of %lB during gc", sz);
3855 return -1;
3856 } else {
3857 LOCAL_total_marked = 0;
3858 LOCAL_total_oldies = 0;
3859#ifdef COROUTING
3860 LOCAL_total_smarked = 0;
3861#endif
3862 LOCAL_discard_trail_entries = 0;
3863 current_env = (CELL *)*--HR;
3864 }
3865 } else if (jmp_res == 3) {
3866 /* we cannot recover, fail system */
3867 restore_machine_regs();
3868
3869
3870 LOCAL_total_marked = 0;
3871 LOCAL_total_oldies = 0;
3872#ifdef COROUTING
3873 LOCAL_total_smarked = 0;
3874#endif
3875 LOCAL_discard_trail_entries = 0;
3876 if (LOCAL_extra_gc_cells_size < 1024 *104) {
3877 LOCAL_extra_gc_cells_size <<= 1;
3878 } else {
3879 LOCAL_extra_gc_cells_size += 1024*1024;
3880 }
3881 } else if (jmp_res == 4) {
3882 /* we cannot recover, fail completely */
3883 Yap_exit(1);
3884 }
3885#if EASY_SHUNTING
3886 LOCAL_sTR0 = LOCAL_sTR = NULL;
3887#endif
3888 LOCAL_total_marked = 0;
3889 LOCAL_total_oldies = 0;
3890#ifdef COROUTING
3891 LOCAL_total_smarked = 0;
3892#endif
3893 LOCAL_discard_trail_entries = 0;
3894 alloc_sz = (CELL *)LOCAL_TrailTop-(CELL*)LOCAL_GlobalBase;
3895 LOCAL_bp = Yap_PreAllocCodeSpace();
3896 while (IN_BETWEEN(LOCAL_bp, AuxSp, LOCAL_bp+alloc_sz)) {
3897 /* not enough space */
3898 *HR++ = (CELL)current_env;
3899 LOCAL_bp = (char *)Yap_ExpandPreAllocCodeSpace(alloc_sz, NULL, TRUE);
3900 if (!LOCAL_bp)
3901 return -1;
3902 current_env = (CELL *)*--HR;
3903 }
3904 memset((void *)LOCAL_bp, 0, alloc_sz);
3905#ifdef HYBRID_SCHEME
3906 LOCAL_iptop = (CELL_PTR *)HR;
3907#endif
3908
3909 /* get the number of active registers */
3910 LOCAL_HGEN = H0;//VarOfTerm(Yap_ReadTimedVar(LOCAL_GcGeneration));
3911 //gc_phase = (UInt)IntegerOfTerm(Yap_ReadTimedVar(LOCAL_GcPhase));
3912 /* old LOCAL_HGEN are not very reliable, but still may have data to recover */
3913 if (gc_phase != LOCAL_GcCurrentPhase) {
3914 LOCAL_HGEN = H0;
3915 }
3916 /* fprintf(stderr,"LOCAL_HGEN is %ld, %p, %p/%p\n", IntegerOfTerm(Yap_ReadTimedVa1r(LOCAL_GcGeneration)), LOCAL_HGEN, H,H0);*/
3917 LOCAL_OldTR = old_TR = push_registers(predarity, count,nextop PASS_REGS);
3918 /* make sure we clean bits after a reset */
3919 marking_phase(old_TR, info PASS_REGS);
3920 /* { CELL *pt; for (pt=H0;pt<HR;pt++) { */
3921 /* fprintf(stderr, "%c %p %lx\n",MARKED_PTR(pt)?'*':' ',pt,*pt); */
3922
3923
3924 /* }} */
3925 if (LOCAL_total_oldies > ((LOCAL_HGEN-H0)*8)/10) {
3926 LOCAL_total_marked -= LOCAL_total_oldies;
3927 tot = LOCAL_total_marked+(LOCAL_HGEN-H0);
3928 } else {
3929 if (LOCAL_HGEN != H0) {
3930 LOCAL_HGEN = H0;
3931 LOCAL_GcCurrentPhase++;
3932 }
3933 tot = LOCAL_total_marked;
3934 }
3935 m_time = Yap_cputime();
3936 gc_time = m_time-time_start;
3937 if (heap_cells) {
3938 if (heap_cells > 1000000)
3939 effectiveness = (heap_cells-tot)/(heap_cells/100);
3940 else
3941 effectiveness = 100*(heap_cells-tot)/heap_cells;
3942 } else
3943 effectiveness = 0;
3944 if (gc_verbose) {
3945 fprintf(stderr, "%% Mark: Marked %ld cells of %ld (efficiency: %ld%%) in %g sec\n",
3946 (long int)tot, (long int)heap_cells, (long int)effectiveness, (double)(m_time-time_start)/1000);
3947 if (LOCAL_HGEN-H0)
3948 fprintf(stderr,"%% previous generation has size " UInt_FORMAT ", with " UInt_FORMAT " (" UInt_FORMAT "%%) unmarked\n", (UInt)(LOCAL_HGEN-H0), (UInt)((LOCAL_HGEN-H0)-LOCAL_total_oldies), (UInt)(100*((LOCAL_HGEN-H0)-LOCAL_total_oldies)/(LOCAL_HGEN-H0)));
3949#ifdef INSTRUMENT_GC
3950 {
3951 int i;
3952 for (i=0; i<16; i++) {
3953 if (chain[i]) {
3954 fprintf(stderr, "%% chain[%d]=%lu\n", i, chain[i]);
3955 }
3956 }
3957 put_type_info((unsigned long int)tot);
3958 fprintf(stderr,"%% %lu/%ld before and %lu/%ld after\n", old_vars, (unsigned long int)(B->cp_h-H0), new_vars, (unsigned long int)(H-B->cp_h));
3959 fprintf(stderr,"%% %ld choicepoints\n", num_bs);
3960 }
3961#endif
3962 }
3963 time_start = m_time;
3964 compaction_phase(old_TR, info PASS_REGS);
3965 pop_registers(predarity, old_TR, nextop PASS_REGS);
3966 //fprintf(stderr, "++++++++++++++++++++\n ");
3967 TR = old_TR;
3968/* fprintf(stderr,"NEW LOCAL_HGEN %ld (%ld)\n", H-H0, LOCAL_HGEN-H0);*/
3969 {
3970 //Term t = MkVarTerm();
3971 // Yap_UpdateTimedVar(LOCAL_GcGeneration, t);
3972 }
3973 // Yap_UpdateTimedVar(LOCAL_GcPhase, MkIntegerTerm(LOCAL_GcCurrentPhase));
3974c_time = Yap_cputime();
3975 if (gc_verbose) {
3976 fprintf(stderr, "%% Compress: took %g sec\n", (double)(c_time-time_start)/1000);
3977 }
3978 gc_time += (c_time-time_start);
3979 LOCAL_TotGcTime += gc_time;
3980 LOCAL_TotGcRecovered += heap_cells-tot;
3981 if (gc_verbose) {
3982 fprintf(stderr, "%% GC %lu took %g sec, total of %g sec doing GC so far.\n", (unsigned long int)LOCAL_GcCalls, (double)gc_time/1000, (double)LOCAL_TotGcTime/1000);
3983 fprintf(stderr, "%% Left %ld cells free in stacks.\n",
3984 (unsigned long int)(ASP-HR));
3985 }
3986 check_global();
3987 // { CELL *pt; for (pt=H0;pt<HR;pt++) {
3988 // fprintf(stderr,"%c %p %lx\n",MARKED_PTR(pt)?'*':' ',pt,*pt);
3989
3990 // }}
3991 return effectiveness;
3992}
3993
3994static bool
3995is_gc_verbose(void)
3996{
3997 CACHE_REGS
3998 if (LOCAL_PrologMode == BootMode)
3999 return false;
4000#ifdef INSTRUMENT_GC
4001 /* always give info when we are debugging gc */
4002 return true;
4003#else
4004 Term t = gcTrace();
4005 return t == TermVerbose || t == TermVeryVerbose;
4006#endif
4007}
4008
4009bool
4010Yap_is_gc_verbose(void)
4011{
4012 return is_gc_verbose();
4013}
4014
4015static bool
4016is_gc_very_verbose(void)
4017{
4018 CACHE_REGS
4019 if (LOCAL_PrologMode == BootMode)
4020 return false;
4021 return gcTrace() == TermVeryVerbose;
4022}
4023
4024Int
4025Yap_total_gc_time(void)
4026{
4027 CACHE_REGS
4028 return(LOCAL_TotGcTime);
4029}
4030
4031static Int
4032p_inform_gc( USES_REGS1 )
4033{
4034 Term tn = MkIntegerTerm(LOCAL_TotGcTime);
4035 Term tt = MkIntegerTerm(LOCAL_GcCalls);
4036 Term ts = Yap_Mk64IntegerTerm((LOCAL_TotGcRecovered*sizeof(CELL)));
4037
4038 return(Yap_unify(tn, ARG2) && Yap_unify(tt, ARG1) && Yap_unify(ts, ARG3));
4039
4040}
4041
4042
4043static int
4044call_gc(gc_entry_info_t *info USES_REGS)
4045{
4046 UInt gc_margin = MinStackGap;
4047 Term Tgc_margin;
4048 Int effectiveness = 0;
4049 int gc_on = FALSE, gc_t = FALSE;
4050
4051 if (trueGlobalPrologFlag(GC_FLAG) && IsIntTerm(getAtomicGlobalPrologFlag(GC_MARGIN_FLAG)))
4052 gc_on = true;
4053 else {
4054 CalculateStackGap( PASS_REGS1 );
4055 return Yap_locked_growstack(gc_margin);
4056 }
4057
4058
4059 if (IsIntegerTerm(Tgc_margin = getAtomicGlobalPrologFlag(GC_MARGIN_FLAG)) &&
4060 gc_margin > 0) {
4061 gc_margin = (UInt)IntegerOfTerm(Tgc_margin);
4062 gc_t = true;
4063 } else {
4064 /* only go exponential for the first 6 calls, that would ask about 2MB minimum */
4065 if (LOCAL_GcCalls < 8)
4066 gc_margin <<= LOCAL_GcCalls;
4067 else {
4068 /* next grow linearly */
4069 gc_margin <<= 8;
4070 /* don't do this: it forces the system to ask for ever more stack!!
4071 gc_margin *= LOCAL_GcCalls;
4072 */
4073 }
4074 }
4075 if (gc_margin < info->gc_min)
4076 gc_margin = info->gc_min;
4077 LOCAL_HGEN = H0;//VarOfTerm(Yap_ReadTimedVar(LOCAL_GcGeneration));
4078 if (gc_on && !(LOCAL_PrologMode & InErrorMode) &&
4079 /* make sure there is a point in collecting the heap */
4080 (ASP-H0)*sizeof(CELL) > info->gc_min &&
4081 HR-H0 > (LCL0-ASP)/2) {
4082 effectiveness = do_gc(info PASS_REGS);
4083 if (effectiveness < 0)
4084 return FALSE;
4085 if (effectiveness > 90 && !gc_t) {
4086 while (gc_margin < (HR-H0)/sizeof(CELL))
4087 gc_margin <<= 1;
4088 }
4089 } else {
4090 effectiveness = 0;
4091 }
4092 /* expand the stack if effectiveness is less than 20 % */
4093 if (ASP - HR < gc_margin/sizeof(CELL) ||
4094 effectiveness < 20) {
4095 LeaveGCMode( PASS_REGS1 );
4096#ifndef YAPOR
4097 if (gc_margin < 2*EventFlag)
4098 gc_margin = 2*EventFlag;
4099 CalculateStackGap( PASS_REGS1 );
4100 return Yap_locked_growstack(gc_margin);
4101#endif
4102 }
4103 /*
4104 * debug for(save_total=1; save_total<=N; ++save_total)
4105 * plwrite(XREGS[save_total],NULL,30,0,0,0);
4106 */
4107 return TRUE;
4108}
4109
4110static void
4111LeaveGCMode( USES_REGS1 )
4112{
4113 if (LOCAL_PrologMode & GCMode)
4114 LOCAL_PrologMode &= ~GCMode;
4115 if (LOCAL_PrologMode & AbortMode) {
4116 LOCAL_PrologMode &= ~AbortMode;
4117 /* in case someone mangles the P register */
4118 Yap_Error(ABORT_EVENT, TermNil, "abort from console");
4119 Yap_RestartYap( 1 );
4120 }
4121}
4122
4123bool Yap_dogc( USES_REGS1 ) {
4124 int rc;
4125 gc_entry_info_t i, *p = &i;
4126 Yap_track_cpred(0, P, 0, p);
4127 LOCAL_PrologMode |= GCMode;
4128 rc = call_gc(p);
4129 LeaveGCMode( PASS_REGS1 );
4130 if (LOCAL_PrologMode & GCMode)
4131 LOCAL_PrologMode &= ~GCMode;
4132 return rc>=0;
4133}
4134
4135bool Yap_dogcl( size_t minsz USES_REGS ) {
4136 int rc;
4137 gc_entry_info_t i, *p = &i;
4138 Yap_track_cpred(0, P, 0, p);
4139 i.gc_min = minsz;
4140 LOCAL_PrologMode |= GCMode;
4141 rc = call_gc(p);
4142 LeaveGCMode( PASS_REGS1 );
4143 if (LOCAL_PrologMode & GCMode)
4144 LOCAL_PrologMode &= ~GCMode;
4145 return rc>=0;
4146}
4147
4148bool Yap_gc( void *p0 ) {
4149 int rc;
4150 gc_entry_info_t *p = p0;
4151 LOCAL_PrologMode |= GCMode;
4152 rc = call_gc(p);
4153 LeaveGCMode( PASS_REGS1 );
4154 if (LOCAL_PrologMode & GCMode)
4155 LOCAL_PrologMode &= ~GCMode;
4156 return rc>=0;
4157}
4158
4159
4160
4161bool
4162Yap_gcl(size_t gc_lim, void *p)
4163{
4164 CACHE_REGS
4165 int res;
4166 UInt min;
4167 gc_entry_info_t *info = p;
4168
4169 CalculateStackGap( PASS_REGS1 );
4170 min = EventFlag*sizeof(CELL);
4171 if (gc_lim < min)
4172 gc_lim = min;
4173 info->gc_min = gc_lim;
4174 LOCAL_PrologMode |= GCMode;
4175
4176 res = call_gc(info PASS_REGS);
4177 LeaveGCMode( PASS_REGS1 );
4178 return res>=0;
4179}
4180static Int
4181garbage_collect( USES_REGS1 )
4182{
4183 int res;
4184 LOCAL_PrologMode |= GCMode;
4185 gc_entry_info_t i, *p = &i;
4186 Yap_track_cpred(0, P, 0, p);
4187 CalculateStackGap( PASS_REGS1 );
4188 i.gc_min = EventFlag*sizeof(CELL);
4189 res = call_gc(p PASS_REGS) >= 0;
4190 LeaveGCMode( PASS_REGS1 );
4191 return res>=0;
4192}
4193
4194void
4195Yap_init_gc(void)
4196{
4197 Yap_InitCPred("garbage_collect", 0, garbage_collect, 0);
4198 Yap_InitCPred("$inform_gc", 3, p_inform_gc, 0);
4199}
4200
4201void
4202Yap_inc_mark_variable()
4203{
4204 CACHE_REGS
4205 LOCAL_total_marked++;
4206}
@ source
If true maintain the source for all clauses.
Definition: YapGFlagInfo.h:601
@ gc_margin
controls when to do garbage collection
Definition: YapGFlagInfo.h:297
@ gc_trace
show activity in garbag collector
Definition: YapGFlagInfo.h:306
PredEntry * Yap_PredForChoicePt(choiceptr cp, op_numbers *op)
Yap_v<<ChoicePt(): find out the predicate who generated a CP.
Definition: stack.c:307
Definition: arrays.h:92
Definition: heapgc.c:75
Definition: heapgc.h:272
Definition: Yap.h:681
Definition: Yatom.h:151
Definition: Yatom.h:544
Definition: arrays.h:76
Definition: amidefs.h:264