biassert.c

00001 /* File:      biassert.c
00002 ** Author(s): David S. Warren, Jiyang Xu
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
00006 ** Copyright (C) ECRC, Germany, 1990
00007 ** 
00008 ** XSB is free software; you can redistribute it and/or modify it under the
00009 ** terms of the GNU Library General Public License as published by the Free
00010 ** Software Foundation; either version 2 of the License, or (at your option)
00011 ** any later version.
00012 ** 
00013 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00014 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00015 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License
00016 ** for more details.lo
00017 ** 
00018 ** You should have received a copy of the GNU Library General Public License
00019 ** along with XSB; if not, write to the Free Software Foundation,
00020 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021 **
00022 ** $Id: biassert.c,v 1.124 2006/07/25 14:18:41 tswift Exp $
00023 ** 
00024 */
00025 
00026 
00027 #include "xsb_config.h"
00028 #include "xsb_debug.h"
00029 
00030 /* Special debug includes */
00031 #include "debugs/debug_biassert.h"
00032 #include <stdio.h>
00033 #include <errno.h>
00034 #include <string.h>
00035 #include <stdlib.h>
00036 
00037 #include "setjmp_xsb.h"
00038 #include "auxlry.h"
00039 #include "cell_xsb.h"
00040 #include "psc_xsb.h"
00041 #include "error_xsb.h"
00042 #include "cinterf.h"
00043 #include "memory_xsb.h"
00044 #include "heap_xsb.h"
00045 #include "register.h"
00046 #include "flags_xsb.h"
00047 #include "deref.h"
00048 #include "inst_xsb.h"
00049 #include "token_xsb.h"
00050 #include "loader_xsb.h"
00051 #include "trie_internals.h"
00052 #include "choice.h"
00053 #include "macro_xsb.h"
00054 #include "tr_utils.h"
00055 #include "trassert.h"
00056 #include "context.h"
00057 #include "thread_xsb.h"
00058 #include "debug_xsb.h"
00059 #include "biassert_defs.h"
00060 
00061 /* --- routines used from other files --------------------------------- */
00062 
00063 extern Cell val_to_hash(Cell);
00064 
00065 extern int xsb_profiling_enabled;
00066 extern void add_prog_seg(Psc, byte *, long);
00067 extern void remove_prog_seg(byte *);
00068 PrRef clref_to_prref(ClRef clref);
00069 
00070 CPtr dbclause_cgc_block_gl = NULL;
00071 CPtr standard_cgc_block_begin_gl = NULL;
00072 CPtr standard_cgc_block_end_gl = NULL;
00073 
00074 /*======================================================================*/
00075 /* dbgen_inst: Generate an instruction in the buffer.                   */
00076 /*======================================================================*/
00077 
00078 #define MARKED_FOR_DELETION 66
00079 
00080 #define write_word(Buff,Loc,w) { *(CPtr)((pb)Buff + *(Loc)) = (Cell)(w); *(Loc) += 4; \
00081                                 pad64bits(Loc); }
00082 #define write_byte(Buff,Loc,w) { *(pb)((pb)Buff + *(Loc)) = (byte)(w); *(Loc) += 1; }
00083 
00084 #ifdef BITS64
00085 #define pad64bits(Loc)  { *(Loc) += 4; }
00086 #else
00087 #define pad64bits(Loc)  {}
00088 #endif
00089 
00090 /* TLS: probably dont need to keep max thread here -- could use max_threads_glc */
00091 struct DispBlk_t {
00092   struct DispBlk_t *PrevDB;
00093   struct DispBlk_t *NextDB;
00094   int MaxThread;
00095   CPtr Thread0;    /* Pointer to array of prrefs */
00096   };
00097 
00098 struct DispBlkHdr_t {
00099   struct DispBlk_t *firstDB;
00100   struct DispBlk_t *lastDB;
00101 } DispBlkHdr = {NULL, NULL};
00102 
00103 #ifdef MULTI_THREAD
00104 
00105 /* For a private dynamic predicate, return addr of its prref or its
00106    table wrapper */
00107 
00108 CPtr dynpredep_to_prortb(CTXTdeclc void *pred_ep) {
00109     if (th->tid > (((struct DispBlk_t **)pred_ep)[1])->MaxThread) 
00110       xsb_abort("Dynamic Dispatch block too small");
00111     return (CPtr) ((&((struct DispBlk_t **)pred_ep)[1]->Thread0)[th->tid]);
00112 }
00113 #endif
00114 
00115 /* Maps psc -> ep to the actual prref, accounting for dispatch tables
00116    and/or table wrappers. 
00117 
00118    Also, it could be that dynpredep_to_prref() returns NULL normally
00119    -- if a private predicate has been defined for one thread but not
00120    another.*/
00121 
00122 PrRef dynpredep_to_prref(CTXTdeclc void *pred_ep) {
00123 #ifdef MULTI_THREAD
00124   if (cell_opcode((CPtr)(pred_ep)) == switchonthread) {
00125     if (th->tid > (((struct DispBlk_t **)pred_ep)[1])->MaxThread) 
00126       xsb_abort("Dynamic Dispatch block too small");
00127     pred_ep = (pb) (&((struct DispBlk_t **)pred_ep)[1]->Thread0)[th->tid];
00128   }
00129   if (!pred_ep) return NULL;
00130 #endif
00131   if (cell_opcode((CPtr)(pred_ep)) == tabletrysingle)
00132     return (PrRef)((CPtr *)(pred_ep))[6];
00133   else return pred_ep;
00134 }
00135 
00136 /* #ifdef DEBUG */
00137 /* I hope we can trust any decent C compiler to compile away
00138    empty switch statements like the ones below, if DEBUG is not set
00139    (in which case xsb_dbgmsg is empty)                    --lfcastro */
00140 
00141 
00142 static inline void dbgen_printinst3(Opcode, Arg1, Arg2, Arg3)
00143 {
00144   switch (Opcode) {
00145   case getlist_tvar_tvar:
00146     xsb_dbgmsg((LOG_ASSERT,"getlist_tvar_tvar - %ld %ld %ld",
00147                (long)Arg1,(long)Arg2,(long)Arg3)); break;
00148   case switchonbound:
00149     xsb_dbgmsg((LOG_ASSERT,"switchonbound - %ld %ld %ld",
00150                (long)Arg1,(long)Arg2,(long)Arg3)); break;
00151   case switchon3bound:
00152     xsb_dbgmsg((LOG_ASSERT,"switchon3bound - %ld %ld %ld",
00153                (long)Arg1,(long)Arg2,(long)Arg3)); break;
00154   default: xsb_dbgmsg((LOG_ASSERT,"Unknown instruction in assert %d",
00155                       Opcode));
00156   }
00157 }
00158 
00159 static inline void dbgen_printinst(Opcode, Arg1, Arg2)
00160 {
00161   switch (Opcode) {
00162   case getpvar: /* PRV */
00163     xsb_dbgmsg((LOG_ASSERT,"getpvar - %d %d\n", Arg1, Arg2)); break;
00164   case getpval: /* PRV */
00165     xsb_dbgmsg((LOG_ASSERT,"getpval - %d %d\n", Arg1, Arg2)); break;
00166   case putpvar: /* PRV */
00167     xsb_dbgmsg((LOG_ASSERT,"putpvar - %d %d\n", Arg1, Arg2)); break;
00168   case putpval: /* PRV */
00169     xsb_dbgmsg((LOG_ASSERT,"putpval - %d %d\n", Arg1, Arg2)); break;
00170   case gettval: /* PRR */
00171     xsb_dbgmsg((LOG_ASSERT,"gettval - %d %d\n", Arg1, Arg2)); break;
00172   case puttvar: /* PRR */
00173     xsb_dbgmsg((LOG_ASSERT,"puttvar - %d %d\n", Arg1, Arg2)); break;
00174   case movreg:  /* PRR */
00175     xsb_dbgmsg((LOG_ASSERT,"movreg - %d %d\n", Arg1, Arg2)); break;
00176   case unipvar: /* PPV */
00177     xsb_dbgmsg((LOG_ASSERT,"unipvar - - %d\n", Arg1)); break;
00178   case unipval: /* PPV */
00179     xsb_dbgmsg((LOG_ASSERT,"unipval - - %d\n", Arg1)); break;
00180   case bldpvar: /* PPV */
00181     xsb_dbgmsg((LOG_ASSERT,"bldpvar - - %d\n", Arg1)); break;
00182   case bldpval: /* PPV */
00183     xsb_dbgmsg((LOG_ASSERT,"bldpval - - %d\n", Arg1)); break;
00184   case unitvar: /* PPR */
00185     xsb_dbgmsg((LOG_ASSERT,"unitvar - - %d\n", Arg1)); break;
00186   case uniavar: /* PPR */
00187     xsb_dbgmsg((LOG_ASSERT,"uniavar - - \n")); break;
00188   case unitval: /* PPR */
00189     xsb_dbgmsg((LOG_ASSERT,"unitval - - %d\n", Arg1)); break;
00190   case bldtvar: /* PPR */
00191     xsb_dbgmsg((LOG_ASSERT,"bldtvar - - %d\n", Arg1)); break;
00192   case bldavar: /* PPR */
00193     xsb_dbgmsg((LOG_ASSERT,"bldavar - - \n")); break;
00194   case bldtval: /* PPR */
00195     xsb_dbgmsg((LOG_ASSERT,"bldtval - - %d\n", Arg1)); break;
00196   case putlist: /* PPR */
00197     xsb_dbgmsg((LOG_ASSERT,"putlist - - %d\n", Arg1)); break;
00198   case getlist: /* PPR */
00199     xsb_dbgmsg((LOG_ASSERT,"getlist - - %d\n", Arg1)); break;
00200   case getattv: /* PPR */
00201     xsb_dbgmsg((LOG_ASSERT,"getattv - - %d\n", Arg1)); break;
00202   case putattv: /* PPR */
00203     xsb_dbgmsg((LOG_ASSERT,"putattv - - %d\n", Arg1)); break;
00204   case putcon:
00205     xsb_dbgmsg((LOG_ASSERT,"putcon - - %d 0x%x\n", Arg1, Arg2)); break;
00206   case putnumcon:
00207     xsb_dbgmsg((LOG_ASSERT,"putnumcon - - %d 0x%x\n", Arg1, int_val(Arg2))); break;
00208   case putfloat:
00209     xsb_dbgmsg((LOG_ASSERT,"putfloat - - %d %f (0x%x)\n", Arg1, ofloat_val(Arg2), ofloat_val(Arg2))); break;
00210   case getcon:
00211     xsb_dbgmsg((LOG_ASSERT,"getcon - - %d 0x%x\n", Arg1, Arg2)); break;
00212   case getnumcon:
00213     xsb_dbgmsg((LOG_ASSERT,"getnumcon - - %d 0x%x\n", Arg1, int_val(Arg2))); break;
00214   case getfloat:
00215     xsb_dbgmsg((LOG_ASSERT,"getfloat - - %d %f (0x%x)\n", Arg1, ofloat_val(Arg2), ofloat_val(Arg2))); break;
00216   case putstr:
00217     xsb_dbgmsg((LOG_ASSERT,"putstr - - %d 0x%x\n", Arg1, Arg2)); break;
00218   case getstr:
00219     xsb_dbgmsg((LOG_ASSERT,"getstr - - %d 0x%x\n", Arg1, Arg2)); break;
00220   case putnil:
00221     xsb_dbgmsg((LOG_ASSERT,"putnil - - %d\n", Arg1)); break;
00222   case getnil:
00223     xsb_dbgmsg((LOG_ASSERT,"getnil - - %d\n", Arg1)); break;
00224   case bldcon:
00225     xsb_dbgmsg((LOG_ASSERT,"bldcon - - - 0x%x\n", Arg1)); break;
00226   case bldnumcon:
00227     xsb_dbgmsg((LOG_ASSERT,"bldnumcon - - - 0x%x\n", int_val(Arg1))); break;
00228   case bldfloat:
00229     xsb_dbgmsg((LOG_ASSERT,"bldfloat - - - %f\n", ofloat_val(Arg1))); break;
00230   case unicon:
00231     xsb_dbgmsg((LOG_ASSERT,"unicon - - - 0x%x\n", Arg1)); break;
00232   case uninumcon:
00233     xsb_dbgmsg((LOG_ASSERT,"uninumcon - - - 0x%x\n", int_val(Arg1))); break;
00234   case unifloat:
00235     xsb_dbgmsg((LOG_ASSERT,"unifloat - - - %f\n", ofloat_val(Arg1))); break;
00236   case xsb_execute:
00237     xsb_dbgmsg((LOG_ASSERT,"execute - - - 0x%x\n", Arg1)); break;
00238   case bldnil:
00239     xsb_dbgmsg((LOG_ASSERT,"bldnil - - -\n")); break;
00240   case uninil:
00241     xsb_dbgmsg((LOG_ASSERT,"uninil - - -\n")); break;
00242   case proceed:
00243     xsb_dbgmsg((LOG_ASSERT,"proceed - - -\n")); break;
00244   case noop:
00245     xsb_dbgmsg((LOG_ASSERT,"noop - - -\n")); break;
00246   case dynnoop:
00247     xsb_dbgmsg((LOG_ASSERT,"dynnoop - - -\n")); break;
00248   case jumptbreg:
00249     xsb_dbgmsg((LOG_ASSERT,"jumptbreg - - %d 0x%x\n", Arg1, Arg2)); break;
00250   case test_heap:
00251     xsb_dbgmsg((LOG_ASSERT,"test_heap - - %d %d\n", Arg1, int_val(Arg2))); break;
00252   case dyntrustmeelsefail:
00253     xsb_dbgmsg((LOG_ASSERT,"dyntrustmeelsefail - - %d 0x%x\n", Arg1, Arg2)); break;
00254   case dynretrymeelse:
00255     xsb_dbgmsg((LOG_ASSERT,"dynretrymeelse - - %d 0x%x\n", Arg1, Arg2)); break;
00256   case dyntrymeelse:
00257     xsb_dbgmsg((LOG_ASSERT,"dyntrymeelse - - %d 0x%x\n", Arg1, Arg2)); break;
00258   case jump:
00259     xsb_dbgmsg((LOG_ASSERT,"jump - - - 0x%x\n", Arg1)); break;
00260   case fail:
00261     xsb_dbgmsg((LOG_ASSERT,"fail - - -\n")); break;
00262   default: 
00263     xsb_dbgmsg((LOG_DEBUG, "Unknown instruction in assert %d",
00264                       Opcode));
00265   }
00266 }
00267 
00268 #define dbgen_printinst3_macro(Opcode, Arg1, Arg2, Arg3) \
00269         dbgen_printinst3(Opcode, Arg1, Arg2, Arg3)
00270 
00271 #define dbgen_printinst_macro(Opcode, Arg1, Arg2) \
00272         dbgen_printinst(Opcode, Arg1, Arg2)
00273 
00274 /* #else  /\* DEBUG *\/ */
00275 
00276 /* #define dbgen_printinst3_macro(Opcode, Arg1, Arg2, Arg3) */
00277 /* #define dbgen_printinst_macro(Opcode, Arg1, Arg2) */
00278 
00279 /* #endif /\* DEBUG *\/ */
00280 
00281 
00282 #define dbgen_inst3_tv(Opcode,Arg1,Arg2,Arg3,Buff,Loc) {        \
00283   dbgen_printinst3_macro(Opcode, Arg1, Arg2, Arg3);             \
00284   write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,Arg1);       \
00285   write_byte(Buff,Loc,Arg2); write_byte(Buff,Loc,Arg3);         \
00286   pad64bits(Loc);                                               \
00287 }
00288 
00289 #define dbgen_inst3_sob(Opcode,Arg1,Arg2,Arg3,Buff,Loc) {       \
00290   dbgen_printinst3_macro(Opcode, Arg1, Arg2, Arg3);             \
00291   write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,Arg1>>16);   \
00292   write_byte(Buff,Loc,Arg1>>8); write_byte(Buff,Loc,Arg1);      \
00293   pad64bits(Loc);                                               \
00294   write_word(Buff,Loc,Arg2); write_word(Buff,Loc,Arg3);         \
00295 }
00296 
00297 #define dbgen_inst_pvv(Opcode,Arg1,Arg2,Buff,Loc) {     \
00298     dbgen_printinst_macro(Opcode, Arg1, (Integer)Arg2); \
00299   write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,0);  \
00300   write_byte(Buff,Loc,Arg1); write_byte(Buff,Loc,Arg2); \
00301   pad64bits(Loc);                                       \
00302 }
00303 
00304 #define dbgen_inst_ppv(Opcode,Arg1,Buff,Loc) {          \
00305   dbgen_printinst_macro(Opcode, Arg1, 0);               \
00306   write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,0);  \
00307   write_byte(Buff,Loc,0); write_byte(Buff,Loc,Arg1);    \
00308   pad64bits(Loc);                                       \
00309 }
00310 
00311 #define dbgen_inst_ppvw(Opcode,Arg1,Arg2,Buff,Loc) {    \
00312     dbgen_printinst_macro(Opcode, Arg1, (Integer)Arg2); \
00313     write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,0);        \
00314     write_byte(Buff,Loc,0); write_byte(Buff,Loc,Arg1);          \
00315     pad64bits(Loc);                                             \
00316     write_word(Buff,Loc,Arg2);                                  \
00317 }
00318 
00319 #define dbgen_inst_ppvw_safe(Opcode,Arg1,Arg2,Buff,Loc) {       \
00320     int tLoc = 0, tempLoc = *Loc; char tBuff[4];                \
00321     dbgen_printinst_macro(Opcode, Arg1, (Integer)Arg2);         \
00322     *Loc += 4;                                                  \
00323     pad64bits(Loc);                                             \
00324     write_word(Buff,Loc,Arg2);                                  \
00325     write_byte(tBuff,&tLoc,Opcode); write_byte(tBuff,&tLoc,0);  \
00326     write_byte(tBuff,&tLoc,0); write_byte(tBuff,&tLoc,Arg1);    \
00327     memmove(Buff+tempLoc,tBuff,4);                              \
00328 }
00329 
00330 #define dbgen_inst_ppvww(Opcode,Arg1,Arg2,Arg3,Buff,Loc) {      \
00331     dbgen_printinst_macro(Opcode, Arg1, (Integer)Arg2);         \
00332     write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,0);        \
00333     write_byte(Buff,Loc,0); write_byte(Buff,Loc,Arg1);          \
00334     pad64bits(Loc);                                             \
00335     write_word(Buff,Loc,Arg2);                                  \
00336     write_word(Buff,Loc,Arg3);                                  \
00337 }
00338 
00339 #define dbgen_inst_pppw(Opcode,Arg1,Buff,Loc) {         \
00340     dbgen_printinst_macro(Opcode, (Integer)Arg1, 0);    \
00341     write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,0);        \
00342     write_byte(Buff,Loc,0); write_byte(Buff,Loc,0);             \
00343     pad64bits(Loc);                                             \
00344     write_word(Buff,Loc,Arg1);                                  \
00345 }
00346 
00347 #define dbgen_inst_ppp(Opcode,Buff,Loc) {               \
00348   dbgen_printinst_macro(Opcode, 0, 0);                  \
00349   write_byte(Buff,Loc,Opcode); write_byte(Buff,Loc,0);  \
00350   write_byte(Buff,Loc,0); write_byte(Buff,Loc,0);       \
00351   pad64bits(Loc);                                       \
00352 }
00353 
00354 #define dbgen_instB3_tv(Opcode,Arg1,Arg2,Arg3) {                                                        \
00355   dbgen_printinst3_macro(Opcode, Arg1, Arg2, Arg3);                                                     \
00356   if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                            \
00357   write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1);       \
00358   write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg2); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg3);         \
00359   pad64bits(asrtBuff->Loc);                                                                             \
00360 }
00361 
00362 #define dbgen_instB3_sob(Opcode,Arg1,Arg2,Arg3) {                                                       \
00363   dbgen_printinst3_macro(Opcode, Arg1, Arg2, Arg3);                                                     \
00364   if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                            \
00365   write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1>>16);   \
00366   write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1>>8); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1);      \
00367   pad64bits(asrtBuff->Loc);                                                                             \
00368   write_word(asrtBuff->Buff,asrtBuff->Loc,Arg2); write_word(asrtBuff->Buff,asrtBuff->Loc,Arg3);         \
00369 }
00370 
00371 #define dbgen_instB_pvv(Opcode,Arg1,Arg2) {                                                     \
00372   dbgen_printinst_macro(Opcode, Arg1, (Integer)Arg2);                                           \
00373   if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                    \
00374   write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);  \
00375   write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg2); \
00376   pad64bits(asrtBuff->Loc);                                                                     \
00377 }
00378 
00379 #define dbgen_instB_ppv(Opcode,Arg1) {                                                          \
00380   dbgen_printinst_macro(Opcode, Arg1,0);                                                        \
00381   if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                    \
00382   write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);  \
00383   write_byte(asrtBuff->Buff,asrtBuff->Loc,0); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1);    \
00384   pad64bits(asrtBuff->Loc);                                                                     \
00385 }
00386 
00387 #define dbgen_instB_ppvw(Opcode,Arg1,Arg2) {                                                    \
00388   dbgen_printinst_macro(Opcode, Arg1, (Integer)Arg2);                                           \
00389   if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                    \
00390   write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);  \
00391   write_byte(asrtBuff->Buff,asrtBuff->Loc,0); write_byte(asrtBuff->Buff,asrtBuff->Loc,Arg1);    \
00392   pad64bits(asrtBuff->Loc);                                                                     \
00393   write_word(asrtBuff->Buff,asrtBuff->Loc,Arg2);                                                \
00394 }
00395 
00396 #define dbgen_instB_pppw(Opcode,Arg1) {                                                                 \
00397     dbgen_printinst_macro(Opcode, (Integer)Arg1, 0);                                                    \
00398     if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                          \
00399     write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);        \
00400     write_byte(asrtBuff->Buff,asrtBuff->Loc,0); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);             \
00401     pad64bits(asrtBuff->Loc);                                                                           \
00402     write_word(asrtBuff->Buff,asrtBuff->Loc,Arg1);                                                      \
00403 }
00404 
00405 #define dbgen_instB_ppp(Opcode) {                                                               \
00406   dbgen_printinst_macro(Opcode,0,0);                                                            \
00407   if (*asrtBuff->Loc >= asrtBuff->BLim) asrtBuff->Buff = buff_realloc(CTXT);                    \
00408   write_byte(asrtBuff->Buff,asrtBuff->Loc,Opcode); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);  \
00409   write_byte(asrtBuff->Buff,asrtBuff->Loc,0); write_byte(asrtBuff->Buff,asrtBuff->Loc,0);       \
00410   pad64bits(asrtBuff->Loc);                                                                     \
00411 }
00412 
00413 
00414 /*======================================================================*/
00415 /* db_cmpl(+Clause, +Buffer, +Index, -Size)                             */
00416 /*      Clause is a fact or rule.                                       */
00417 /*      Buffer is the buffer where the code is put.                     */
00418 /*      Index is the argument to index on (0 if none).                  */
00419 /*      Size is the size of the compiled code                           */
00420 /* The predicate will generate code for the given clause in the Buffer. */
00421 /* The first 8 bytes are reserved for general chain.  If index is       */
00422 /* requested, the 2nd 8 bytes are used for the buckete chain. See Code  */
00423 /* below.                                                               */
00424 /*======================================================================*/
00425 
00426 
00427 #ifndef MULTI_THREAD
00428 static jmp_buf assertcmp_env;
00429 #endif
00430 
00431 struct flatten_elt {
00432         union {
00433                 prolog_term term;
00434                 Cell opcode;
00435         } v;
00436         int _reg;
00437 };
00438 
00439 #define FLATTEN_STACK_SIZE 512  
00440 
00441 struct flatten_q {
00442   int flatten_stack_top;
00443   struct flatten_elt flatten_stack[FLATTEN_STACK_SIZE];
00444 };
00445 
00446 
00447 #define INST_QUEUE_SIZE 512 /* was 1024 */
00448 
00449 struct instruction {
00450         Cell opcode;
00451         Cell arg1;
00452         Cell arg2;
00453 };
00454 
00455 struct instruction_q {
00456   int inst_queue_top;
00457   int inst_queue_bottom;
00458   int inst_queue_added;
00459   struct instruction inst_queue[INST_QUEUE_SIZE];
00460 };
00461 
00462 static void assertcmp_throw(CTXTdeclc int num)
00463 {
00464     longjmp(assertcmp_env, num);
00465 }
00466 
00467 
00468 #define ERR_FUNCTOR     1
00469 #define ERR_REGISTER    2
00470 
00471 static int arity(CTXTdeclc prolog_term T0)
00472 {
00473   if (isconstr(T0)) return p2c_arity(T0);
00474   else if (islist(T0)) return 2;
00475   else if (isstring(T0)) return 0;
00476   else assertcmp_throw(CTXTc ERR_FUNCTOR);
00477   return -1;
00478 }
00479 
00480 static void assertcmp_printerror(CTXTdeclc int num)
00481 {
00482     switch (num) {
00483     case ERR_FUNCTOR:
00484         xsb_abort("[Assert] functor expected");
00485         break;
00486     case ERR_REGISTER:
00487         xsb_abort("[Assert] need too many registers");
00488         break;
00489     default: 
00490         xsb_abort("[Assert] error occured in assert_cmp");
00491     }
00492 }
00493 
00494 /* db_cmpl(Clause, Buff, Index, Size) */
00495 
00496 static Integer p2c_float_as_int(prolog_term T0)
00497 {
00498 //  union float_conv {
00499 //      float f;
00500 //      Integer i;
00501 //    } 
00502     
00503     FloatConv converter;
00504     converter.f = (float)ofloat_val(T0);
00505     return converter.i;
00506 }
00507 
00508 static int is_frozen_var(prolog_term T0)
00509 {
00510     if (isconstr(T0) && strcmp(p2c_functor(T0), "$assertVAR")==0 &&
00511         p2c_arity(T0) == 1) {
00512         T0 = p2p_arg(T0, 1);
00513         return int_val(T0);
00514     } else return 0;
00515 }
00516 
00517 static void flatten_stack_init(struct flatten_q *flatten_stackq)
00518 {
00519     flatten_stackq->flatten_stack_top = 0;
00520 }
00521 
00522 static int flatten_stack_size(struct flatten_q *flatten_stackq)
00523 {
00524     return flatten_stackq->flatten_stack_top;
00525 }
00526 
00527 static void flatten_stack_push(struct flatten_q *flatten_stackq,
00528                                int argno, Cell term)
00529 {
00530     flatten_stackq->flatten_stack[flatten_stackq->flatten_stack_top]._reg = argno;
00531     flatten_stackq->flatten_stack[flatten_stackq->flatten_stack_top].v.opcode = term;
00532     flatten_stackq->flatten_stack_top++;
00533     if (flatten_stackq->flatten_stack_top >= FLATTEN_STACK_SIZE)
00534       xsb_abort("flatten_stack overflow in assert");
00535 }
00536 
00537 static void flatten_stack_pop(struct flatten_q *flatten_stackq,
00538                               int *argnop, Cell *termp)
00539 {
00540     flatten_stackq->flatten_stack_top--;
00541     *argnop = flatten_stackq->flatten_stack[flatten_stackq->flatten_stack_top]._reg;
00542     *termp = flatten_stackq->flatten_stack[flatten_stackq->flatten_stack_top].v.opcode;
00543 }
00544 
00545 static void inst_queue_init(struct instruction_q *inst_queue)
00546 {
00547     inst_queue->inst_queue_top = inst_queue->inst_queue_bottom = 10;
00548 }
00549 
00550 static int inst_queue_empty(struct instruction_q *inst_queue)
00551 {
00552     return (inst_queue->inst_queue_top == inst_queue->inst_queue_bottom);
00553 }
00554 
00555 static void inst_queue_push(struct instruction_q *inst_queue,
00556                             Cell opcode, Cell arg1, Cell arg2)
00557 {
00558     inst_queue->inst_queue[inst_queue->inst_queue_top].opcode = opcode;
00559     inst_queue->inst_queue[inst_queue->inst_queue_top].arg1 = arg1;
00560     inst_queue->inst_queue[inst_queue->inst_queue_top].arg2 = arg2;
00561     inst_queue->inst_queue_top = (inst_queue->inst_queue_top+1) % INST_QUEUE_SIZE;
00562     if (inst_queue->inst_queue_top == inst_queue->inst_queue_bottom)
00563       xsb_abort("instruction queue overflow in assert");
00564 }
00565 
00566 static void inst_queue_pop(struct instruction_q *inst_queue,
00567                            Cell *opcodep, Cell *arg1p, Cell *arg2p)
00568 {
00569     if (inst_queue->inst_queue_top == 0) inst_queue->inst_queue_top = INST_QUEUE_SIZE;
00570     inst_queue->inst_queue_top--;
00571     *opcodep = inst_queue->inst_queue[inst_queue->inst_queue_top].opcode;
00572     *arg1p = inst_queue->inst_queue[inst_queue->inst_queue_top].arg1;
00573     *arg2p = inst_queue->inst_queue[inst_queue->inst_queue_top].arg2;
00574 }
00575 
00576 static void inst_queue_rem(struct instruction_q *inst_queue,
00577                            Cell *opcodep, Cell *arg1p, Cell *arg2p)
00578 {
00579     *opcodep = inst_queue->inst_queue[inst_queue->inst_queue_bottom].opcode;
00580     *arg1p = inst_queue->inst_queue[inst_queue->inst_queue_bottom].arg1;
00581     *arg2p = inst_queue->inst_queue[inst_queue->inst_queue_bottom].arg2;
00582     inst_queue->inst_queue_bottom = (inst_queue->inst_queue_bottom+1) % INST_QUEUE_SIZE;
00583 }
00584 
00585 static void inst_queue_add(struct instruction_q *inst_queue,
00586                            Cell opcodep, Cell arg1p, Cell arg2p)
00587 {
00588     if (inst_queue->inst_queue_bottom == 0) inst_queue->inst_queue_bottom = INST_QUEUE_SIZE;
00589     inst_queue->inst_queue_bottom--;
00590     if (inst_queue->inst_queue_top == inst_queue->inst_queue_bottom)
00591       xsb_abort("instruction queue overflow in assert");
00592     inst_queue->inst_queue[inst_queue->inst_queue_bottom].opcode = opcodep;
00593     inst_queue->inst_queue[inst_queue->inst_queue_bottom].arg1 = arg1p;
00594     inst_queue->inst_queue[inst_queue->inst_queue_bottom].arg2 = arg2p;
00595     inst_queue->inst_queue_added++;
00596 }
00597 
00598 static void inst_queue_rotate(struct instruction_q *inst_queue) {
00599   prolog_term T0, T1;
00600   Cell Argno;
00601   while (inst_queue->inst_queue_added--) {
00602     inst_queue_rem(inst_queue,&Argno,&T0,&T1);
00603     inst_queue_push(inst_queue,Argno,T0,T1);
00604   }
00605 }
00606 
00607 /*typedef int *RegStat;*/
00608         /* 0 - all rest registers are free */
00609         /* >0 - next free register */
00610         /* -1 used for real var */
00611         /* -2 used for introduced var */
00612 
00613 #define RVAR -1
00614 #define TVAR -2
00615 
00616 struct RegStat_t {
00617   int RegArray[MAX_REGS];
00618   int RegArrayInit[MAX_REGS];
00619   int FreeReg;
00620 };
00621 
00622 typedef struct RegStat_t *RegStat;
00623 
00624 static void reg_init(RegStat Reg, int Size)
00625 {
00626     int i;
00627 
00628     Reg->FreeReg = Size+1;
00629     for (i=0; i<Reg->FreeReg; i++) Reg->RegArray[i] = RVAR;
00630     Reg->RegArray[Reg->FreeReg] = 0;
00631 }
00632 
00633 /* Type: RVAR=-1 - used for real var; TVAR=-2 - used for introduced var */
00634 static int reg_get(CTXTdeclc RegStat Reg, int Type)
00635 {
00636     int new_reg;
00637 
00638     new_reg = Reg->FreeReg;
00639     if (Reg->RegArray[Reg->FreeReg]==0) {
00640         Reg->FreeReg++;
00641         if (Reg->FreeReg >= MAX_REGS) {
00642           assertcmp_throw(CTXTc ERR_REGISTER);
00643         }
00644         Reg->RegArray[Reg->FreeReg] = 0;
00645     } else Reg->FreeReg = Reg->RegArray[Reg->FreeReg];
00646     Reg->RegArray[new_reg] = Type;
00647     Reg->RegArrayInit[new_reg] = 0;     /* register is not initialized */
00648     return new_reg;
00649 }
00650 
00651 static void reg_release(RegStat Reg, int R0)
00652 {
00653     if (Reg->RegArray[R0]==TVAR) {
00654         Reg->RegArray[R0] = Reg->FreeReg;
00655         Reg->FreeReg = R0;
00656     }
00657 }
00658 
00659 #ifndef MULTI_THREAD
00660 struct asrtBuff_t asrtBuffB = {NULL,512,NULL,0,0};
00661 struct asrtBuff_t *asrtBuff = &asrtBuffB;
00662 #endif
00663 
00664 static char *buff_realloc(CTXTdecl)
00665 {
00666   /*  xsb_dbgmsg((LOG_DEBUG,"Enter buff_realloc(%d) %X", asrtBuff->Buff_size,asrtBuff->Buff)); */
00667   asrtBuff->Buff_size = asrtBuff->Buff_size + asrtBuff->Buff_size;
00668   if (asrtBuff->Buff == NULL) asrtBuff->Buff = (char *)mem_alloc(asrtBuff->Buff_size,ASSERT_SPACE);
00669   else asrtBuff->Buff = (char *)mem_realloc(asrtBuff->Buff,(asrtBuff->Buff_size / 2),asrtBuff->Buff_size,ASSERT_SPACE);
00670   asrtBuff->BLim = asrtBuff->Buff_size-16;
00671   /*  xsb_dbgmsg((LOG_DEBUG,"Leave buff_realloc(%d) %X", asrtBuff->Buff_size,asrtBuff->Buff)); */
00672   return(asrtBuff->Buff);
00673 }
00674 
00675 /*----------------------------------------------------------------------*/
00676 /*  Function prototypes.                                                */
00677 /*----------------------------------------------------------------------*/
00678 
00679 static void db_genmvs(CTXTdeclc struct instruction_q *, RegStat);
00680 static void db_putterm(CTXTdeclc int, prolog_term, RegStat, struct flatten_q *);
00681 static void db_gentopinst(CTXTdeclc prolog_term, int, RegStat);
00682 static void db_genterms(CTXTdeclc struct instruction_q *, RegStat);
00683 static void db_geninst(CTXTdeclc prolog_term, RegStat, struct instruction_q *);
00684 static void db_bldsubs(CTXTdeclc prolog_term, RegStat, struct flatten_q *);
00685 static void db_genaput(CTXTdeclc prolog_term, int, struct instruction_q *, RegStat);
00686 
00687 /*======================================================================*/
00688 /*  The following code compiles a clause into a local buffer.  It       */
00689 /*  treats all rules as though they had a single literal on their       */
00690 /*  right-hand-side.  Thus it compiles a clause with more than one      */
00691 /*  literal on the right-hand-side as a call to the predicate ,/2.      */
00692 /*======================================================================*/
00693 
00694 int assert_code_to_buff_p(CTXTdeclc prolog_term);
00695 
00696 int assert_code_to_buff( CTXTdecl /* Clause */)
00697 {
00698   return assert_code_to_buff_p(CTXTc reg_term(CTXTc 1));
00699 }
00700 
00701 int assert_code_to_buff_p(CTXTdeclc prolog_term Clause)
00702 {
00703   prolog_term Head, Body;
00704   int Location;
00705   int Loc_size;
00706   struct RegStat_t Reg_lc;
00707   RegStat Reg = &Reg_lc;
00708   int Arity;
00709   int has_body;
00710   int Argno;
00711   int v;
00712   Pair sym;
00713   struct instruction_q inst_queue_lc;
00714   struct instruction_q *inst_queue = &inst_queue_lc;
00715 
00716   /* set catcher */
00717   if ((Argno = setjmp(assertcmp_env))) {
00718     assertcmp_printerror(CTXTc Argno);
00719     return FALSE;
00720   }
00721   if (isconstr(Clause) && get_str_psc(Clause)==if_psc) { 
00722     Head = p2p_arg(Clause, 1);
00723     Body = p2p_arg(Clause, 2);
00724     has_body = 1;
00725     if (isstring(Body)) {
00726       if (string_val(Body) == true_string) has_body = 0; 
00727       else {
00728         sym = insert(string_val(Body),0,(Psc)flags[CURRENT_MODULE],&v);
00729         Body = makecs(hreg);
00730         new_heap_functor(hreg,sym->psc_ptr);
00731       }
00732     }
00733   } else {
00734     Head = Clause;
00735     Body = (prolog_term) NULL;
00736     has_body = 0;
00737   }
00738   Arity = arity(CTXTc Head);
00739   Location = 0;
00740   asrtBuff->Loc = &Location;
00741   dbgen_instB_ppvw(test_heap,Arity,0);  /* size will be backpatched */
00742   Loc_size = *asrtBuff->Loc - sizeof(Cell);
00743   if (has_body) reg_init(Reg,xsb_max(Arity,(int)get_arity(get_str_psc(Body))));
00744   else reg_init(Reg,Arity);
00745   inst_queue_init(inst_queue);
00746   for (Argno = 1; Argno <= Arity; Argno++) {
00747     db_gentopinst(CTXTc p2p_arg(Head,Argno),Argno,Reg);
00748   }
00749   if (has_body) {
00750     inst_queue_init(inst_queue);
00751     for (Argno=1; Argno<=arity(CTXTc Body); Argno++) {
00752       db_genaput(CTXTc p2p_arg(Body,Argno),Argno,inst_queue,Reg);
00753     }
00754     db_genmvs(CTXTc inst_queue,Reg);
00755     dbgen_instB_pppw(xsb_execute, get_str_psc(Body));
00756   } else dbgen_instB_ppp(proceed);
00757   asrtBuff->Size = *asrtBuff->Loc;
00758   write_word(asrtBuff->Buff,&Loc_size,(asrtBuff->Size/sizeof(Cell)));  /* backpatch max heap needed*/
00759 
00760   return TRUE;
00761 }
00762 
00763 static void db_gentopinst(CTXTdeclc prolog_term T0, int Argno, RegStat Reg)
00764 {
00765   int Rt;
00766   struct instruction_q inst_queue_lc;
00767   struct instruction_q *inst_queue = &inst_queue_lc;
00768   
00769   if (isinteger(T0)) {
00770     dbgen_instB_ppvw(getnumcon, Argno, int_val(T0)); /* getnumcon */
00771   } else if (isstring(T0)) {
00772     if (strcmp(string_val(T0),"$assertAVAR"))
00773         dbgen_instB_ppvw(getcon, Argno, (Cell)string_val(T0));  /* getcon */
00774   } else if (isfloat(T0)) {
00775     dbgen_instB_ppvw(getfloat, Argno, T0); /* getfloat */
00776   } else if (isref(T0)) {
00777     c2p_functor(CTXTc "$assertVAR", 1, T0);
00778     T0 = p2p_arg(T0, 1);
00779     c2p_int(CTXTc Argno, T0);
00780     Reg->RegArrayInit[Argno] = 1;       /* Reg is initted */
00781   } else if (isnil(T0)) {
00782     dbgen_instB_ppv(getnil, Argno);     /* getnil */
00783   } else if ((Rt = is_frozen_var(T0))) {
00784     dbgen_instB_pvv(gettval, Rt, Argno);        /* gettval */
00785   } else {
00786     inst_queue_init(inst_queue);
00787     inst_queue_push(inst_queue, Argno, T0, 0);
00788     if (isattv(T0)) {
00789       T0 = p2p_arg(T0, 0);              /* the VAR part of the attv */
00790       c2p_functor(CTXTc "$assertVAR", 1, T0);
00791       T0 = p2p_arg(T0, 1);
00792       c2p_int(CTXTc Argno, T0);
00793       Reg->RegArrayInit[Argno] = 1;             /* Reg is initted */
00794     }      
00795     db_genterms(CTXTc inst_queue, Reg);
00796   }
00797 }
00798 
00799 static void db_genterms(CTXTdeclc struct instruction_q *inst_queue,
00800                         RegStat Reg)
00801 {
00802   prolog_term T0, T1, T2;
00803   Cell Argno;
00804   
00805   while (!inst_queue_empty(inst_queue)) {
00806     inst_queue_pop(inst_queue, &Argno, &T0, &T1);
00807     Reg->RegArrayInit[Argno] = 1;       /* Reg is initted */
00808     if (islist(T0)) {
00809       T1 = p2p_car(T0);
00810       T2 = p2p_cdr(T0);
00811       if (isref(T1) && isref(T2) && T1!=T2 /* not same var */) {
00812         int Rt1, Rt2;
00813         c2p_functor(CTXTc "$assertVAR", 1, T1);
00814         T1 = p2p_arg(T1, 1);
00815         Rt1 = reg_get(CTXTc Reg, RVAR);
00816         c2p_int(CTXTc Rt1, T1);
00817         c2p_functor(CTXTc "$assertVAR", 1, T2);
00818         T2 = p2p_arg(T2, 1);
00819         Rt2 = reg_get(CTXTc Reg, RVAR);
00820         c2p_int(CTXTc Rt2, T2);
00821         dbgen_instB3_tv(getlist_tvar_tvar, Argno, Rt1, Rt2);
00822         Reg->RegArrayInit[Rt1] = 1;     /* Reg is initted */
00823         Reg->RegArrayInit[Rt2] = 1;     /* Reg is initted */
00824         reg_release(Reg,Argno);
00825       } else {
00826         dbgen_instB_ppv(getlist, Argno);    /* getlist */
00827         reg_release(Reg,Argno);
00828         inst_queue->inst_queue_added = 0;
00829         db_geninst(CTXTc p2p_car(T0), Reg, inst_queue);
00830         db_geninst(CTXTc p2p_cdr(T0), Reg, inst_queue);
00831         inst_queue_rotate(inst_queue);
00832       }
00833     } else if (isconstr(T0)) {
00834       dbgen_instB_ppvw(getstr, Argno, get_str_psc(T0));   /* getstr */
00835       reg_release(Reg,Argno);
00836       inst_queue->inst_queue_added = 0;
00837       for (Argno=1; Argno <= (int)get_arity(get_str_psc(T0)); Argno++) {
00838         db_geninst(CTXTc p2p_arg(T0,Argno), Reg, inst_queue);
00839       }
00840       inst_queue_rotate(inst_queue);
00841     }
00842     else { /* is_attv(T0) */
00843       T1 = cell(clref_val(T0) + 1);     /* the ATTR part of the attv */
00844       XSB_Deref(T1);
00845       dbgen_instB_ppv(getattv, Argno);  /* getattv */
00846       /* The register for a new attv CANNOT be released ! */
00847       /* reg_release(Reg,Argno); */
00848       db_geninst(CTXTc T1, Reg, inst_queue);
00849     }
00850   }
00851 }
00852 
00853 static void db_geninst(CTXTdeclc prolog_term Sub, RegStat Reg,
00854                        struct instruction_q *inst_queue)
00855 {
00856   int Rt;
00857   
00858   if (isinteger(Sub)) {
00859     dbgen_instB_pppw(uninumcon, int_val(Sub));
00860   } else if (isstring(Sub)) {
00861     if (!strcmp(string_val(Sub),"$assertAVAR")) {
00862       dbgen_instB_ppp(uniavar);
00863     } else dbgen_instB_pppw(unicon, (Cell)p2c_string(Sub));
00864   } else if (isnil(Sub)) {
00865     dbgen_instB_ppp(uninil);
00866   } else if (isfloat(Sub)) {
00867     dbgen_instB_pppw(unifloat, Sub);
00868   } else if (isref(Sub)) {
00869     c2p_functor(CTXTc "$assertVAR", 1, Sub);
00870     Sub = p2p_arg(Sub, 1);
00871     Rt = reg_get(CTXTc Reg, RVAR);
00872     c2p_int(CTXTc Rt, Sub);
00873     dbgen_instB_ppv(unitvar, Rt);
00874     Reg->RegArrayInit[Rt] = 1;  /* reg is inited */
00875   } else if ((Rt = is_frozen_var(Sub))) {
00876     dbgen_instB_ppv(unitval, Rt);
00877   } else if (isattv(Sub)) {
00878     /*
00879      * An ATTV is treated as a real variable, so that the register will
00880      * never be released.
00881      */
00882     Rt = reg_get(CTXTc Reg, RVAR);
00883     dbgen_instB_ppv(unitvar, Rt);
00884     Reg->RegArrayInit[Rt] = 1;  /* reg is inited */
00885     inst_queue_add(inst_queue, Rt, Sub, 0);
00886 
00887     Sub = p2p_arg(Sub, 0);              /* the VAR part of the attv */
00888     c2p_functor(CTXTc "$assertVAR", 1, Sub);
00889     Sub = p2p_arg(Sub, 1);
00890     c2p_int(CTXTc Rt, Sub);
00891   } else {
00892     Rt = reg_get(CTXTc Reg, TVAR);
00893     dbgen_instB_ppv(unitvar, Rt);
00894     Reg->RegArrayInit[Rt] = 1;  /* reg is inited */
00895     inst_queue_add(inst_queue, Rt, Sub, 0);
00896   }
00897 }
00898 
00899 static void db_genaput(CTXTdeclc prolog_term T0, int Argno,
00900                        struct instruction_q *inst_queue,
00901                        RegStat Reg)
00902 {
00903   int Rt;
00904   struct flatten_q flatten_stack_lc;
00905   struct flatten_q *flatten_stackq = &flatten_stack_lc;
00906 
00907   if (isref(T0)) {
00908     c2p_functor(CTXTc "$assertVAR", 1, T0);
00909     T0 = p2p_arg(T0, 1);
00910     Rt = reg_get(CTXTc Reg, RVAR);
00911     c2p_int(CTXTc Rt, T0);  /* used to be TempVar???? */
00912     dbgen_instB_pvv(puttvar, Rt, Rt);
00913     Reg->RegArrayInit[Rt] = 1;  /* reg is inited */
00914     inst_queue_push(inst_queue, movreg, Rt, Argno);
00915   } else if ((Rt = is_frozen_var(T0))) {
00916     inst_queue_push(inst_queue, movreg, Rt, Argno);
00917   } else if (isinteger(T0)) {
00918     inst_queue_push(inst_queue, putnumcon, int_val(T0), Argno);
00919   } else if (isfloat(T0)) {
00920     inst_queue_push(inst_queue, putnumcon, p2c_float_as_int(T0), 
00921                     Argno);
00922   } else if (isnil(T0)) {
00923     inst_queue_push(inst_queue, putnil, 0, Argno);
00924   } else if (isstring(T0)) {
00925     if (!strcmp(string_val(T0),"$assertAVAR")) {
00926       Rt = reg_get(CTXTc Reg, RVAR);
00927       dbgen_instB_pvv(puttvar, Rt, Rt);
00928       Reg->RegArrayInit[Rt] = 1;  /* reg is inited */
00929       inst_queue_push(inst_queue, movreg, Rt, Argno);
00930     } else inst_queue_push(inst_queue, putcon, (Cell)p2c_string(T0), Argno);
00931   } else if (isattv(T0)) {
00932     prolog_term T1;
00933     
00934     Rt = reg_get(CTXTc Reg, RVAR);
00935     inst_queue_push(inst_queue, movreg, Rt, Argno);
00936     flatten_stack_init(flatten_stackq);
00937 
00938     T1 = p2p_arg(T0, 0);                /* the VAR part of the attv */
00939     c2p_functor(CTXTc "$assertVAR", 1, T1);
00940     T1 = p2p_arg(T1, 1);
00941     c2p_int(CTXTc Rt, T1);
00942     Reg->RegArrayInit[Rt] = 1;          /* Reg is initted */
00943 
00944     db_putterm(CTXTc Rt,T0,Reg,flatten_stackq);    
00945   } else {  /* structure */
00946     Rt = reg_get(CTXTc Reg, TVAR);
00947     inst_queue_push(inst_queue, movreg, Rt, Argno);
00948     flatten_stack_init(flatten_stackq);
00949     db_putterm(CTXTc Rt,T0,Reg,flatten_stackq);
00950   }
00951 }
00952 
00953 static void db_putterm(CTXTdeclc int Rt, prolog_term T0,
00954                        RegStat Reg, struct flatten_q *flatten_stackq)
00955 {
00956   int Argno;
00957   int BldOpcode;
00958   Cell Arg1;
00959   int stack_size;
00960   
00961   stack_size = flatten_stack_size(flatten_stackq);
00962   if (islist(T0)) {             /* is_list */
00963     db_bldsubs(CTXTc p2p_cdr(T0),Reg,flatten_stackq);
00964     db_bldsubs(CTXTc p2p_car(T0),Reg,flatten_stackq);
00965     dbgen_instB_ppv(putlist, Rt);                       /* putlist */
00966   } else if (isconstr(T0)) {    /* is_functor */
00967     for (Argno=get_arity(get_str_psc(T0)); Argno>=1; Argno--)
00968       db_bldsubs(CTXTc p2p_arg(T0,Argno),Reg,flatten_stackq);
00969     dbgen_instB_ppvw(putstr, Rt, get_str_psc(T0));      /* putstr */
00970   } else {                      /* is attv */
00971     db_bldsubs(CTXTc cell(clref_val(T0)+1), Reg, flatten_stackq);
00972     dbgen_instB_ppv(putattv, Rt);
00973   }
00974   Reg->RegArrayInit[Rt] = 1;    /* in any case, reg is inited */
00975   while (flatten_stack_size(flatten_stackq)>stack_size) {
00976     flatten_stack_pop(flatten_stackq, &BldOpcode, &Arg1);       
00977     /* be careful about order!!*/
00978     switch (BldOpcode) {
00979     case bldpvar:
00980       if (Reg->RegArrayInit[Arg1]) {
00981         dbgen_instB_ppv(bldpval, Arg1); break;
00982       } else {
00983         Reg->RegArrayInit[Arg1] = 1;
00984         dbgen_instB_ppv(bldpvar, Arg1); break;
00985       }
00986     case bldtvar:
00987       if (Reg->RegArrayInit[Arg1]) {
00988         dbgen_instB_ppv(bldtval, Arg1);
00989       } else {
00990         Reg->RegArrayInit[Arg1] = 1;
00991         dbgen_instB_ppv(bldtvar, Arg1);
00992       }
00993       break;
00994     case bldavar:
00995       dbgen_instB_ppp(bldavar); break;
00996     case bldcon:
00997       dbgen_instB_pppw(bldcon, Arg1); break;
00998     case bldnumcon:
00999       dbgen_instB_pppw(bldnumcon, Arg1); break;
01000     case bldfloat:
01001       dbgen_instB_pppw(bldfloat, Arg1); break;
01002     case bldnil:
01003       dbgen_instB_ppp(bldnil); break;
01004     default: 
01005       xsb_dbgmsg((LOG_DEBUG,"Incorrect bld instruction in assert %d", 
01006                   BldOpcode));
01007     }
01008   }
01009 }
01010 
01011 static void db_bldsubs(CTXTdeclc prolog_term Sub, RegStat Reg,
01012                        struct flatten_q *flatten_stackq)
01013 {
01014   int Rt;
01015   
01016   if (isstring(Sub)) {
01017     if (!strcmp(string_val(Sub),"$assertAVAR"))
01018       flatten_stack_push(flatten_stackq, bldavar, 0);
01019     else flatten_stack_push(flatten_stackq,bldcon,(Cell)string_val(Sub)); /* bldcon */
01020   } else if (isinteger(Sub)) {               /* bldnumcon(Sub) */
01021     flatten_stack_push(flatten_stackq, bldnumcon, int_val(Sub));
01022   } else if (isfloat(Sub)) {             /* bldfloat(Sub) */
01023     flatten_stack_push(flatten_stackq, bldfloat, Sub);
01024   } else if (isref(Sub)) {
01025     c2p_functor(CTXTc "$assertVAR", 1, Sub);
01026     Sub = p2p_arg(Sub, 1);
01027     Rt = reg_get(CTXTc Reg, RVAR);
01028     c2p_int(CTXTc Rt, Sub);
01029     flatten_stack_push(flatten_stackq, bldtvar, Rt);    /* bldtvar(Ri) */
01030   } else if (isnil(Sub)) {
01031     flatten_stack_push(flatten_stackq, bldnil, 0);      /* bldnil */
01032   } else if ((Rt = is_frozen_var(Sub))) {
01033     flatten_stack_push(flatten_stackq, bldtvar, Rt);
01034   } else if (isattv(Sub)) {
01035     prolog_term T1;
01036 
01037     Rt = reg_get(CTXTc Reg, RVAR);
01038     flatten_stack_push(flatten_stackq, bldtvar, Rt);
01039 
01040     T1 = p2p_arg(Sub, 0);       /* the VAR part of the attv */
01041     c2p_functor(CTXTc "$assertVAR", 1, T1);
01042     T1 = p2p_arg(T1, 1);
01043     c2p_int(CTXTc Rt, T1);
01044 
01045     /* Reg->RegArrayInit[Rt] will be set to 1 in db_putterm() */
01046 
01047     db_putterm(CTXTc Rt, Sub, Reg, flatten_stackq);
01048   } else {
01049     Rt = reg_get(CTXTc Reg, TVAR);
01050     flatten_stack_push(flatten_stackq, bldtvar, Rt);
01051     db_putterm(CTXTc Rt,Sub,Reg,flatten_stackq);
01052   }
01053 }
01054 
01055 static xsbBool target_is_not_source(struct instruction_q *inst_queue, int Reg)
01056 {
01057   int i;
01058   
01059   for (i=inst_queue->inst_queue_bottom; i<inst_queue->inst_queue_top; i++) {
01060     if (inst_queue->inst_queue[i].opcode==movreg && (int)inst_queue->inst_queue[i].arg1 == Reg)
01061       return FALSE;
01062   }
01063   return TRUE;
01064 }
01065 
01066 static xsbBool source_is_not_target(struct instruction_q *inst_queue, int Reg)
01067 {
01068   int i;
01069   
01070   for (i=inst_queue->inst_queue_bottom; i<inst_queue->inst_queue_top; i++) {
01071     if ((int)inst_queue->inst_queue[i].arg2 == Reg) return FALSE;
01072   }
01073   return TRUE;
01074 }
01075 
01076 /* this is a simple routine to generate a series of instructions to
01077    load a series of registers with constants or from other registers.
01078    It is given a list of Source,Target pairs.  Target is always a
01079    register  number.  Source may be a putcon(con), putnumcon(num),
01080    puttvar(reg), puttvar(Var), or movreg(reg).  The registers  can
01081    overlap in any way.  db_genmvs tries to generate a reasonably efficient
01082    series of instructions to load the indicated registers with the
01083    indicated values.  */ 
01084 
01085 static void db_genmvs(CTXTdeclc struct instruction_q *inst_queue, RegStat Reg)
01086 {
01087   Cell Opcode, Arg, T0, R0;
01088   
01089   /* pay attention to the ordering, must be a QUEUE !!!!! */
01090   while (!inst_queue_empty(inst_queue)) {
01091     inst_queue_rem(inst_queue, &Opcode, &Arg, &T0);     /* T0: target reg */
01092     switch (Opcode) {
01093     case puttvar:  
01094       dbgen_instB_pvv(Opcode, Arg, T0);
01095       break;
01096     case putnil:
01097       if (target_is_not_source(inst_queue,T0))
01098         {dbgen_instB_ppv(Opcode, T0);}
01099       else inst_queue_push(inst_queue, Opcode, Arg, T0);
01100       break;
01101     case putcon:
01102     case putnumcon:
01103       if (target_is_not_source(inst_queue,T0))
01104         {dbgen_instB_ppvw(Opcode, T0, Arg);}
01105       else inst_queue_push(inst_queue, Opcode, Arg, T0);
01106       break;
01107     case movreg:
01108       if (Arg==T0) break;
01109       else if (target_is_not_source(inst_queue,T0)) {
01110         dbgen_instB_pvv(movreg, Arg, T0); /* movreg */
01111         reg_release(Reg,Arg);
01112       } else if (source_is_not_target(inst_queue,Arg)) /* assume target is source */
01113         inst_queue_push(inst_queue, movreg, Arg, T0);
01114       /* delay the instruction at the end */
01115       /* else if (Arg>T0) dbgen_instB_pvv(movreg,Arg,T0); movreg */
01116       else {
01117         R0 = reg_get(CTXTc Reg, TVAR);
01118         dbgen_instB_pvv(movreg, Arg, R0); /* movreg */
01119         reg_release(Reg,Arg);
01120         inst_queue_push(inst_queue, movreg, R0, T0);
01121         /* dbgen_instB_pvv(movreg, R0, T0); */ /* movreg */
01122       }
01123       break;
01124     }
01125   }
01126 }
01127 
01128 /*======================================================================*/
01129 /*      The following byte offsets are valid for 32 bit architectures   */
01130 /*      For 64 bit architecture multiply everything by 2                */
01131 /*======================================================================*/
01132 
01133 /*======================================================================*/
01134 /* assert_buff_to_clref(+Term +Arg,+Arity,+Prref,+AZ,+Index,+HashTabSize)*/
01135 /*      allocates a Clref, copies the byte-code for the clause from     */
01136 /*      an internal buffer into it, and adds to to the chains.          */
01137 /*      The arguments are:                                              */
01138 /*      Term:  The term being asserted.                                 */
01139 /*      Arg:   The argument value of the indexed arg (ignored if no ind)*/
01140 /*      Arity: the number of registers to save in a choice point.       */
01141 /*              Note the Arity is one more than the original arity, to  */
01142 /*              hold the cut address.                                   */
01143 /*      Prref: predicate reference to which to add the asserted fact    */
01144 /*      AZ:   0 - inserted as the first clause; 1 - as the last clause  */
01145 /*      Index:  0 if no index is to be built, or n if an index          */
01146 /*              on the nth argument of the fact is to be used           */
01147 /*      HashTabSize:  The size of the hash table to create if one must  */
01148 /*              be created for this clause (the SOB record)             */
01149 /*======================================================================*/
01150 
01151 /*======================================================================*/
01152 /* Formats for dynamic code:                                            */
01153 /* PSC rec point to:                                                    */
01154 /*      PrRef:                                                          */
01155 /*              0: BC instruction: fail (if empty),                     */
01156 /*                      jump and save breg (if nonempty)                */
01157 /*              4: Addr of first Clref on ALL chain                     */
01158 /*              8: Addr of last Clref on ALL chain                      */
01159 /*                                                                      */
01160 /* PrRef's point to chain of clRef's (one of 2 types):                  */
01161 /* (the -8 location stores length of buff + flag indicating ClRef type  */
01162 /*                                                                      */
01163 /* Whoever set this up arranged for the pointer to point AFTER the      */
01164 /* Clref structure.  So if you want to acess it as a structure you need */
01165 /* to decrement it (see macros below)                                   */
01166 /*                                                                      */
01167 /*      ClRef0 (for unindexed asserted code):                           */
01168 /*              -8: length of buffer (+0)                               */
01169 /*              -4: Addr of previous ClRef (or PrRef)                   */
01170 /*              0: Trymeelse-type instruction, for chain                */
01171 /*              4: (cont) Addr of next ClRef on chain                   */
01172 /*              8+: BC for asserted clause                              */
01173 /*      ClRef1 (for group of indexed clauses, aka SOB record):          */
01174 /*              -8: length of buffer (+1)                               */
01175 /*              -4: Addr of previous ClRef (or PrRef)                   */
01176 /*              0: Try-type instruction, for chain                      */
01177 /*              4: (cont) Addr of next ClRef on chain,                  */
01178 /*                      if trust-type then ptr to prref, if first-level */
01179 /*                      SOB, or ptr to previous enclosing SOB+20        */
01180 /*              8: BC switch-on-bound instruction (drop thru if var)    */
01181 /*              11: (cont) arg(s) to index on                           */
01182 /*              12: (cont) address of Hash Table                        */
01183 /*              16: (cont) size of Hash Table                           */
01184 /*              20: BC jump to...       (or fail if empty)              */
01185 /*              24: (cont) Addr of first ClRefI on all subchain         */
01186 /*                  or to ClRef1 for next index                         */
01187 /*              28: Addr of last ClRefI on all subchain                 */
01188 /*              32: Number of clauses accessible thru this hash table   */
01189 /*              36+: Hash Table                                         */
01190 /*                                                                      */
01191 /* ClRef1's point to indexed clauses, each represented by a ClRefI:     */
01192 /*      ClRefI (for an indexed clause):                                 */
01193 /*              -8: length of buffer (+3)                               */
01194 /*              -4: Addr of previous ClRefI on all chain                */
01195 /*              0: Try-type instruction, for all subchain               */
01196 /*              4: (cont) Addr of next ClRefI on all subchain           */
01197 /*            For each index we have the following four fields:         */
01198 /*              8: BC noop(14) to skip next NI*8-2 bytes                */
01199 /*              12: Addr of previous ClRefI on bucket chain             */
01200 /*              16: Try-type instruction, for hash bucket subchain      */
01201 /*              20: (cont) Addr of next ClRefI in bucket,               */
01202 /*                  or back to SOB rec if last                          */
01203 /*              24: BC noop(6) to skip next (NI-1)*8-2 bytes            */
01204 /*              28: Addr of previous ClRefI on bucket chain             */
01205 /*              32: Try-type instruction, for hash bucket subchain      */
01206 /*              36: (cont) Addr of next ClRefI in bucket                */
01207 /*         NI*16+8: BC for asserted code                                */
01208 /*                                                                      */
01209 /*======================================================================*/
01210 
01211 /* Predicate References defined in macro_xsb.h / clause reference in context.h  */
01212 
01213 typedef struct ClRefHdrI *ClRefI;
01214 typedef struct  {
01215   unsigned long buflen ;
01216   struct ClRefI *prev ;
01217   CPtr Instr ;
01218   struct ClRefI *next ;
01219 }       ClRefHdrI;
01220 
01221 
01222 #ifdef BITS64
01223 #define HIGHBIT 0x8000000000000000
01224 #else
01225 #define HIGHBIT 0x80000000
01226 #endif
01227 
01228 #define PredOpCode(P)           (cell_opcode(&(P)->Instr))
01229 
01230 typedef ClRef SOBRef ;
01231 
01232 #define ClRefAddr(Cl)           ((CPtr)((ClRef)(Cl)-1))
01233 #define ClRefSize(Cl)           (((ClRef)(Cl))[-1].buflen & ~0x3 & ~HIGHBIT)
01234 #define ClRefType(Cl)           (((ClRef)(Cl))[-1].buflen & 0x3)
01235 #define SetClRefSize(Cl,len)    (((ClRef)(Cl))[-1].buflen |= \
01236                 (((ClRef)(Cl))[-1].buflen & 0x3) | ((len) & ~0x3))
01237 #define SetClRefType(Cl,type)   (((ClRef)(Cl))[-1].buflen = \
01238                 (((ClRef)(Cl))[-1].buflen & ~0x3) | ((type) & 0x3))
01239 #define ClRefPrev(Cl)           (((ClRef)(Cl))[-1].prev)
01240 #define ClRefWord(Cl,pos)       (((CPtr)(Cl))[(pos)])
01241 
01242 #define SetClRefPrev(Cl,Prv)    (((ClRef)(Cl))[-1].prev = (ClRef)(Prv))
01243 
01244 /* Clause types */
01245 
01246 #define UNINDEXED_CL    0
01247 #define SOB_RECORD      1
01248 #define TRIE_CL         2
01249 #define INDEXED_CL      3
01250 
01251 #define MakeClRef(ptr,Type,NCells)\
01252 {       long sz = (((NCells)*sizeof(Cell)+sizeof(ClRefHdr) + 7) & ~0x7);        \
01253         (ptr) = (ClRef)mem_calloc(sz,1,ASSERT_SPACE);\
01254         (ptr)->buflen = ((Type)&3)+sz;\
01255         (ptr)++;\
01256 }
01257 
01258 /* Clause common fields */
01259 
01260 #define ClRefTryInstr(Cl)       (ClRefWord((Cl),0))
01261 #define ClRefTryOpCode(Cl)      (cell_opcode(&ClRefTryInstr(Cl)))
01262 #define ClRefNext(Cl)           ((ClRef)ClRefWord((Cl),1))
01263 
01264 
01265 #define SetClRefNext(Cl,Nxt)    (ClRefWord((Cl),1)=(Cell)(Nxt))
01266 
01267 /* First byte code in clause at word 2  - Jump/SOB/etc */
01268 #define ClRefEntryPoint(Cl)     (&ClRefWord((Cl),2))
01269 
01270 /* For compiled clause */
01271 #define ClRefCompiledCode(Cl)   (ClRefWord((Cl),3))
01272 
01273 /* For indexed clause group (SOBblock) */
01274 
01275 #define ClRefSOBInstr(Cl)       (ClRefWord((Cl),2))
01276 #define ClRefHashSize(Cl)       (ClRefWord((Cl),4))
01277 #define ClRefJumpInstr(Cl)      (ClRefWord((Cl),5))
01278 #define ClRefFirstIndex(Cl)     (ClRefWord((Cl),6))
01279 #define ClRefLastIndex(Cl)      (ClRefWord((Cl),7))
01280 #define ClRefNumNonemptyBuckets(Cl)     (ClRefWord((Cl),8))
01281 #define ClRefHashTable(Cl)      (&ClRefWord((Cl),9))
01282 #define ClRefHashBucket(Cl,b)   ((CPtr)(ClRefHashTable(Cl)[(b)]))
01283 
01284 #define ClRefSOBArg(Cl,n)       (cell_operandn(&ClRefWord((Cl),2),(n)))
01285 
01286 /* Get the PrRef field of a SOB */
01287 #define ClRefPrRef(Cl)          ((PrRef)&ClRefWord((Cl),5))
01288 
01289 /* Get the ClRef containing the PrRef */
01290 #define PrRefClRef(Pr)          ((ClRef)((CPtr)(Pr)-5))
01291 
01292 #define ClRefUpSOB(Cl)          (PrRefClRef(ClRefNext(Cl)))
01293 
01294 /* For Indexed clause index table */
01295 
01296 #define ClRefNumInds(Cl)\
01297          ( (cell_operand3(&ClRefWord((Cl),2))/(sizeof(Cell)/2) + 1)/4 )
01298 #define ClRefIndPtr(Cl,Ind)     (&ClRefWord((Cl),(Ind)*4))
01299 
01300 #define IndPtrClRef(IP,Ind)     ((ClRef)((CPtr)(IP)-(Ind)*4))
01301 #define IndRefNoop(IndPtr)      ((IndPtr)[-2])
01302 #define IndRefPrev(IndPtr)      (((CPtr *)(IndPtr))[-1])
01303 #define IndRefTryInstr(IndPtr)  ((IndPtr)[0])
01304 #define IndRefNext(IndPtr)      (((CPtr *)(IndPtr))[1])
01305 
01306 #define IC_CELLS(NI)            (4*(NI)+2)
01307 
01308 #define ClRefIEntryPoint(Cl,NI) (&ClRefWord((Cl),IC_CELLS(NI)))
01309 
01310 /* First word of code in an (un)indexed clause */
01311 #define ClRefEntryAny(Cl)                                               \
01312         ((CPtr)                                                         \
01313                 ((ClRefType(Cl)&1) == UNINDEXED_CL ? ClRefEntryPoint(Cl) :\
01314                                 ClRefIEntryPoint((Cl),ClRefNumInds(Cl)) \
01315         ))
01316 
01317 #define ClRefNotRetracted(Cl) (cell_opcode(ClRefEntryAny(Cl))!=fail || \
01318                                cell_operand1(ClRefEntryAny(Cl))!=MARKED_FOR_DELETION)
01319 
01320 static void db_addbuff(byte, ClRef, PrRef, int, int, int); 
01321 static void db_addbuff_i(byte, ClRef, PrRef, int, int *, int, prolog_term, int);
01322 
01323 /************************************************************/
01324 /* debugging code to dump asserted code index structure     */
01325 /* (works only for 32-bit machines                          */
01326 /************************************************************/
01327 /********* COMMENTED OUT UNTIL NEEDED ***
01328 void asrt_tab(FILE *fd, int ind) {
01329   int i;
01330   for (i=0;i<ind;i++) fprintf(fd," ");
01331 }
01332 
01333 void dump_assert_index_block(FILE *fd, ClRef clrefptr, ClRef lastclrefptr, int indent) {
01334   int htsize, i, j, numindexes;
01335 
01336   do {
01337     if (ClRefType(clrefptr) == UNINDEXED_CL) {
01338       fprintf(fd,"UI %p: Len: %lu, Prev: %p, Try: %lx, Else: %p\n",
01339               clrefptr, ClRefSize(clrefptr), ClRefPrev(clrefptr), ClRefTryInstr(clrefptr), 
01340               ClRefNext(clrefptr));
01341     } else if (ClRefType(clrefptr) == SOB_RECORD) {
01342       asrt_tab(fd,indent);
01343       fprintf(fd,"SB %p: Len: %lu, Prev: %p, Try: %lx, Else: %p\n",
01344               clrefptr, ClRefSize(clrefptr), ClRefPrev(clrefptr), ClRefTryInstr(clrefptr), 
01345               ClRefNext(clrefptr));
01346       asrt_tab(fd,indent+12);
01347       fprintf(fd,"SOB: %lx, HT: %lx, HTs: %lu, BR: %lx, Else: %lx, Last: %lx, Num: %ld\n",
01348               ClRefSOBInstr(clrefptr), ClRefWord(clrefptr,3), ClRefHashSize(clrefptr), 
01349               ClRefJumpInstr(clrefptr), ClRefFirstIndex(clrefptr),
01350               ClRefLastIndex(clrefptr), ClRefNumNonemptyBuckets(clrefptr));
01351       htsize = ClRefHashSize(clrefptr);
01352       for (i=0; i<htsize; i++) {
01353         if (ClRefHashBucket(clrefptr,i) != &dynfail_inst) {
01354           asrt_tab(fd,indent+12);
01355           fprintf(fd,"HT %p: %p\n",&ClRefWord(clrefptr,i+9),ClRefHashBucket(clrefptr,i));
01356         }
01357       }
01358       fprintf(fd,"\n");
01359       dump_assert_index_block(fd,(ClRef)ClRefFirstIndex(clrefptr),
01360                               (ClRef)ClRefLastIndex(clrefptr),indent+2);
01361     } else if (ClRefType(clrefptr) == INDEXED_CL) {
01362       fprintf(fd,"IC %p: Len: %ld, Prev: %p, Try: %lx, Else: %p\n",
01363               clrefptr, ClRefSize(clrefptr), ClRefPrev(clrefptr), 
01364               ClRefTryInstr(clrefptr), IndRefNext(clrefptr));
01365       numindexes = ClRefNumInds(clrefptr);
01366       for (j=0; j<numindexes; j++) {
01367         fprintf(fd,"   %p: BR: %lx, Prev: %lx, Try: %lx, Nxt: %lx\n",
01368                 &ClRefWord(clrefptr,4*j+2)+2,
01369                 ClRefWord(clrefptr,4*j+2),ClRefWord(clrefptr,4*j+3),
01370                 ClRefWord(clrefptr,4*j+4),ClRefWord(clrefptr,4*j+5));
01371       }
01372       fprintf(fd,"\n");
01373     } else xsb_abort("bad format");
01374     if (clrefptr == lastclrefptr) return;
01375     clrefptr = ClRefNext(clrefptr);
01376   }
01377   while (1);
01378 }
01379 
01380 void dump_asserted_pred(PrRef prref, char *dumpfilename) {
01381   FILE *fd;
01382 
01383   fd = fopen(dumpfilename,"w");
01384 
01385   fprintf(fd,"PR %p: BR: %lx, Fst: %lx, Lst: %lx\n\n",
01386           prref, *((long unsigned int *)prref), 
01387           *((long unsigned int *)prref+1), *((long unsigned int *)prref+2));
01388 
01389   dump_assert_index_block(fd,*((ClRef *)prref+1),*((ClRef *)prref+2),0);
01390   fclose(fd);
01391 }
01392 **** COMMENTED OUT UNTIL NEEDED **********/
01393 /***************************************************************/
01394 /* end of debugging code to dump asserted code index structure */
01395 /***************************************************************/
01396 
01397 /* Used by assert & retract to get through the SOBs */
01398 
01399 static void get_indexes( prolog_term prolog_ind, int *Index, int *NI )
01400 {
01401   Index[0] = 0;
01402   if (isinteger(prolog_ind)) {
01403     Index[1] = int_val(prolog_ind);
01404     if (Index[1] == 0) *NI = 0; else *NI = 1;
01405   } else {
01406     for (*NI = 0; !isnil(prolog_ind); prolog_ind = p2p_cdr(prolog_ind)) {
01407       (*NI)++;
01408       Index[*NI] = int_val(p2p_car(prolog_ind));
01409     }
01410   }
01411 }
01412 
01413 /* Add the global buffer, which must have been filled, into the index
01414     for the Prref */
01415 
01416 xsbBool assert_buff_to_clref_p(CTXTdeclc prolog_term,byte,PrRef,int,
01417                                prolog_term,int,ClRef *);
01418 
01419 xsbBool assert_buff_to_clref(CTXTdecl /*Head,Arity,Prref,AZ,Indexes,HashTabSize,Clref*/)
01420 {
01421   ClRef Clref;
01422   assert_buff_to_clref_p(CTXTc reg_term(CTXTc 1),
01423                          (byte)ptoc_int(CTXTc 2),
01424                          (PrRef)ptoc_int(CTXTc 3),
01425                          ptoc_int(CTXTc 4),
01426                          reg_term(CTXTc 5),
01427                          ptoc_int(CTXTc 6),
01428                          &Clref);
01429   /* ctop_int(7, (Integer Clref)); */
01430   return TRUE;
01431 }
01432 
01433 xsbBool assert_buff_to_clref_p(CTXTdeclc prolog_term Head,
01434                                byte Arity,
01435                                PrRef Pred,
01436                                int AZ,
01437                                prolog_term Indexes,
01438                                int HashTabSize,
01439                                ClRef *Clref)
01440 {
01441   ClRef Clause;
01442   int Location, *Loc, Inum;
01443   int Index[20], NI;
01444 
01445   xsb_dbgmsg((LOG_ASSERT,"Now add clref to chain:"));
01446 
01447   get_indexes( Indexes, Index, &NI ) ;
01448 
01449   MakeClRef( Clause,
01450              (NI>0) ? INDEXED_CL : UNINDEXED_CL,
01451              //      IC_CELLS(NI) + ((asrtBuff->Size+0xf)&~0x7)/sizeof(Cell) ) ;
01452              IC_CELLS(NI) + ((asrtBuff->Size+0x7)&~0x7)/sizeof(Cell) ) ;
01453 
01454   if (xsb_profiling_enabled)
01455     add_prog_seg(get_str_psc(Head),(byte *)Clause,ClRefSize(Clause));
01456 
01457   //  printf("asserting clause for: %s/%d at %x\n",
01458   // get_name(get_str_psc(Head)),get_arity(get_str_psc(Head)),Clause);
01459 
01460   Location = 0; Loc = &Location;
01461   dbgen_inst_ppv(dynnoop,sizeof(Cell)/2,Clause,Loc);    /* will become dyntry */
01462   write_word(Clause,Loc,0);
01463   for (Inum = NI; Inum > 0; Inum--) {
01464     /* put template code for chaining buffers from hash tables  */
01465     dbgen_inst_ppv(noop,(4*Inum-1)*sizeof(Cell)/2,Clause,Loc);  /* noop(6) */
01466     write_word(Clause,Loc,0);
01467     dbgen_inst_ppv(dynnoop,sizeof(Cell)/2,Clause,Loc);             /* noop(2) */
01468     write_word(Clause,Loc,0);
01469   }
01470 
01471 /* asrtBuff->Buff is a global variable used to communicate from assert_code_to_buff
01472    to assert_buff_to_clref through PROLOG calls */
01473 
01474   memmove(((pb)Clause)+Location,asrtBuff->Buff,asrtBuff->Size); /* fill in clause with code from Buff */
01475   /* ctop_int(7, (Integer)Clause);  DO NOT RETURN ANYTHING */
01476   /* *Clref = Clause; */
01477   
01478   SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
01479 
01480   if (NI <= 0) db_addbuff(Arity,Clause,Pred,AZ,FALSE,1);
01481   else db_addbuff_i(Arity,Clause,Pred,AZ,Index,NI,Head,HashTabSize);
01482 
01483   SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
01484 
01485   return TRUE;
01486 }
01487 
01488 /* add NewClause to beginning of try-retry chain beginning with FirstClause */
01489 static void prefix_to_chain(int ifSOB, byte Arity, ClRef FirstClause, ClRef NewClause)
01490 {
01491   int Loc = 0;
01492   dbgen_inst_ppvw(ifSOB?trymeelse:dyntrymeelse,Arity,FirstClause,NewClause,&Loc);
01493 
01494   Loc = 0;
01495   if (ClRefTryOpCode(FirstClause) == dynnoop || ClRefTryOpCode(FirstClause) == noop)
01496   {  dbgen_inst_ppvw(dyntrustmeelsefail,Arity,ClRefNext(FirstClause),
01497                      FirstClause,&Loc); }
01498   else if (ClRefTryOpCode(FirstClause) == dyntrymeelse ||
01499            ClRefTryOpCode(FirstClause) == trymeelse)
01500   {  dbgen_inst_ppvw(dynretrymeelse,Arity,ClRefNext(FirstClause),
01501                      FirstClause,&Loc);}
01502   else xsb_dbgmsg((LOG_DEBUG,"***Error 1 in assert: 0x%x",
01503                   ClRefTryOpCode(FirstClause)));
01504 
01505   ClRefPrev(NewClause)   = ClRefPrev(FirstClause);
01506   ClRefPrev(FirstClause) = NewClause;
01507 
01508 }
01509 
01510 /* add NewClause after LastClause on try-retry chain */
01511 static void append_to_chain(byte Arity, ClRef LastClause, ClRef NewClause)
01512 {
01513   int Loc = 0;
01514   dbgen_inst_ppvw(dyntrustmeelsefail,Arity,ClRefNext(LastClause),
01515                   NewClause,&Loc);
01516   SetClRefPrev(NewClause, LastClause);
01517 
01518   Loc = 0;
01519   if (ClRefTryOpCode(LastClause) == dynnoop)
01520   {  dbgen_inst_ppvw_safe(dyntrymeelse,Arity,NewClause,
01521                      LastClause,&Loc);  }
01522   else if (ClRefTryOpCode(LastClause) == noop)
01523   {  dbgen_inst_ppvw_safe(trymeelse,Arity,NewClause,
01524                      LastClause,&Loc);  }
01525   else if (ClRefTryOpCode(LastClause) == dyntrustmeelsefail)
01526   {  dbgen_inst_ppvw_safe(dynretrymeelse,Arity,NewClause,
01527                      LastClause,&Loc);  }
01528   else xsb_dbgmsg((LOG_DEBUG,"***Error 2 in assert: 0x%x",
01529                   ClRefTryOpCode(LastClause)));
01530 
01531 }
01532 
01533 /* add Clause to end of Pred */
01534 static void db_addbuff(byte Arity, ClRef Clause, PrRef Pred, int AZ, int ifSOB, int Inum) 
01535 {
01536   int Loc; 
01537   ClRef LastClause ;
01538   
01539   if (PredOpCode(Pred) == fail) {
01540     Loc = 0;
01541     dbgen_inst_ppv(ifSOB?noop:dynnoop,sizeof(Cell)/2,Clause,&Loc);
01542     SetClRefNext(Clause, Pred) ;
01543     Loc = 0;
01544     if (Inum > 1) {dbgen_inst_pppw(jump,Clause,Pred,&Loc);}
01545     else dbgen_inst_ppvw(jumptbreg,Arity,Clause,Pred,&Loc);
01546     Pred->LastClRef = Clause ;
01547     SetClRefPrev(Clause, Pred) ;
01548   } else if ( PredOpCode(Pred) == jumptbreg || PredOpCode(Pred) == jump ) {
01549     if (AZ == 0) {
01550       prefix_to_chain(ifSOB, Arity, Pred->FirstClRef, Clause);
01551       Pred->FirstClRef = Clause ;
01552     } else {
01553       LastClause = Pred->LastClRef ;
01554       append_to_chain(Arity,LastClause,Clause);
01555       Pred->LastClRef = Clause ;
01556     }
01557   } else xsb_dbgmsg((LOG_DEBUG,"***Error 3 in assert"));
01558 }
01559 
01560 #define NUMHASHSIZES 16
01561 /* some primes for hash table sizes */
01562 static int hashsizes_table[NUMHASHSIZES] = {17,503,5003,49999,200003,400009,700001,1000003,
01563         1000033,1000037,1000039,1000081,1000099,1000117,1000121,1000133}; 
01564 
01565 static int hash_resize( PrRef Pred, SOBRef SOBrec, unsigned int OldTabSize )
01566 {
01567    unsigned int ThisTabSize ;
01568    int i;
01569 
01570 /* xsb_dbgmsg(LOG_DEBUG,"SOB - %p, with %d cls",
01571               SOBrec, ClRefNumNonemptyBuckets(SOBrec) ) ; */
01572    /* Compute number of clauses */
01573    if( PredOpCode(Pred) != fail && ClRefType(SOBrec) == SOB_RECORD ) {
01574      ThisTabSize = ClRefHashSize(SOBrec) ;
01575      if (ClRefNumNonemptyBuckets(SOBrec) > (ThisTabSize/4)*3) {
01576        if (ThisTabSize >= (unsigned int) hashsizes_table[NUMHASHSIZES-1]) {
01577          ThisTabSize = ThisTabSize+2;
01578        } else {
01579          for (i=0; i<NUMHASHSIZES; i++) 
01580            if ((unsigned int) hashsizes_table[i] > ThisTabSize) break; 
01581          ThisTabSize = hashsizes_table[i];
01582        }
01583        /*printf("Resizing HT to %d\n",ThisTabSize);*/
01584      }
01585      return xsb_max(ThisTabSize, OldTabSize) ;
01586    }
01587    else return OldTabSize ;
01588 }
01589 
01590 static int hash_val(int Ind, prolog_term Head, int TabSize )
01591 /* return -1 if cannot hash to this Ind (var) */
01592 {
01593   int Hashval = 0 ;
01594   int i, j ;
01595   prolog_term Arg ;
01596 
01597   if (Ind <= 0xff) {  /* handle usual case specially */
01598     Arg = p2p_arg(Head,Ind) ;
01599     /* The following line is a hack and should be taken out
01600      * when the compiler change for indexing []/0 is made. */
01601     if (isnil(Arg)) Hashval = ihash(0, TabSize);
01602     else if (isref(Arg) || isattv(Arg)) Hashval = -1;
01603     else Hashval = ihash(val_to_hash(Arg), TabSize);
01604   } else {   /* handle joint indexes */
01605     for (i = 2; i >= 0; i--) {
01606       j = (Ind >> (i*8)) & 0xff;
01607       if (j > 0) {
01608         if (j <= 0x80) {
01609           Arg = p2p_arg(Head,j);
01610           if (isref(Arg) || isattv(Arg)) return -1;
01611           else Hashval += Hashval + ihash(val_to_hash(Arg), TabSize);
01612         } else {
01613           prolog_term *stk[MAXTOINDEX], term;
01614           int k, depth = 0, argsleft[MAXTOINDEX];
01615           argsleft[0] = 1;
01616           term = Head; XSB_Deref(term);
01617           stk[0] = clref_val(term)+ (j - 0x80);
01618           for (k = MAXTOINDEX; k > 0; k--) {
01619             /*printf("depth = %d, left = %d\n",depth,argsleft[depth]);*/
01620             if (depth < 0) break; /* out of for */
01621             term = *stk[depth];
01622             argsleft[depth]--;
01623             if (argsleft[depth] <= 0) depth--;
01624             else stk[depth]++;
01625             XSB_Deref(term);
01626             switch (cell_tag(term)) {
01627               /* These must match what's done in val_to_hash, except it goes through structures */
01628             case XSB_FREE:
01629             case XSB_REF1:
01630             case XSB_ATTV:
01631               return -1;
01632             case XSB_INT: 
01633             case XSB_FLOAT:     /* Yes, use int_val to avoid conversion problem */
01634               term = (Cell)int_val(term);
01635               break;
01636             case XSB_LIST:
01637               depth++;
01638               argsleft[depth] = 2;
01639               stk[depth] = clref_val(term);
01640               term = (Cell)(list_pscPair); 
01641               break;
01642             case XSB_STRUCT:
01643               if (isboxedinteger(term)) {
01644                 term = (Cell)boxedint_val(term);
01645               } else if (isboxedfloat(term)) {
01646                 term = int_val(cell(clref_val(term)+1)) ^
01647                   int_val(cell(clref_val(term)+2)) ^
01648                   int_val(cell(clref_val(term)+3));
01649               } else {
01650                 depth++;
01651                 argsleft[depth] = get_arity(get_str_psc(term));
01652                 stk[depth] = clref_val(term)+1;
01653                 term = (Cell)get_str_psc(term);
01654               }
01655               break;
01656             case XSB_STRING:
01657               term = (Cell)string_val(term);
01658               break;
01659             }
01660             Hashval += Hashval + ihash(term, TabSize);
01661           }
01662         }
01663       }
01664     }
01665     Hashval %= TabSize;
01666   }
01667   return Hashval ;
01668 }
01669 
01670 static SOBRef new_SOBblock(int ThisTabSize, int Ind, Psc psc )
01671 {
01672    int i, Loc ;
01673    SOBRef NewSOB ;
01674 
01675    /* get NEW SOB block */
01676    MakeClRef(NewSOB,SOB_RECORD,9+ThisTabSize);
01677    /*   xsb_dbgmsg((LOG_DEBUG,"New SOB %p, size = %d", NewSOB, ThisTabSize)); */
01678 
01679    if (xsb_profiling_enabled)
01680      add_prog_seg(psc,(byte *)NewSOB,ClRefSize(NewSOB)); /* dsw profiling */
01681 
01682    Loc = 0 ;
01683    dbgen_inst3_sob( Ind>0xff ? switchon3bound : switchonbound,
01684           Ind,((Integer)ClRefHashTable(NewSOB)),ThisTabSize,&ClRefSOBInstr(NewSOB),&Loc);
01685    /* set the PrRef inside SOB */
01686    Loc = 0 ;
01687    dbgen_inst_ppp(fail,&ClRefJumpInstr(NewSOB),&Loc);
01688    ClRefFirstIndex(NewSOB) = (Cell)&ClRefJumpInstr(NewSOB) ;
01689    ClRefLastIndex( NewSOB) = (Cell)&ClRefJumpInstr(NewSOB) ;
01690    ClRefNumNonemptyBuckets(NewSOB) = 0 ;
01691       
01692    /* Initialize hash table */
01693    for (i = 0; i < ThisTabSize; i++)
01694       ClRefHashTable(NewSOB)[i] = (Cell)&dynfail_inst ;
01695 
01696    return NewSOB ;
01697 }
01698 
01699 static void addto_hashchain( int AZ, int Hashval, SOBRef SOBrec, CPtr NewInd,
01700                              int Arity )
01701 {
01702     CPtr *Bucketaddr = (CPtr *) (ClRefHashTable(SOBrec) + Hashval);
01703     CPtr OldInd = *Bucketaddr ;
01704     int Loc ;
01705 
01706     if ((pb)OldInd == (pb)&dynfail_inst) { /* empty bucket, add first clause */
01707       *Bucketaddr = NewInd ;
01708       IndRefPrev(NewInd) = (CPtr) Bucketaddr ;
01709       IndRefNext(NewInd) = (CPtr) SOBrec ;
01710       ClRefNumNonemptyBuckets(SOBrec)++ ;
01711     } else if (AZ == 0) { /* add at beginning */
01712       Loc = 0;
01713       dbgen_inst_ppvw(dyntrymeelse,Arity,OldInd,NewInd,&Loc);
01714       Loc = 0;
01715       if (cell_opcode(OldInd) == dynnoop)
01716       {  dbgen_inst_ppvw(dyntrustmeelsefail,Arity,IndRefNext(OldInd),
01717                          OldInd,&Loc); }
01718       else
01719       {  dbgen_inst_ppvw(dynretrymeelse,Arity,IndRefNext(OldInd),
01720                          OldInd,&Loc); }
01721       IndRefPrev(OldInd) = NewInd;
01722       *Bucketaddr = NewInd ;
01723       IndRefPrev(NewInd) = (CPtr) Bucketaddr ;
01724     } else { /* AZ == 1 add at end */
01725       Loc = 0;
01726       dbgen_inst_ppvw(dyntrustmeelsefail,Arity, SOBrec, NewInd,&Loc);
01727       Loc = 0;
01728       if (cell_opcode(OldInd) == dynnoop)
01729       {  dbgen_inst_ppvw_safe(dyntrymeelse,Arity,NewInd,OldInd,&Loc); }
01730       else {
01731         while (cell_opcode(OldInd) != dyntrustmeelsefail)
01732           OldInd = IndRefNext(OldInd);
01733         dbgen_inst_ppvw_safe(dynretrymeelse,Arity,NewInd,OldInd,&Loc);
01734       }
01735       IndRefPrev(NewInd) = OldInd ;
01736     }
01737 }
01738 
01739 static void addto_allchain( int AZ, ClRef Clause, SOBRef SOBrec, byte Arity)
01740 {
01741   ClRef Last, First ;
01742   int Loc ;
01743 
01744   /* add code buff to all chain */
01745   if (PredOpCode(ClRefPrRef(SOBrec)) == fail) { /* insert first clrefI into SOB buff */
01746     Loc = 0;
01747     dbgen_inst_ppv(dynnoop,sizeof(Cell)/2,Clause,&Loc);
01748     Loc = 0 ;
01749     dbgen_inst_pppw(jump,Clause,ClRefPrRef(SOBrec),&Loc);
01750     ClRefLastIndex(SOBrec) = (Cell) Clause ;
01751     ClRefPrev(Clause) = SOBrec ;
01752     SetClRefNext(Clause, SOBrec);
01753   } else if (AZ == 0) {  /* add at beginning */
01754     First = (ClRef) ClRefFirstIndex(SOBrec);
01755     prefix_to_chain(FALSE,Arity,First,Clause);
01756     ClRefPrev(First) = Clause;
01757     ClRefFirstIndex(SOBrec) = (Cell) Clause;
01758   } else {  /* add at end */
01759     Last = (ClRef) ClRefLastIndex(SOBrec);
01760     append_to_chain(Arity, Last, Clause);
01761     ClRefPrev(Clause) = Last ;
01762     ClRefLastIndex(SOBrec) = (Cell) Clause;
01763   }
01764 }
01765 
01766 /* adds an indexed buffer to an index chain */
01767 static void db_addbuff_i(byte Arity, ClRef Clause, PrRef Pred, int AZ,
01768                          int *Index, int NI, prolog_term Head, int HashTabSize)
01769 { SOBRef SOBbuff ;
01770   int Inum, Ind;
01771   unsigned int ThisTabSize; int Hashval;
01772 
01773   SOBbuff = AZ == 0 ? Pred->FirstClRef : Pred->LastClRef ;
01774   HashTabSize = ThisTabSize = hash_resize(Pred, SOBbuff, HashTabSize);
01775   
01776   for (Inum = 1; Inum <= NI; Inum++) {
01777     SOBbuff = AZ == 0 ? Pred->FirstClRef : Pred->LastClRef ;
01778     Ind = Index[Inum];
01779     Hashval = hash_val(Ind, Head, ThisTabSize) ;
01780     if (Hashval < 0) {Hashval = 0; ThisTabSize = 1;}
01781     if (PredOpCode(Pred) == fail || ClRefType(SOBbuff) != SOB_RECORD
01782         || ClRefHashSize(SOBbuff) != ThisTabSize
01783         || ClRefSOBArg(SOBbuff,1) != (byte)(Ind>>16)  /* for byte-back */
01784         || ClRefSOBArg(SOBbuff,2) != (byte)(Ind>>8)
01785         || ClRefSOBArg(SOBbuff,3) != (byte)Ind) {
01786       SOBbuff = new_SOBblock(ThisTabSize,Ind,get_str_psc(Head));
01787       /* add new SOB block */
01788       db_addbuff(Arity,SOBbuff,Pred,AZ,TRUE,Inum);
01789     }
01790     Pred = ClRefPrRef(SOBbuff) ; /* fake a prref */
01791     addto_hashchain(AZ, Hashval, SOBbuff, ClRefIndPtr(Clause,Inum), Arity);
01792   }
01793   addto_allchain( AZ, Clause, SOBbuff, Arity ) ;
01794 }
01795 
01800 static void find_usable_index(prolog_term Head, ClRef *s,
01801                               int *ILevel, int *Index ) {
01802   int i,Ind = 0;
01803 
01804   *Index = *ILevel = 0 ;
01805   for (i = 1; ClRefType(*s) == SOB_RECORD; i++ ) {
01806     if (Head != (prolog_term)NULL) {
01807       Ind = ((ClRefSOBArg(*s,1) << 8) | ClRefSOBArg(*s,2) ) << 8 |
01808         ClRefSOBArg(*s,3) ;
01809       if (hash_val(Ind,Head,1) >= 0) { /* found one */
01810         *Index = Ind; *ILevel = i;
01811         break ;
01812       }
01813     }
01814     *s = (ClRef)ClRefFirstIndex(*s);
01815   }
01816   /* printf("fui: ILevel=%d, Index=%d\n",*ILevel,*Index); */
01817 }
01818 
01819 /* These following macros are used only in first_clref and next_clref
01820    and make some assumptions based on this use. */
01821 
01822 /* Check if a clause with head H is in the hash table of a SOB */
01823 /* The indexing Level is used to adjust the returned clause    */
01824 /* pointer to the beginning of the clause                      */
01825 
01826 #define CheckSOBClause(H, Ind, sob, Level )                     \
01827 {    int h, t ;                                                 \
01828      ClRef cl ;                                                 \
01829      t = ClRefHashSize(sob);                                    \
01830      h = hash_val( (Ind), (H), t ) ;                            \
01831      cl = (ClRef) ClRefHashTable(sob)[h] ;                      \
01832      if ((pb)cl != (pb)&dynfail_inst)                           \
01833         return IndPtrClRef(cl,Level) ;                          \
01834 }
01835 
01836 /* This macro finds the next SOB to search in the indexing tree */
01837 /* the ordering is down, left, (up+)left, the down and left     */
01838 /* parts being performed by the next macro.                     */
01839 /* It returns 0 if the root (prref) is ever reached.            */
01840 /* [Compiled clauses may be intermixed with dynamic ones, so    */
01841 /* that possibility must be checked.    -- no longer]           */
01842 
01843 #define NextSOB(sob,curLevel,IndLevel,Ind,Head)                 \
01844 {   while( ClRefTryOpCode(sob) == dyntrustmeelsefail            \
01845         || ClRefTryOpCode(sob) == noop ) /* end of sob chain */ \
01846         if( curLevel-- == 1 ) /* root of sob tree */            \
01847                 return 0 ;                                      \
01848         else sob = ClRefUpSOB(sob) ; /* go up */                \
01849     sob = ClRefNext(sob) ; /* follow sob chain */               \
01850     if (curLevel == 1) { /* may have changed indexes?!? */      \
01851         find_usable_index(Head,&sob,IndLevel,Ind);              \
01852         curLevel = *IndLevel;                                   \
01853         }                                                       \
01854     if( ClRefType(sob) != SOB_RECORD ) return sob;              \
01855 }
01856 
01857 /* sob points to first SOB of the index chain                   */
01858 /* look for Head/Ind in all SOB chains for this index level     */
01859 /* if needed go up to look in next sob chain(s)                 */
01860 
01861 #define FirstClauseSOB(sob,curLevel,IndLevel,Head,Ind)          \
01862 {   for(;;)                                                     \
01863         if( curLevel < *IndLevel ) /* sob node */               \
01864         {   sob = ClRefPrRef(sob)->FirstClRef; /* go down */    \
01865             curLevel++ ;                                        \
01866         }                                                       \
01867         else /* curLevel == *IndLevel -> sob leaf */            \
01868         {   CheckSOBClause(Head,*Ind,sob,curLevel) ;            \
01869             NextSOB(sob,curLevel,IndLevel,Ind,Head) ;           \
01870         }                                                       \
01871 }
01872 
01873 ClRef first_clref( PrRef Pred, prolog_term Head, int *ILevel, int *Index )
01874 {   SOBRef sob ;        /* working SOB */
01875     int curLevel ;  /* index depth */
01876 
01877     if( PredOpCode(Pred) == fail )
01878         return 0 ;
01879 
01880     /* first findout what index shall we use */
01881     sob = Pred->FirstClRef;
01882     find_usable_index(Head,&sob,ILevel,Index);
01883 
01884     if( *ILevel == 0 )  /* It's not indexable, so s points to first clause */
01885         return sob ;    /* in all chain of first SOB at lowest level */
01886     else
01887     {   curLevel = *ILevel ;
01888         FirstClauseSOB(sob,curLevel,ILevel,Head,Index) ;
01889     }
01890 }
01891 
01892 ClRef next_clref( PrRef Pred, ClRef Clause, prolog_term Head,
01893                          int *IndexLevel, int *Ind )
01894 {   SOBRef sob ;        /* working SOB */
01895     int numInds ;       /* number of indexes */
01896     int curLevel ;      /* how deep is sob in the indexing trees (0->Prref/numInds->leaf) */
01897     CPtr PI ;   /* working index pointer */
01898 
01899     if( ClRefType(Clause) != INDEXED_CL ) {     /* mixed clause types */
01900         if( ClRefTryOpCode(Clause) == dyntrustmeelsefail
01901             || ClRefTryOpCode(Clause) == dynnoop 
01902             || ClRefTryOpCode(Clause) == noop)
01903           return 0 ;
01904         else if( ClRefType(ClRefNext(Clause)) != SOB_RECORD )
01905           return ClRefNext(Clause) ;
01906         else /* should do as in cl_ref_first -- to index */
01907         {   sob = ClRefNext(Clause) ; 
01908             if( *IndexLevel == 0 ) /* goto first cl in all chain */
01909             {   while( ClRefType(sob) == SOB_RECORD )
01910                     sob = ClRefPrRef(sob)->FirstClRef ;
01911                 return sob ;
01912             }
01913             else
01914             {   for( curLevel = 1 ; curLevel < *IndexLevel ; curLevel++ )
01915                     sob = ClRefPrRef(sob)->FirstClRef ; /* all the way down */
01916                 CheckSOBClause(Head,*Ind,sob,*IndexLevel) ;
01917                 NextSOB(sob,curLevel,IndexLevel,Ind,Head) ;
01918                 FirstClauseSOB(sob,curLevel,IndexLevel,Head,Ind) ;
01919             }
01920         }
01921     }
01922     else if( *IndexLevel == 0 ) { /* look in all chain */
01923         if( ClRefTryOpCode(Clause) == dyntrymeelse || /* mid chain */
01924             ClRefTryOpCode(Clause) == dynretrymeelse ) 
01925             return ClRefNext(Clause) ;
01926         else /* INDEXED_CL, look on next SOB */
01927           {   numInds = curLevel = ClRefNumInds(Clause);
01928                                       /* all chain is on lowest index chain */
01929             sob = ClRefNext(Clause);    /* sob = current SOB */
01930             NextSOB(sob,curLevel,IndexLevel,Ind,Head);
01931             /* all leaf SOBs have non empty all chains */
01932             while( curLevel++ < numInds ) {
01933               sob = ClRefPrRef(sob)->FirstClRef ;
01934             }
01935             return ClRefPrRef(sob)->FirstClRef ;
01936         }
01937     }
01938     else        /* look in appropriate hash chain */
01939     {   PI = ClRefIndPtr(Clause,*IndexLevel) ;
01940         if( cell_opcode(PI) == dyntrymeelse || /* mid chain */
01941             cell_opcode(PI) == dynretrymeelse ) 
01942             return IndPtrClRef(IndRefNext(PI),*IndexLevel) ;
01943         else /* end of chain */
01944           {
01945             sob = (SOBRef)IndRefNext(PI) ; /* sob = current SOB */
01946             curLevel = *IndexLevel ;
01947             NextSOB(sob,curLevel,IndexLevel,Ind,Head) ;
01948             FirstClauseSOB(sob,curLevel,IndexLevel,Head,Ind) ;
01949         }
01950     }
01951 }
01952 /* Generic macro that deletes an element from a chain           *
01953  * Made possible because of the design of all chains containing *
01954  * the three words:                                             *
01955  *              (-1)Prev - (0)TryInstr - (1)Next                *
01956  * Index Rec Macros are used, although any kind of chain can be *
01957  * handled                                                      *
01958  * Args are PC    - pointer to Chain element                    *
01959  *          Displ - value to use as noop arg for begging of BC  *
01960  * return position of element just deleted                      */
01961 
01962 #define delete_from_chain( c, PC, Displ )                               \
01963 {   switch( c )                                                         \
01964     {   case noop: /* uniq */                                           \
01965         case dynnoop: /* uniq */                                        \
01966             break ;                                                     \
01967         case trymeelse: /* first */                                     \
01968             IndRefPrev(IndRefNext(PC)) = IndRefPrev(PC) ;               \
01969             if( cell_opcode(IndRefNext(PC)) == dynretrymeelse )            \
01970                 cell_opcode(IndRefNext(PC)) = trymeelse ;               \
01971             else /* trustme */                                          \
01972             {   cell_opcode(IndRefNext(PC)) = noop ;                    \
01973                 cell_operand3(IndRefNext(PC)) = (Displ) ;               \
01974             }                                                           \
01975             break ;                                                     \
01976         case dyntrymeelse: /* first */                                  \
01977             IndRefPrev(IndRefNext(PC)) = IndRefPrev(PC) ;               \
01978             if( cell_opcode(IndRefNext(PC)) == dynretrymeelse )            \
01979                 cell_opcode(IndRefNext(PC)) = dyntrymeelse ;            \
01980             else /* dyntrustme */                                       \
01981             {   cell_opcode(IndRefNext(PC)) = dynnoop ;                 \
01982                 cell_operand3(IndRefNext(PC)) = (Displ) ;               \
01983             }                                                           \
01984             break ;                                                     \
01985         case dynretrymeelse: /* mid */                                     \
01986             IndRefPrev(IndRefNext(PC)) = IndRefPrev(PC) ;               \
01987             IndRefNext(IndRefPrev(PC)) = IndRefNext(PC) ;               \
01988             break ;                                                     \
01989         case dyntrustmeelsefail: /* last */                             \
01990             IndRefNext(IndRefPrev(PC)) = IndRefNext(PC) ;               \
01991             if( cell_opcode(IndRefPrev(PC)) == dynretrymeelse )            \
01992                 cell_opcode(IndRefPrev(PC)) = dyntrustmeelsefail ;      \
01993             else if (cell_opcode(IndRefPrev(PC)) == trymeelse )         \
01994             {   cell_opcode(IndRefPrev(PC)) = noop ;                    \
01995                 cell_operand3(IndRefPrev(PC)) = (Displ) ;               \
01996             }                                                           \
01997             else /* dyntrymeelse */                                     \
01998             {   cell_opcode(IndRefPrev(PC)) = dynnoop ;                 \
01999                 cell_operand3(IndRefPrev(PC)) = (Displ) ;               \
02000             }                                                           \
02001             break ;                                                     \
02002         default:                                                        \
02003             xsb_exit("error removing a clause: %x",c) ;                 \
02004             break ;                                                     \
02005     }                                                                   \
02006 }
02007 
02008 /* delete from a hash chain */
02009 
02010 static void delete_from_hashchain( ClRef Clause, int Ind, int NI )
02011 {  
02012     CPtr PI = ClRefIndPtr(Clause,Ind) ;
02013     byte c = cell_opcode(PI) ;
02014 
02015     delete_from_chain(c,PI,((NI-Ind)*4+1)*sizeof(Cell)/2) ;
02016 
02017     if( cell_opcode(PI) == dynnoop) {
02018       *IndRefPrev(PI) = (Cell) &dynfail_inst ;
02019     }
02022     else if( cell_opcode(PI) == dyntrymeelse )
02023         *IndRefPrev(PI) = (Cell) IndRefNext(PI) ;
02024 }
02025 
02026 /* delete from the chain pointed by a prref - a all chain or a sob chain */
02027 
02028 static void delete_from_allchain( ClRef Clause )
02029 {  
02030     PrRef Pred ;
02031     byte c = ClRefTryOpCode(Clause) ;
02032 
02033     delete_from_chain( c, (CPtr)Clause, sizeof(Cell)/2 ) ;
02034 
02035     switch( c )
02036     {   case dynnoop:
02037             Pred = ClRefPrRef(ClRefPrev(Clause)) ;
02038             PredOpCode(Pred) = fail ;
02039             Pred->FirstClRef = Pred->LastClRef = (ClRef) Pred ;
02040             break ;
02041         case dyntrymeelse:
02042         case trymeelse:
02043             Pred = ClRefPrRef(ClRefPrev(Clause)) ;
02044             Pred->FirstClRef = ClRefNext(Clause) ;
02045             break ;
02046         case dyntrustmeelsefail:
02047             Pred = ClRefPrRef(ClRefNext(Clause)) ;
02048             Pred->LastClRef = ClRefPrev(Clause) ;
02049             break ;
02050      }
02051 }
02052 
02053 /* Delete the clref from the chain itself, then adjust the first and
02054    last pointers from the PrRef -- note that retrys need no PrRef
02055    adjustment. */
02056 
02057 static void delete_from_sobchain(ClRef Clause)
02058 {  
02059     PrRef Pred ;
02060     byte c = ClRefTryOpCode(Clause) ;
02061 
02062     delete_from_chain( c, (CPtr)Clause, sizeof(Cell)/2 ) ;
02063 
02064     switch( c )
02065     {   case dynnoop:
02066             Pred = (PrRef)ClRefPrev(Clause) ;
02067             PredOpCode(Pred) = fail ;
02068             Pred->FirstClRef = Pred->LastClRef = (ClRef) Pred ;
02069             break ;
02070         case noop:
02071             Pred = (PrRef)ClRefPrev(Clause) ;
02072             PredOpCode(Pred) = fail ;
02073             Pred->FirstClRef = Pred->LastClRef = (ClRef) Pred ;
02074             break ;
02075         case dyntrymeelse:
02076         case trymeelse:
02077             Pred = (PrRef)ClRefPrev(Clause) ;
02078             Pred->FirstClRef = ClRefNext(Clause) ;
02079             break ;
02080         case dyntrustmeelsefail:
02081             Pred = (PrRef)ClRefNext(Clause) ;
02082             Pred->LastClRef = ClRefPrev(Clause) ;
02083             break ;
02084      }
02085 }
02086 
02087 /********************************************************************
02088 Predicates for Clause Garbage Collecting and Safe Space Reclamation
02089 ********************************************************************/
02090 
02091 /***********************************************************************
02092 
02093    MARKING CP STACKS FOR RETRACT/RETRACTALL
02094 
02095    Retract must mark ClRefs (using a high bit on the size field),
02096    rather than check for an exact match between CPs and the clause.
02097    This is because removing a clause from a chain may change the
02098    instruction of the Clref immediately preceding or succeeding it --
02099    this change may not be possible if there is a choice point pointing
02100    to that next instruction.
02101 
02102    For instance, suppose an indexing chain has try -- retry -- trust
02103    with a CP C pointing to the retry, and that the "try" clause is
02104    retracted.  If space reclamation is done immediately, the retry
02105    will be changed to a try.  Later, when C is executed on failure, a
02106    second CP for the same goal will be put onto the CP stack ---
02107    leading to an infinite loop that takes a little time to figure out
02108    (believe me :-)
02109 
02110    My solution is to mark the clauses which allows a later check of
02111    immediate predecessors and successors, by
02112    determine_if_safe_to_delete(). Space is reclaimed immediately only
02113    if situations like the above do not occur.
02114 
02115 ************************************************************************/
02116 
02117 /* dynamic clauses now have special try/retry/trust instructions */
02118 #define is_dynamic_clause_inst(inst)                                    \
02119   ((int) inst == dynretrymeelse ||   (int) inst == dyntrustmeelsefail)  
02120 
02121 /* TLS: due to weirdness of ClRefs, a ClRef pointer points to the END
02122    of the ClRef.  To access its components you must decrement the
02123    ClRef pointer.  At some point I'd like to change this, but this
02124    would be a rather delicate operation. */
02125 
02126 #define mark_clref(pClRef)  \
02127   (ClRef_Buflen(pClRef -1) = ClRef_Buflen(pClRef - 1) | HIGHBIT)
02128 
02129 #define unmark_clref(pClRef)  \
02130   (ClRef_Buflen(pClRef -1) = ClRef_Buflen(pClRef - 1 ) & (~HIGHBIT))
02131 
02132 #define clref_is_marked(pClRef)  \
02133   (ClRef_Buflen(pClRef -1 ) & HIGHBIT)
02134 
02135 /* I think this is going back in the CLref through various
02136    indexing chains to find the "base" of the Clref.*/
02137 ClRef clref_from_try_addr(ClRef code_addr) {
02138   while (cell_opcode((CPtr)code_addr - 2) == noop) {
02139     code_addr = (ClRef)((CPtr)code_addr - 4);
02140   }
02141   return (ClRef)code_addr;
02142 }
02143 
02144 /* cf. mark_cpstack_retracall(), etc.  Traverses choice point stack to
02145    mark any CLREFS that it sees.  If it finds something that is
02146    difficult to reason about, (i.e. a ;/2 within a dynamic clause or a
02147    get_db_clause pointer, it breaks out of the loop, returning a flag
02148    that will prevent the retract from immediately reclaiming space */
02149 
02150 int mark_cpstack_retract(CTXTdeclc ClRef clref) {
02151   CPtr cp_top,cp_bot, cp_inst_addr ;
02152   byte cp_inst;
02153   int found_match;
02154   ClRef cp_clref;
02155 
02156   cp_bot = (CPtr)(tcpstack.high) - CP_SIZE;
02157 
02158   cp_top = ((bfreg < breg)? bfreg : breg) ;             
02159   found_match = 0;
02160   while ( cp_top < cp_bot && !(found_match)) {
02161     cp_inst = *(byte *)*cp_top;
02162     if ( is_dynamic_clause_inst(cp_inst) ) {
02163       cp_clref = clref_from_try_addr((ClRef)*cp_top);
02164       if (clref == cp_clref) {
02165         //      fprintf(stderr,"found exact match\n");
02166         found_match = 1;
02167       } 
02168       else {
02169         mark_clref(cp_clref);
02170       }
02171     }
02172     else {
02173       cp_inst_addr = (CPtr) *cp_top;
02174       if (cp_inst_addr == dbclause_cgc_block_gl
02175           || (cp_inst_addr > standard_cgc_block_begin_gl 
02176               && cp_inst_addr < standard_cgc_block_end_gl)) {
02177         //      fprintf(stderr,"found dangling dbclause/; ptr in mc_retract\n");
02178         found_match = 1;
02179       }
02180     }
02181     cp_top = cp_prevtop(cp_top);
02182   }
02183   return found_match;
02184 }
02185 
02186 /* * * * * * * * * */
02187 
02188 void unmark_cpstack_retract(CTXTdecl) {
02189   CPtr cp_top,cp_bot ;
02190   byte cp_inst;
02191   ClRef cp_clref;
02192 
02193   cp_bot = (CPtr)(tcpstack.high) - CP_SIZE;
02194 
02195   cp_top = ((bfreg < breg)? bfreg : breg) ;             
02196   while ( cp_top < cp_bot ) {
02197     cp_inst = *(byte *)*cp_top;
02198     if ( is_dynamic_clause_inst(cp_inst) ) {
02199       cp_clref = clref_from_try_addr((ClRef)*cp_top);
02200       unmark_clref(cp_clref);
02201     }
02202     cp_top = cp_prevtop(cp_top);
02203   }
02204 }
02205 
02206 /* * * * * * * * * */
02207 
02208 /* Used for non-open ClRef-based retractalls.  Traverses choice point
02209  stack to mark any Clrefs that it sees.  If it finds something that is
02210  difficult to reason about, (i.e. a ';' choice point within a dynamic
02211  clause or a get_db_clause pointer, it breaks out of the loop,
02212  returning a flag that will prevent the retractall from immediately
02213  reclaiming space for any of the retracted clauses.  */
02214 
02215 int mark_cpstack_retractall(CTXTdecl) {
02216   CPtr cp_top,cp_bot,cp_inst_addr ;
02217   byte cp_inst;
02218   ClRef cp_clref;
02219   int found_match = 0;
02220 
02221   cp_bot = (CPtr)(tcpstack.high) - CP_SIZE;
02222 
02223   cp_top = ((bfreg < breg)? bfreg : breg) ;             
02224   while ( cp_top < cp_bot && !found_match) {
02225     cp_inst = *(byte *)*cp_top;
02226     if ( is_dynamic_clause_inst(cp_inst) ) {
02227       cp_clref = clref_from_try_addr((ClRef)*cp_top);
02228       mark_clref(cp_clref);
02229     }
02230     else {
02231       cp_inst_addr = (CPtr) *cp_top;
02232       if (cp_inst_addr == dbclause_cgc_block_gl
02233           || (cp_inst_addr > standard_cgc_block_begin_gl 
02234               && cp_inst_addr < standard_cgc_block_end_gl)) {
02235         //      fprintf(stderr,"found dangling dbclause/; ptr in CLREF retra\n");
02236         found_match = 1;
02237       }
02238     }
02239     cp_top = cp_prevtop(cp_top);
02240   }
02241   return found_match;
02242 }
02243 
02244 /* * * * * * * * * */
02245 
02246 static inline int dyntabled_incomplete(CTXTdeclc Psc psc) {
02247   if (get_tabled(psc) && !is_completed_table(get_tip(CTXTc psc)))
02248     return TRUE;
02249   else return FALSE;
02250   }
02251 
02252 /* * * * * * * * * */
02253 
02254 /*
02255    check_cpstack_retractall() is used for abolishing a predicate, and for
02256    PrRef-based retractall.  In these cases, we can simply check
02257    whether a clause for the predicate is on the CP stack. This differs
02258    from retract, where an explicit marking phase is needed.
02259 */
02260 
02261 int check_cpstack_retractall(CTXTdeclc PrRef prref) { 
02262 
02263   CPtr cp_top,cp_bot, cp_inst_addr; 
02264   byte cp_inst; 
02265   int found_prref_match; 
02266   ClRef clref_ptr;
02267 
02268   cp_bot = (CPtr)(tcpstack.high) - CP_SIZE;
02269 
02270   cp_top = ((bfreg < breg)? bfreg : breg) ;             
02271   found_prref_match = 0;
02272   while ( cp_top < cp_bot && !(found_prref_match)) {
02273     cp_inst = *(byte *)*cp_top;
02274     // dynamic clauses now have special try/retry/trust instructions
02275     if ( is_dynamic_clause_inst(cp_inst) ) {
02276       clref_ptr = clref_from_try_addr((ClRef)*cp_top);
02277       if (prref == clref_to_prref(clref_ptr)) {
02278         found_prref_match = 1;
02279       }
02280     }
02281     else {
02282       cp_inst_addr = (CPtr) *cp_top;
02283       if (cp_inst_addr == dbclause_cgc_block_gl
02284           || (cp_inst_addr > standard_cgc_block_begin_gl 
02285               && cp_inst_addr < standard_cgc_block_end_gl)) {
02286         //      fprintf(stderr,"found dangling dbclause/; ptr in gen retra\n");
02287         found_prref_match = 1;
02288       }
02289     }
02290     cp_top = cp_prevtop(cp_top);
02291   }
02292   return found_prref_match;
02293 }
02294 
02295 /* * * * * * * * * */
02296 
02297 /* 
02298    DelCF chains point to clrefs or prrefs that have been retracted or
02299    abolished, but whose space has not been reclaimed.  Each thread can
02300    access two such chains -- one for shared predicates and one for
02301    private predicates.  DelCF frames are linked together by two
02302    doubly-linked list, one for all DelCF frames, and one for frames
02303    for a given predicate.  The PrRef for a predicate P points to the
02304    first DelCF frame for P.
02305 
02306    For a predicate P, DelCFs for clrefs are added before DelCFs for
02307    prrefs -- this way clrefs are removed before prrefs during GC,
02308    which is safer.  
02309  */
02310 
02311 /* used by mt engine for shared tables */
02312 DelCFptr delcf_chain_begin = (DelCFptr) NULL;
02313 
02314 /* Asserting _pred structures to end of pred chain.  This means that
02315    if lastdcf is not null, just stick it on the end; otherwise adjust
02316    Prref's delcf pointer. */
02317 DelCFptr new_DelCF_pred(CTXTdeclc PrRef pPrRef,Psc pPSC,
02318                                 DelCFptr *chain_begin) {
02319   DelCFptr pDCF; 
02320 
02321   pDCF = (DelCFptr)mem_alloc(sizeof(DeletedClauseFrame),ASSERT_SPACE); 
02322     if ( IsNULL(pDCF) )                                                 
02323       xsb_abort("Ran out of memory in allocation of DeletedClauseFrame"); 
02324     DCF_PrRef(pDCF) = pPrRef;                   
02325     DCF_ClRef(pDCF) = PrRef_FirstClRef(pPrRef);  // diff from _clause create
02326     DCF_PSC(pDCF) = pPSC;
02327     DCF_Type(pDCF) = DELETED_PRREF;
02328     DCF_Mark(pDCF) = 0;
02329     DCF_PrevDCF(pDCF) = 0;                                              
02330     DCF_PrevPredDCF(pDCF) = 0;                                          
02331     DCF_NextDCF(pDCF) = *chain_begin;
02332     DCF_NextPredDCF(pDCF) = PrRef_DelCF(pPrRef);  
02333     if (*chain_begin) DCF_PrevDCF(*chain_begin) = pDCF; 
02334     if (PrRef_DelCF(pPrRef))  DCF_PrevPredDCF(PrRef_DelCF(pPrRef)) = pDCF; 
02335     *chain_begin = pDCF;                                                
02336     PrRef_DelCF(pPrRef) = pDCF;
02337     return pDCF;
02338 }
02339 
02340 /* * * * * * * * * */
02341 
02342 /* Asserting _clause structures to START of pred chain -- this means
02343    that they will be abolished before any pred-level retractalls for
02344    the same predicate. */
02345 DelCFptr new_DelCF_clause(PrRef pPrRef,Psc pPSC,ClRef pClRef,
02346                                  DelCFptr *chain_begin) {
02347   DelCFptr pDCF; 
02348 
02349   pDCF = (DelCFptr)mem_alloc(sizeof(DeletedClauseFrame),ASSERT_SPACE); 
02350     if ( IsNULL(pDCF) )                                                 
02351       xsb_abort("Ran out of memory in allocation of DeletedClauseFrame"); 
02352     DCF_PrRef(pDCF) = pPrRef;                   
02353     DCF_ClRef(pDCF) = pClRef;     // diff from _pred create
02354     DCF_PSC(pDCF) = pPSC;                                               
02355     DCF_Type(pDCF) = DELETED_CLREF;
02356     DCF_Mark(pDCF) = 0;                                                 
02357     DCF_PrevDCF(pDCF) = 0;                                              
02358     DCF_PrevPredDCF(pDCF) = 0;                                          
02359     DCF_NextDCF(pDCF) = *chain_begin;                           
02360     DCF_NextPredDCF(pDCF) = PrRef_DelCF(pPrRef);  
02361     if (*chain_begin) DCF_PrevDCF(*chain_begin) = pDCF; 
02362     if (PrRef_DelCF(pPrRef))  DCF_PrevPredDCF(PrRef_DelCF(pPrRef)) = pDCF; 
02363     *chain_begin = pDCF;                                                
02364     PrRef_DelCF(pPrRef) = pDCF;
02365     return pDCF;
02366 }
02367 
02368 /* * * * * * * * * */
02369 
02370 /* No mutexes, because it is called only during gc, w. only 1 active
02371  * thread. Note that prref might be NULL if we have abolished the
02372  * predicate. */
02373 
02374 #define Free_DelCF(pDCF,pPRREF,chain_begin) {                           \
02375   if (DCF_PrevDCF(pDCF) == 0) {                                         \
02376     chain_begin = DCF_NextDCF(pDCF);                                    \
02377   }                                                                     \
02378   else {                                                                \
02379     DCF_NextDCF(DCF_PrevDCF(pDCF)) = DCF_NextDCF(pDCF);                 \
02380   }                                                                     \
02381   if (DCF_NextDCF(pDCF) != 0) {                                         \
02382     DCF_PrevDCF(DCF_NextDCF(pDCF)) = DCF_PrevDCF(pDCF);                 \
02383   }                                                                     \
02384   if (DCF_PrevPredDCF(pDCF) == 0 && pPRREF) {                           \
02385     PrRef_DelCF(pPRREF) = DCF_NextPredDCF(pDCF);                        \
02386   }                                                                     \
02387   else {                                                                \
02388     DCF_NextPredDCF(DCF_PrevPredDCF(pDCF)) = DCF_NextPredDCF(pDCF);     \
02389   }                                                                     \
02390   if (DCF_NextPredDCF(pDCF) != 0) {                                     \
02391     DCF_PrevPredDCF(DCF_NextPredDCF(pDCF)) = DCF_PrevPredDCF(pDCF);     \
02392   }                                                                     \
02393   mem_dealloc(pDCF,sizeof(DeletedTableFrame),ASSERT_SPACE);             \
02394 }
02395 
02396 /* * * * * * * * * */
02397 
02398 /* 
02399    Assumes check has been made that the prref itself has at least one
02400    clause to retract -- this prevents a retractall of an empty predicate
02401    from adding a delcf frame.
02402 
02403    Any clref structures present in the pred chain will be deleted by
02404    the retractall anyway, so they can be removed.
02405 
02406    Inserting delcf_preds at end of pred_chain.  
02407 */
02408 
02409 void check_insert_global_delcf_pred(CTXTdeclc PrRef prref,Psc psc) { 
02410   DelCFptr dcf = PrRef_DelCF(prref);
02411 
02412   SYS_MUTEX_LOCK(MUTEX_DYNAMIC);
02413   while ( dcf != 0 ) {
02414     if (DCF_Type(dcf) == DELETED_CLREF) {
02415       //      fprintf(stderr,"Prref over-riding clref for %s/%d\n",
02416       //              get_name(psc),get_arity(psc));
02417       Free_DelCF(dcf,prref,delcf_chain_begin);
02418     }
02419     dcf = DCF_NextPredDCF(dcf);
02420   }
02421   dcf = new_DelCF_pred(CTXTc prref,psc,&delcf_chain_begin);
02422   SYS_MUTEX_UNLOCK(MUTEX_DYNAMIC);
02423 }
02424 
02425 #ifdef MULTI_THREAD
02426 void check_insert_private_delcf_pred(CTXTdeclc PrRef prref,Psc psc) { 
02427   DelCFptr dcf = PrRef_DelCF(prref);
02428 
02429   while ( dcf != 0 ) {
02430     if (DCF_Type(dcf) == DELETED_CLREF) {
02431       //      fprintf(stderr,"Prref over-riding clref for %s/%d\n",
02432       //              get_name(psc),get_arity(psc));
02433       Free_DelCF(dcf,prref,private_delcf_chain_begin);
02434     }
02435     dcf = DCF_NextPredDCF(dcf);
02436   }
02437   dcf = new_DelCF_pred(CTXTc prref,psc,&private_delcf_chain_begin);
02438 }
02439 #endif
02440 
02441 /* Currently am not comparing deleted clauses to deleted predicates.
02442    Just delete the clauses, then do the retractalls.*/
02443 
02444 void check_insert_global_delcf_clause(CTXTdeclc PrRef prref,
02445                                       Psc psc,ClRef clref) { 
02446   DelCFptr dcf = PrRef_DelCF(prref);
02447   int found = 0;
02448 
02449   SYS_MUTEX_LOCK(MUTEX_DYNAMIC);
02450   //  while ( dcf != 0 ) {
02451   //    if (DCF_Type(dcf) == DELETED_CLREF && DCF_ClRef(dcf) == clref) {
02452       //      fprintf(stderr,"Found clref for %s/%d\n",
02453       //      get_name(psc),get_arity(psc));
02454   //      found = 1;
02455   //    }
02456   //    dcf = DCF_NextPredDCF(dcf);
02457   //  }
02458   if (!found) {
02459     dcf = new_DelCF_clause(prref,psc,clref,&delcf_chain_begin);
02460   }
02461   SYS_MUTEX_UNLOCK(MUTEX_DYNAMIC);
02462 }
02463 
02464 #ifdef MULTI_THREAD
02465 void check_insert_private_delcf_clause(CTXTdeclc PrRef prref,
02466                                       Psc psc,ClRef clref) { 
02467   DelCFptr dcf = PrRef_DelCF(prref);
02468   int found = 0;
02469 
02470   //  while ( dcf != 0 ) {
02471   //    if (DCF_Type(dcf) == DELETED_CLREF && DCF_ClRef(dcf) == clref) {
02472       //      fprintf(stderr,"Found clref for %s/%d\n",
02473       //      get_name(psc),get_arity(psc));
02474   //      found = 1;
02475   //    }
02476   //    dcf = DCF_NextPredDCF(dcf);
02477   //  }
02478   if (!found) {
02479     dcf = new_DelCF_clause(prref,psc,clref,&private_delcf_chain_begin);
02480   }
02481 }
02482 
02483 #define check_insert_shared_delcf_pred(context,prref,psc)       \
02484   check_insert_global_delcf_pred(context,prref,psc)      
02485 
02486 #define check_insert_shared_delcf_clause(context,prref,psc,clref)       \
02487   check_insert_global_delcf_clause(context,prref,psc,clref)      
02488 
02489 #define check_insert_private_delcf_pred(context,prref,psc)      \
02490   check_insert_private_delcf_pred(context,prref,psc)     
02491 
02492 #define check_insert_private_delcf_clause(context,prref,psc,clref)      \
02493   check_insert_global_delcf_clause(context,prref,psc,clref)      
02494 
02495 #else 
02496 #define check_insert_private_delcf_pred(prref,psc)      \
02497   check_insert_global_delcf_pred(prref,psc)      
02498 
02499 #define check_insert_private_delcf_clause(prref,psc,clref)      \
02500   check_insert_global_delcf_clause(prref,psc,clref)      
02501 #endif
02502 
02503 /* * * * * * * * * * * */
02504 
02505 /* Marking DelCFs
02506 
02507    During the GC phase, a DelCF frame is marked if a traversal of the
02508    choice point stack indicates that it may be unsafe to reclaim space
02509    for the clrefs/prref it represents.
02510 
02511    If a DelCF represents a deleted prref, reclamation is complicated
02512    by the fact that clauses can be repeatedly asserted for a predicate
02513    and retractalled.  If GC cannot occur right away, this leads to
02514    "generations" of DelCFs.  Probably the best solution for this is to
02515    put ISO-style timestamps in clrefs and prrefs: until then, however,
02516    I'm marking all prrefs for a predicate P if any clause for P is in
02517    the CP stack -- regardless of its "generation".
02518 
02519    In addition, if a dynamic predicate is tabled and has incomplete
02520    tables, the Delcf is marked.  I'm not sure if this can occur(?)
02521 */
02522 
02523 void mark_delcf_subchain(CTXTdeclc DelCFptr delcf,ClRef clref) {
02524   PrRef prref;
02525 
02526   prref = clref_to_prref(clref);
02527   while (delcf) {
02528     if (dyntabled_incomplete(CTXTc DCF_PSC(delcf))) {
02529       DCF_Mark(delcf) = 1;
02530       //      fprintf(stderr,"Marking DelCF for incomplete table: %s/%d\n",
02531       //      get_name(DCF_PSC(delcf)),get_arity(DCF_PSC(delcf)));
02532     }
02533     if (DCF_Type(delcf) == DELETED_PRREF && prref == DCF_PrRef(delcf) ) {
02534       DCF_Mark(delcf) = 1;
02535       //      fprintf(stderr,"Marking Pred DelCF for %s/%d\n",
02536       //      get_name(DCF_PSC(delcf)),get_arity(DCF_PSC(delcf)));
02537     } else if (DCF_Type(delcf) == DELETED_CLREF && DCF_ClRef(delcf) == clref) {
02538       DCF_Mark(delcf) = 1;
02539       //      fprintf(stderr,"Marking Clause DelCF for %s/%d\n",
02540       //      get_name(DCF_PSC(delcf)),get_arity(DCF_PSC(delcf)) );
02541     } 
02542     delcf = DCF_NextPredDCF(delcf);
02543   }
02544 }
02545 
02546 /* 
02547    This function, called by gc_dynamic traverses the CP stack to mark
02548    both DelCFs and ClRefs that cannot be GC'd.  
02549 
02550    DelCFs are marked in mark_delcf_subchain() and are obtained by the
02551    DelCF pointer off of the PrRef.  ClRefs must also be marked
02552    directly.  This is done so that determine_if_safe_to_delete() can
02553    operate properly (see other comments for this predicate).  See
02554    comments for mark_cpstack_retract()).
02555  */
02556 
02557 int mark_dynamic(CTXTdecl) 
02558 {
02559   CPtr cp_top,cp_bot, cp_inst_addr ;
02560   byte cp_inst;
02561   ClRef clref_ptr;
02562   PrRef prref_ptr;
02563   int found_match = 0;
02564 
02565   cp_bot = (CPtr)(tcpstack.high) - CP_SIZE;
02566   cp_top = ((bfreg < breg)? bfreg : breg) ;             
02567 
02568   while ( cp_top < cp_bot && !found_match) {
02569     cp_inst = *(byte *)*cp_top;
02570     if ( is_dynamic_clause_inst(cp_inst) ) {
02571       clref_ptr = clref_from_try_addr((ClRef)*cp_top);
02572       mark_clref(clref_ptr);
02573       prref_ptr = clref_to_prref(clref_ptr);
02574       mark_delcf_subchain(CTXTc PrRef_DelCF(prref_ptr),clref_ptr);
02575     }
02576     else {
02577       cp_inst_addr = (CPtr) *cp_top;
02578       if (cp_inst_addr == dbclause_cgc_block_gl
02579           || (cp_inst_addr > standard_cgc_block_begin_gl 
02580               && cp_inst_addr < standard_cgc_block_end_gl)) {
02581         //      fprintf(stderr,"found dangling dbclause/; ptr in gc\n");
02582         found_match = 1;
02583       }
02584     }
02585     cp_top = cp_prevtop(cp_top);
02586   }
02587   return found_match;
02588 }
02589 
02590 void gc_retractall(CTXTdeclc ClRef);
02591 int determine_if_safe_to_delete(ClRef);
02592 static int really_delete_clause(ClRef);
02593 
02594 /* Upon freeing, the Pred-delcf pointer for the current prref may need
02595    to be set.  To do this, need to find the current prref (via
02596    dynpredep_to_prref()) not a possibly old one pointed to by the
02597    delcf frame.
02598 */
02599 
02600 int sweep_dynamic(CTXTdeclc DelCFptr *chain_begin) { 
02601   DelCFptr next_delcf_ptr, delcf_ptr = *chain_begin; 
02602   int dcf_cnt = 0;
02603   PrRef prref;
02604 
02605   /* Free global deltcs */
02606   while (delcf_ptr) {
02607     next_delcf_ptr = DCF_NextDCF(delcf_ptr);
02608     if (DCF_Mark(delcf_ptr)) {
02609       //      fprintf(stderr,"GC Sweep skipping marked %s/%d\n",
02610       //              get_name(DCF_PSC(delcf_ptr)),get_arity(DCF_PSC(delcf_ptr)));
02611       DCF_Mark(delcf_ptr) = 0;
02612       dcf_cnt++;
02613     }
02614     else {
02615       if (DCF_Type(delcf_ptr) == DELETED_PRREF) {
02616         //      fprintf(stderr,"Garbage Collecting Predicate: %s/%d\n",
02617         //              get_name(DCF_PSC(delcf_ptr)),get_arity(DCF_PSC(delcf_ptr)));
02618         gc_retractall(CTXTc DCF_ClRef(delcf_ptr));
02619         prref = dynpredep_to_prref(CTXTc get_ep(DCF_PSC(delcf_ptr)));
02620         Free_DelCF(delcf_ptr,prref,*chain_begin);
02621       }
02622       else {
02623         if (DTF_Type(delcf_ptr) == DELETED_CLREF) {
02624           if (determine_if_safe_to_delete(DCF_ClRef(delcf_ptr))) {
02625             //      fprintf(stderr,"Garbage Collecting Clause: %s/%d (%p)\n",
02626             //              get_name(DCF_PSC(delcf_ptr)),get_arity(DCF_PSC(delcf_ptr)),
02627             //              DCF_ClRef(delcf_ptr));
02628             really_delete_clause(DCF_ClRef(delcf_ptr));
02629             prref = dynpredep_to_prref(CTXTc get_ep(DCF_PSC(delcf_ptr)));
02630             Free_DelCF(delcf_ptr,prref,*chain_begin);
02631           } else {
02632             dcf_cnt++;
02633             //      fprintf(stderr,"GC Sweep skipping unsafe: %s/%d\n",
02634             //              get_name(DCF_PSC(delcf_ptr)),get_arity(DCF_PSC(delcf_ptr)));
02635           }
02636         }
02637       }
02638     }
02639     delcf_ptr = next_delcf_ptr;
02640   }
02641   return dcf_cnt;
02642 }
02643 
02644 /* Returns -1 in situations it cant handle: currently, calling with
02645  * frozen stacks or multiple threads, or where there may be pointers
02646  * to dynamic code that are difficult to reason about.  Also returns
02647  * -1 if clause gc has been turned off.
02648  */
02649 
02650 int gc_dynamic(CTXTdecl) 
02651 {
02652   int ctr = -1;
02653 
02654   if (pflags[CLAUSE_GARBAGE_COLLECT] == 0) return -1;
02655 
02656 #ifdef MULTI_THREAD
02657   if (flags[NUM_THREADS] == 1 ) {
02658     if (!delcf_chain_begin && !private_delcf_chain_begin) return 0;
02659     if (!mark_dynamic(CTXT)) {
02660       ctr = sweep_dynamic(CTXTc &delcf_chain_begin) + 
02661         sweep_dynamic(CTXTc &private_delcf_chain_begin);
02662     }
02663     unmark_cpstack_retract(CTXT);
02664   } else {
02665     if (!private_delcf_chain_begin) return 0;
02666     if (!mark_dynamic(CTXT)) {
02667       ctr = sweep_dynamic(CTXTc &private_delcf_chain_begin);
02668     }
02669     unmark_cpstack_retract(CTXT);
02670   }
02671 #else 
02672     if (!delcf_chain_begin) return 0;
02673     if (!mark_dynamic(CTXT)) {
02674       ctr = sweep_dynamic(CTXTc &delcf_chain_begin);
02675     }
02676     unmark_cpstack_retract(CTXT);
02677 #endif
02678   return ctr;
02679 }
02680 
02681 #define FIXED_BLOCK_SIZE_FOR_TABLED_PRED     (8 * sizeof(Cell))
02682 
02683 /* TLS: did not put a MUTEX_DISPBLKHDR as the chain of dispblks
02684    themselves are not changed, only pointers to prrefs within the
02685    displblks. */
02686 #ifdef MULTI_THREAD
02687 
02688 static inline void thread_free_private_delcfs(CTXTdecl) {
02689 
02690   DelCFptr next_delcf;
02691   DelCFptr delcf = private_delcf_chain_begin;
02692 
02693   while (delcf) {
02694     next_delcf = DCF_NextDCF(delcf);
02695     mem_dealloc(delcf,sizeof(DeletedClauseFrame),ASSERT_SPACE);         
02696     delcf = next_delcf;
02697   }
02698 }
02699 
02700 /* free_private_prref() is the same as free_prref, except that it
02701    knows to free a private tif, rather than having to check via the
02702    psc record. */
02703 
02704 void free_private_prref(CTXTdeclc CPtr *p) {
02705 
02706     if ( *(pb)p == tabletrysingle )
02707       {
02708         TIFptr mtTIF = (TIFptr) *(p+2);
02709         Free_Private_TIF(mtTIF);
02710         /* free prref, from calld instr set in db_build_prref */
02711         mem_dealloc((pb)(*(p+6)), sizeof(PrRefData),ASSERT_SPACE);
02712         if (xsb_profiling_enabled)
02713           remove_prog_seg((pb)*(p+6));
02714         mem_dealloc((pb)p, FIXED_BLOCK_SIZE_FOR_TABLED_PRED,
02715                     ASSERT_SPACE) ; /*free table hdr*/
02716       }
02717     else {
02718       mem_dealloc((pb)p, sizeof(PrRefData),ASSERT_SPACE);  /* free prref */
02719       if (xsb_profiling_enabled)
02720         remove_prog_seg((pb)p);
02721     }
02722 }
02723 
02724 void retractall_prref(CTXTdeclc PrRef);
02725 
02726 void thread_free_dyn_blks(CTXTdecl) {
02727   struct DispBlk_t *dispblk;
02728   PrRef prref0, prref;
02729 
02730   //  printf("Enter thread_free_dyn_blks\n");
02731   SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
02732   for (dispblk=DispBlkHdr.firstDB ; dispblk != NULL ; dispblk=dispblk->NextDB) {
02733     if (th->tid <= dispblk->MaxThread) {
02734       prref0 = (PrRef)(&(dispblk->Thread0))[th->tid];
02735       if (prref0) {
02736         if (cell_opcode((CPtr *)prref0) == tabletrysingle) 
02737           prref = (PrRef)((CPtr *)prref0)[6];
02738         else prref = prref0;
02739         retractall_prref(CTXTc prref);
02740         free_private_prref(CTXTc (CPtr *)prref0);
02741         //      printf("set prref free for thread %d\n",th->tid);
02742         (&(dispblk->Thread0))[th->tid] = (CPtr) NULL;
02743       }
02744     }
02745   }
02746   SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
02747 }
02748 
02749 /* Called upon a thread's exit. */
02750 
02751 void release_private_dynamic_resources(CTXTdecl) {
02752   thread_free_private_delcfs(CTXT);
02753   thread_free_dyn_blks(CTXT);
02754 }
02755 
02756 #endif
02757 
02758 /********************************************************************/
02759 /* Insert in retract buffer and remove old clauses */
02760 
02761 static int really_delete_clause(ClRef Clause)
02762 {
02763   xsb_dbgmsg((LOG_RETRACT,
02764              "Really deleting clause(%p) op(%x) type(%d)",
02765              Clause, ClRefTryOpCode(Clause), ClRefType(Clause) )) ;
02766     switch( ClRefType(Clause) )
02767     {
02768         case UNINDEXED_CL:
02769           delete_from_sobchain(Clause) ;
02770           break ;
02771 
02772         case INDEXED_CL:
02773         {   int i, NI ;
02774             SOBRef sob ;
02775             CPtr IP ;
02776 
02777             NI = ClRefNumInds(Clause) ;
02778             xsb_dbgmsg((LOG_RETRACT,
02779                        "Really deleting clause (%p) size %d indexes %d",
02780                        Clause, ClRefSize(Clause), NI )) ;
02781             delete_from_allchain(Clause) ;
02782 
02783             /* remove it from index chains */
02784             for( i = NI; i >= 1; i-- ) {
02785               IP = ClRefIndPtr(Clause, i);
02786               if (cell_opcode(IP) == dynnoop) /* deleting last in bucket */
02787                 sob = (SOBRef)IndRefNext(IP); /* so get SOB addr */
02788               else sob = NULL;
02789 
02790               xsb_dbgmsg((LOG_RETRACT,
02791                           "SOB(%d) - hash size %d - %d clauses",
02792                           i, ClRefHashSize(sob), ClRefNumNonemptyBuckets(sob) ));
02793               xsb_dbgmsg((LOG_RETRACT,
02794                           "Addr %p : prev %p : next %p",
02795                           sob, ClRefNext(sob), ClRefPrev(sob) ));
02796               delete_from_hashchain(Clause,i,NI) ;
02797               if (sob && --ClRefNumNonemptyBuckets(sob) == 0) 
02798                 { /* if emptied bucket, decrement count; if all empty, reclaim SOB */
02799                     xsb_dbgmsg((LOG_RETRACT,"deleting sob - %p", sob ));
02800                     delete_from_sobchain(sob) ;
02801                     mem_dealloc((pb)ClRefAddr(sob), ClRefSize(sob),ASSERT_SPACE);
02802                 }
02803             }
02804             break ;
02805         }
02806         case SOB_RECORD:
02807         default :
02808           xsb_exit( "retract internal error!" ) ;
02809     }
02810     mem_dealloc((pb)ClRefAddr(Clause), ClRefSize(Clause),ASSERT_SPACE);
02811     if (xsb_profiling_enabled)
02812       remove_prog_seg((pb)Clause);
02813     return TRUE ;
02814 }
02815 
02816 /********************/
02817 
02818 int determine_if_safe_to_delete(ClRef Clause) {
02819   byte opcode;
02820   int NI, i;
02821   CPtr IP;
02822 
02823   if (clref_is_marked(Clause)) return FALSE;
02824 
02825   opcode = ClRefTryOpCode(Clause);
02826   if ((opcode == trymeelse || opcode == dyntrymeelse)
02827       && clref_is_marked(ClRefNext(Clause))) {
02828     return FALSE;
02829   }
02830 
02831   NI = ClRefNumInds(Clause) ;
02832 
02833   /* remove it from index chains */
02834   for( i = NI; i >= 1; i-- ) {
02835   
02836     IP = ClRefIndPtr(Clause, i);
02837     if (cell_opcode(IP) == trymeelse || cell_opcode(IP) == dyntrymeelse) {
02838       if (clref_is_marked((ClRef) (IndRefNext(IP) - (4 * i)))) {
02839         return FALSE;
02840       }
02841     }
02842   }
02843   return TRUE;
02844 }
02845           
02846 /* Mark a clause for deletion: don't do anything else.  This is done
02847    regardless of whether space is reclaimed or not.*/
02848 static void mark_for_deletion(CTXTdeclc ClRef Clause)
02849 {
02850   //  fprintf(stderr,"Mark for deletion: (%p) op(%x) type(%d)",
02851   // Clause, ClRefTryOpCode(Clause), ClRefType(Clause));
02852   SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
02853   switch( ClRefType(Clause) ) {
02854         case UNINDEXED_CL: {
02855           cell_opcode(ClRefEntryPoint(Clause)) = fail ;
02856           cell_operand1(ClRefEntryPoint(Clause)) = MARKED_FOR_DELETION;
02857         }
02858           break ;
02859         case INDEXED_CL: {
02860           cell_opcode(ClRefIEntryPoint(Clause,ClRefNumInds(Clause))) = fail ;
02861           cell_operand1(ClRefIEntryPoint(Clause,ClRefNumInds(Clause))) 
02862             = MARKED_FOR_DELETION;
02863           }
02864           break ;
02865         case SOB_RECORD:
02866           xsb_exit( "retracting indexing record!" ) ;
02867           break ;
02868         default :
02869           xsb_exit( "retract internal error!" ) ;
02870           break ;
02871     }
02872     SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
02873 }
02874 
02875 /* called only if retract_nr == 0.  If retract_nr != 0, then we check
02876    that it is not a shared predicate and more than one active thread.
02877    If not, the cpstack is marked, and it is determined whether the
02878    clause is safe to delete (that we aren't changing an instruction
02879    pointed to by the cp stack).  If none of these cases is true, THEN
02880    we can actually delete the clause.  Otherwise, we make a frame on
02881    the delcf list. */
02882 
02883 static void retract_clause(CTXTdeclc ClRef Clause, Psc psc ) { 
02884   PrRef prref; 
02885   int really_deleted = 0;
02886   
02887   mark_for_deletion(CTXTc Clause);
02888 
02889   if ((flags[NUM_THREADS] == 1 || !get_shared(psc)) 
02890       && pflags[CLAUSE_GARBAGE_COLLECT] == 1  && !dyntabled_incomplete(CTXTc psc)) {
02891 
02892     if (!mark_cpstack_retract(CTXTc Clause) && 
02893         determine_if_safe_to_delete(Clause)) {
02894       //          fprintf(stderr,"Really deleting clause: %s/%d (%p)\n",
02895       //                  get_name(psc),get_arity(psc),Clause);
02896       really_delete_clause(Clause);
02897       really_deleted = 1;
02898     }
02899     unmark_cpstack_retract(CTXT);
02900   }
02901   if (!really_deleted) {
02902     /* retracting only if unifying -- dont worry abt. NULL return for d_to_p */
02903     prref = dynpredep_to_prref(CTXTc get_ep(psc));
02904     //    fprintf(stderr,"Delaying retract of clref in use: %s/%d\n",
02905     //    get_name(psc),get_arity(psc));
02906 #ifndef MULTI_THREAD
02907     check_insert_private_delcf_clause(prref,psc,Clause);
02908 #else
02909     if (!get_shared(psc)) {
02910       check_insert_private_delcf_clause(CTXT, prref,psc,Clause);
02911     }
02912     else {
02913       check_insert_shared_delcf_clause(CTXT, prref,psc,Clause);
02914     }
02915 #endif
02916   }
02917 }
02918 
02919 
02920 /***
02921  *** Entry points for CLAUSE/RETRACT predicates
02922  ***/
02923 
02924 ClRef previous_clref(ClRef Clause) {
02925   int numInds;
02926   byte opcode;
02927 
02928   if (ClRefType(Clause) == INDEXED_CL) {
02929     opcode = ClRefTryOpCode(Clause);
02930     if (opcode == dynnoop || opcode == dyntrymeelse
02931         || opcode == noop || opcode == trymeelse) {
02932       numInds = ClRefNumInds(Clause);
02933       Clause = ClRefPrev(Clause); /* get used_up parent SOB */
02934       opcode = ClRefTryOpCode(Clause);
02935       while (opcode == dynnoop || opcode == dyntrymeelse
02936              || opcode == noop || opcode == trymeelse) {
02937         if (--numInds) {
02938           Clause = (ClRef)(((Cell *)ClRefPrev(Clause)) - 5);
02939           opcode = ClRefTryOpCode(Clause);
02940         } else return ClRefPrev(Clause);
02941       }
02942       Clause = ClRefPrev(Clause);
02943       while (ClRefType(Clause) == SOB_RECORD) {
02944         Clause = (ClRef)ClRefLastIndex(Clause);
02945       }
02946     } else Clause = ClRefPrev(Clause);
02947   } else { // if (ClRefType(Clause) == UNINDEXED_CL)) {
02948     Clause = ClRefPrev(Clause);
02949     while (ClRefType(Clause) == SOB_RECORD) {
02950       Clause = (ClRef)ClRefLastIndex(Clause);
02951     }
02952   }
02953    return Clause;
02954 }
02955 
02956 CPtr get_ClRefEntryPoint(ClRef Clause) {
02957   int numInds;
02958   if( ClRefType(Clause) != INDEXED_CL )
02959     return ClRefEntryPoint(Clause);
02960   else {
02961     numInds = ClRefNumInds(Clause) ;
02962     return ClRefIEntryPoint(Clause,numInds) ;
02963   }
02964 }
02965 
02966 ClRef db_get_clause_code_space(PrRef Pred, ClRef Clause, CPtr *CodeBegAddr, 
02967                                CPtr *CodeEndAddr) {
02968   int IndexArg = 0;
02969   int IndexLev = 0;
02970 
02971   do {
02972     if (Clause == NULL) 
02973       Clause = first_clref(Pred,(prolog_term)NULL,&IndexLev,&IndexArg);
02974     else Clause = next_clref(Pred,Clause,(prolog_term)NULL,&IndexLev,&IndexArg);
02975   } while (Clause && !(ClRefNotRetracted(Clause)));
02976 
02977   if (Clause != NULL) {
02978     *CodeBegAddr = get_ClRefEntryPoint(Clause);
02979     *CodeEndAddr = (CPtr)((pb)ClRefAddr(Clause) + ClRefSize(Clause));
02980   }
02981   return Clause;
02982 }
02983 
02984 /* db_get_last_clause returns the clref of the last (un-failed) clause
02985 in a predicate.  It fails if there are no clauses.  It should be
02986 extended to handle indexed predicates... */
02987 
02988 xsbBool db_get_last_clause( CTXTdecl /*+(PrRef)Pred, -(ClRef)Clause, 
02989                               -(Integer)Type, -(Integer)EntryPoint*/ )
02990 {
02991   PrRef Pred = (PrRef)ptoc_int(CTXTc 1);
02992   ClRef Clause;
02993   CPtr EntryPoint = 0;
02994 
02995   Pred = dynpredep_to_prref(CTXTc Pred);
02996   if (!Pred) return FALSE;
02997     
02998   if (Pred->LastClRef == (ClRef)Pred) return FALSE;
02999   Clause = Pred->LastClRef;
03000 
03001   while (ClRefType(Clause) == SOB_RECORD) {
03002     Clause = (ClRef)ClRefLastIndex(Clause);
03003   }
03004 
03005   while (Clause != (ClRef)Pred && !ClRefNotRetracted(Clause)) {
03006     Clause = previous_clref(Clause);
03007   }
03008 
03009   if (Clause == (ClRef)Pred) return FALSE;
03010   EntryPoint = get_ClRefEntryPoint(Clause);
03011   ctop_int(CTXTc 2, (Integer)Clause);
03012   ctop_int(CTXTc 3, (Integer)ClRefType(Clause));
03013   ctop_int(CTXTc 4, (Integer)EntryPoint);
03014   return TRUE;
03015 }
03016 
03017 /* db_get_clause
03018  * gets next clause from predicate
03019  * Arg 1 is the previous ClRef, or 0 if this is the first call.
03020  * Arg 2 is n if the nth index is to be used, 0 initially, and on subsequent
03021  *      calls, should pass in value previously returned in Arg 10.
03022  * Arg 3 is the integer indicating the field(s) indexed on (from the sob(3) instr,
03023  *      initially 0, and subsequently value returned in Arg 11.
03024  * Arg 4 is the Prref (predicate handle)
03025  * Arg 5 is a prolog term that matches the head of the clause
03026  * Arg 6 is 0 for "normal" clauses, 1 for clauses that consist of a fail 
03027  * instruction (generated by retract_nr and to be passed to reclaim space)
03028  * Arg 7 returns the clause address
03029  * Arg 8 returns the clause type
03030  * Arg 9 returns the jump point into the code
03031  * Arg 10 returns the ordinal for indexing (pass back in Arg 2 on subsequent calls)
03032  * Arg 11 returns the index fields mask (pass back in Arg 3 on subsequent calls)
03033  */
03034 
03035 xsbBool db_get_clause( CTXTdecl /*+CC, ?CI, ?CIL, +PredEP, +Head, +Failed, -Clause, -Type, -EntryPoint, -NewCI, -NewCIL */ )
03036 {
03037   PrRef Pred = (PrRef)ptoc_int(CTXTc 4);
03038   int IndexLevel = 0, IndexArg = 0;
03039   ClRef Clause ;
03040   prolog_term Head = reg_term(CTXTc 5);
03041   CPtr EntryPoint = 0;
03042   Integer failed = ptoc_int(CTXTc 6) ;
03043 
03044   //  printf("entered db_get_clause: %s/%d\n",get_name(get_str_psc(Head)),get_arity(get_str_psc(Head)));
03045 
03046     xsb_dbgmsg((LOG_RETRACT_GC,
03047                "GET CLAUSE P-%p(%x) C-%p(%x) F-%p L-%p",
03048                Pred, *(pb)Pred, ptoc_int(CTXTc 1),
03049                ptoc_int(CTXTc 1) ? *(pb)(ptoc_int(CTXTc 1)) : 0,
03050                Pred->FirstClRef, Pred->LastClRef ));
03051 
03052     Pred = dynpredep_to_prref(CTXTc Pred);
03053     
03054     SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03055     if( !(Pred) || (Pred->LastClRef == (ClRef)Pred) )
03056     {   Clause = 0 ;
03057         goto set_outputs;
03058     }
03059 
03060     Clause = (ClRef)ptoc_int(CTXTc 1);
03061     if (Clause == 0) {
03062       Clause = first_clref( Pred, Head, &IndexLevel, &IndexArg ) ;
03063       while (Clause && ClRefNotRetracted(Clause)==failed) {
03064         Clause = next_clref( Pred, Clause, Head, &IndexLevel, &IndexArg );
03065       }
03066     }
03067     else
03068       { IndexLevel = ptoc_int(CTXTc 2);  /* which index is used, ith */
03069         IndexArg   = ptoc_int(CTXTc 3);  /* index mask */
03070 
03071         do { /* loop until a clause is found:
03072                 Retracted if looking for failed; 
03073                 Not Retracted if looking for not failed */
03074             Clause = next_clref( Pred, Clause, Head, &IndexLevel, &IndexArg );
03075         } while (Clause && ClRefNotRetracted(Clause)==failed ) ;
03076     }
03077 
03078 set_outputs:
03079     if( Clause != 0 ) {
03080       if( ClRefType(Clause) == SOB_RECORD ) {
03081             xsb_exit("Error in get clause");
03082       }
03083       else EntryPoint = get_ClRefEntryPoint(Clause);
03084     }
03085     else
03086       EntryPoint = 0 ;
03087 
03088     xsb_dbgmsg((LOG_RETRACT_GC,
03089                "GOT CLAUSE C-%p(%x)", Clause, Clause ? *(pb)Clause : 0 ));
03090     SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03091 
03092     ctop_int(CTXTc  7, (Integer)Clause ) ;
03093     ctop_int(CTXTc  8, Clause != 0 ? (Integer)ClRefType(Clause) : 4 ) ;
03094     ctop_int(CTXTc  9, (Integer)EntryPoint ) ;
03095     ctop_int(CTXTc 10, IndexLevel);
03096     ctop_int(CTXTc 11, IndexArg);
03097     return TRUE ;
03098 }
03099 
03100 /* obsolete, and probably wrong. */
03101 xsbBool db_reclaim0( CTXTdecl /* CLRef, Type */ )
03102 {
03103   ClRef Clause = (ClRef)ptoc_int(CTXTc 1) ;
03104 
03105   mark_for_deletion(CTXTc Clause) ;
03106   return TRUE;
03107 }
03108 
03109 xsbBool db_retract0( CTXTdecl /* ClRef, retract_nr */ )
03110 {
03111   ClRef clause = (ClRef)ptoc_int(CTXTc 1) ;
03112   //  int retract_nr = (int)ptoc_int(CTXTc 2) ;
03113   
03114   int retract_nr = 0;
03115   
03116   if (retract_nr) {
03117     mark_for_deletion(CTXTc clause);
03118   } 
03119   else {
03120     Psc psc = (Psc)ptoc_int(CTXTc 3);
03121     retract_clause(CTXTc clause, psc ) ;
03122   }
03123   return TRUE;
03124 }
03125 
03126 
03127 /*----------------------------------------------------------------------
03128   in the following, the number 8 denotes the size (in cells) of the
03129   following fixed sequence of instructions:
03130          <tabletrysingle, allocate_gc, getVn, calld, new_answer_dealloc>
03131   that gets generated as an entry point clause for all dynamic tabled
03132   predicates.
03133   ----------------------------------------------------------------------*/
03134 /* TLS: changed mem_alloc to nocheck as xsb_throw() depends on this
03135    predicate.  So if we're out of memory here, we're sunk. */
03136 
03137 static inline void allocate_prref_tab(CTXTdeclc Psc psc, PrRef *prref, pb *new_ep) {
03138   int Loc;
03139 
03140   if (!(*prref = (PrRef)mem_alloc_nocheck(sizeof(PrRefData),ASSERT_SPACE))) 
03141     xsb_exit("++Unrecoverable Error[XSB/Runtime]: [Resource] Out of memory (PrRef)");
03142   //  fprintf(stdout,"build_prref: %s/%d, shared=%d, prref=%p\n",
03143   //          get_name(psc),get_arity(psc),get_shared(psc),prref);
03144 
03145   if (xsb_profiling_enabled)
03146     add_prog_seg(psc,(byte *)*prref,sizeof(PrRefData)); /* dsw profiling */
03147 
03148   Loc = 0 ;
03149   dbgen_inst_ppp(fail,*prref,&Loc) ;
03150   //  ((CPtr)(*prref))[2] = (Cell)(*prref) ; TLS: ugh!
03151   PrRef_FirstClRef(*prref) = NULL;
03152   PrRef_LastClRef(*prref) = (ClRefHdr *)*prref;
03153   PrRef_Psc(*prref) = psc;        
03154   PrRef_Mark(*prref) = 0;
03155   PrRef_DelCF(*prref) = NULL;
03156   if ( get_tabled(psc) )
03157     {
03158       TIFptr tip;
03159       CPtr tp;
03160       tip = New_TIF(CTXTc psc);
03161       tp  = (CPtr)mem_alloc_nocheck(FIXED_BLOCK_SIZE_FOR_TABLED_PRED,ASSERT_SPACE) ;
03162       if (tp == NULL) {
03163         xsb_exit("++Unrecoverable Error[XSB/Runtime]: [Resource] Out of memory (PrRef)");
03164       }
03165       Loc = 0 ;
03166       dbgen_inst_ppvww(tabletrysingle,get_arity(psc),(tp+3),tip,tp,&Loc) ;
03167       dbgen_inst_pvv(allocate_gc,3,3,tp,&Loc) ;
03168       dbgen_inst_ppv(getVn,2,tp,&Loc) ;  /* was getpbreg */
03169       dbgen_inst_ppvw(calld,3,*prref,tp,&Loc) ; /* *prref is *(tp+6), see remove_prref*/
03170       dbgen_inst_pvv(new_answer_dealloc,get_arity(psc),2,tp,&Loc) ;
03171       *new_ep = (pb)tp;
03172     }
03173   else *new_ep = (pb)*prref;
03174 }
03175 
03176 
03177 PrRef build_prref( CTXTdeclc Psc psc )
03178 {
03179   PrRef p;
03180   pb new_ep;
03181   //  Integer Tabled = ptoc_int(CTXTc 2);
03182 
03183   set_type(psc, T_DYNA);
03184   set_env(psc, T_VISIBLE);
03185 
03186   /* set data to point to usermod -- lfcastro */
03187   if (get_data(psc) == NULL) 
03188     set_data(psc,global_mod);
03189     
03190   allocate_prref_tab(CTXTc psc,&p,&new_ep);
03191   p->psc = psc;
03192   p-> mark = 0;
03193 
03194 #ifdef MULTI_THREAD
03195   //  printf("prref disp tab for %s/%d? shared=%d\n",
03196   //         get_name(psc),get_arity(psc),get_shared(psc));
03197 
03198   if ((*(pb)get_ep(psc) == switchonthread) || !get_shared(psc)) {
03199     struct DispBlk_t *dispblk;
03200     if (*(pb)get_ep(psc) != switchonthread) {
03201       /* create new switchonthread instruction and dispblock */
03202       pb disp_instr_addr = mem_calloc(sizeof(Cell),2,MT_PRIVATE_SPACE);
03203       dispblk = (struct DispBlk_t *) 
03204         mem_calloc(sizeof(struct DispBlk_t)+MAX_THREADS*sizeof(Cell),
03205                    1,MT_PRIVATE_SPACE);
03206 
03207       SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03208       if (DispBlkHdr.firstDB) DispBlkHdr.firstDB->PrevDB = dispblk;
03209       dispblk->NextDB = DispBlkHdr.firstDB;
03210       DispBlkHdr.firstDB = dispblk;
03211       if (!DispBlkHdr.lastDB) DispBlkHdr.lastDB = dispblk;
03212       SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03213 
03214       dispblk->MaxThread = MAX_THREADS;
03215       *disp_instr_addr = switchonthread;
03216       *(((CPtr *)disp_instr_addr)+1) = (CPtr)dispblk;
03217       set_ep(psc,disp_instr_addr);
03218     } else {
03219       /* add to dispblock if room, extending if nec */
03220       dispblk = (struct DispBlk_t *)*((CPtr)get_ep(psc)+1);
03221     }
03222     if (dispblk->MaxThread >= th->tid) {
03223       (&(dispblk->Thread0))[th->tid] = (CPtr)new_ep;
03224     } else xsb_exit("must expand dispatch-block");
03225   } else set_ep(psc,new_ep);
03226 #else
03227   set_ep(psc,new_ep);
03228 #endif /* MULTI_THREAD */
03229   return p;
03230 }
03231 
03232 xsbBool db_build_prref( CTXTdecl /* PSC, Tabled?, -PrRef */ ) {
03233 
03234   ctop_int(CTXTc 3, (Integer)build_prref(CTXTc (Psc)ptoc_int(CTXTc 1)));
03235   return TRUE;
03236 }
03237 
03238 
03239 PrRef get_prref(CTXTdeclc Psc psc) {
03240   PrRef prref;
03241   if (get_ep(psc) == (byte *)&fail_inst) {
03242     prref = build_prref(CTXTc psc);
03243   } else {
03244     prref = dynpredep_to_prref(CTXTc get_ep(psc));
03245 #ifdef MULTI_THREAD
03246     //  SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03247     if (!prref) {
03248       pb new_ep;
03249       struct DispBlk_t *dispblk = ((struct DispBlk_t **)get_ep(psc))[1];
03250       allocate_prref_tab(CTXTc psc,&prref,&new_ep);
03251       if (dispblk->MaxThread >= th->tid) {
03252         (&(dispblk->Thread0))[th->tid] = (CPtr) new_ep;
03253       } else {
03254         //      SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03255         xsb_exit("must expand dispatch-block");
03256       }
03257     }
03258     //  SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03259 #endif
03260   }
03261   return prref;
03262 }
03263 
03264 xsbBool db_get_prref( CTXTdecl /* PSC, -PrRef */ ) {
03265   ctop_int(CTXTc 2,(Integer)get_prref(CTXTc (Psc)ptoc_int(CTXTc 1)));
03266   return TRUE;
03267 }
03268 
03269 /* See also free_private_pref() below.  free_private_prref() is the
03270    same as free_prref, except that it knows to free a private tif,
03271    rather than having to check via the psc record. */
03272 
03273 void free_prref(CTXTdeclc CPtr *p, Psc psc) {
03274 
03275     if ( *(pb)p == tabletrysingle )
03276       {
03277         TIFptr mtTIF = (TIFptr) *(p+2);
03278 #ifdef MULTI_THREAD
03279         if (!get_shared(psc)) {
03280           Free_Private_TIF(mtTIF);
03281         }
03282         else {
03283           Free_Shared_TIF(mtTIF);
03284         }
03285 #else
03286         Free_Shared_TIF(mtTIF);
03287 #endif
03288         /* free prref, from calld instr set in db_build_prref */
03289         mem_dealloc((pb)(*(p+6)), sizeof(PrRefData),ASSERT_SPACE);
03290         if (xsb_profiling_enabled)
03291           remove_prog_seg((pb)*(p+6));
03292         mem_dealloc((pb)p, FIXED_BLOCK_SIZE_FOR_TABLED_PRED,ASSERT_SPACE) ; /*free table hdr*/
03293       }
03294     else {
03295       mem_dealloc((pb)p, sizeof(PrRefData),ASSERT_SPACE);  /* free prref */
03296       if (xsb_profiling_enabled)
03297         remove_prog_seg((pb)p);
03298     }
03299 }
03300 
03301 /* Given an sob clref, return the prref in which it occurs */
03302 PrRef sob_to_prref(ClRef clref) {
03303   while (ClRefTryOpCode(clref) == dynretrymeelse) {
03304     /* search backward, under (unsupported) assumption that it is 
03305        more likely to be near the beginning; could look forward. */
03306     clref = ClRefPrev(clref);
03307   }
03308   switch (ClRefTryOpCode(clref)) {
03309   case dynnoop:
03310   case noop:
03311   case dyntrymeelse:
03312   case trymeelse:
03313     return (PrRef)ClRefPrev(clref);
03314   case dyntrustmeelsefail:
03315     return (PrRef)ClRefNext(clref);
03316   }
03317   return NULL;
03318 }
03319 
03320 /* Given a clref, return the prref in which it occurs */
03321 #ifdef UNDEFINED
03322 PrRef clref_to_prref(ClRef clref) {
03323   CPtr curInd;
03324   if (ClRefType(clref) == UNINDEXED_CL) {
03325     return sob_to_prref(clref);
03326   } else if (ClRefType(clref) == INDEXED_CL) { /* indexed, use first index */
03327     curInd = ClRefIndPtr(clref,1);
03328     if (ClRefTryOpCode(curInd) != dynnoop) {
03329       while (cell_opcode(curInd) != dyntrustmeelsefail) {
03330         curInd = IndRefNext(curInd);
03331       }
03332     }
03333     return sob_to_prref((SOBRef)IndRefNext(curInd));
03334   } else return NULL;
03335 }
03336 #endif
03337 
03338 PrRef clref_to_prref(ClRef clref) {
03339   CPtr curInd;
03340   if (ClRefType(clref) == UNINDEXED_CL || ClRefType(clref) == SOB_RECORD) {
03341     return sob_to_prref(clref);
03342   } else if (ClRefType(clref) == INDEXED_CL) { /* indexed, use first index */
03343     curInd = ClRefIndPtr(clref,1);
03344     if (ClRefTryOpCode(curInd) != dynnoop) {
03345       while (cell_opcode(curInd) != dyntrustmeelsefail) {
03346         curInd = IndRefNext(curInd);
03347       }
03348     }
03349     return sob_to_prref((SOBRef)IndRefNext(curInd));
03350   } else return NULL;
03351 }
03352 
03353 
03354 /*----------------------------------------------------------------------*/
03355 /* some stuff for trie_assert                                           */
03356 /*----------------------------------------------------------------------*/
03357 
03358 #define clref_fld(x) ((CPtr) *(x +1))
03359 #define next_clref(x) ((CPtr) *(x +1))
03360 #define last_clref(PRREF)  ((CPtr)((PrRef)(PRREF))->LastClRef)
03361 #define try_type_instr_fld(x)  (ClRefTryOpCode(x))
03362 #define code_to_run(x)   (cell_opcode(ClRefEntryPoint(x)))
03363 #define first_instr_to_run(x)  (cell_opcode(ClRefWord(x,3)))
03364 
03365 /*----------------------------------------------------------------------*/
03366 
03367 static inline int clref_trie_asserted(CPtr Clref) {
03368   return((code_to_run(Clref) == jump) && 
03369          (first_instr_to_run(Clref) == trie_assert_inst));
03370 }
03371 /*----------------------------------------------------------------------*/
03372 
03373 /* called by gen_retractall in case the predicate "abolished" is a trie.
03374    This deletes from the root of the trie, as obtained by the first ClRef */
03375 
03376 static void abolish_trie_asserted_stuff(CTXTdeclc PrRef prref) {
03377 
03378    BTNptr pRoot;
03379    CPtr b;
03380 
03381    /*** printf("abolish_trie\n"); ***/
03382    b = (CPtr)prref->FirstClRef;
03383    pRoot = (BTNptr)*(b + 3);
03384    switch_to_trie_assert;
03385    delete_trie(CTXTc pRoot);
03386    switch_from_trie_assert;
03387    *(pb)prref = fail;
03388    mem_dealloc((pb)(b-2),6*sizeof(Cell),ASSERT_SPACE);  /* allocated in trie_assert */
03389 }
03390 
03391 /*----------------------------------------------------------------------*/
03392 
03393 static int another_buff(Cell Instr)
03394 {
03395   int op = cell_opcode(&Instr) ;
03396   return (op != dynnoop && op != dyntrustmeelsefail && op != fail 
03397     && op != noop);
03398 }
03399 
03400 /*======================================================================*/
03401 /* The following routine deletes all clauses from a prref.  It is the   */
03402 /* equivalent of retractall(p(_,_,_,..,_)). It is given the address of  */
03403 /* a buffer and frees it and all buffers it points to.                  */
03404 /*======================================================================*/
03405 #define MAXDYNFREEBUFF 200
03406 
03407 /* If you update this, please check gc_retractall() also */
03408 void retractall_prref(CTXTdeclc PrRef prref) {
03409   int btop = 0;
03410   ClRef buffer;
03411   ClRef buffers_to_free[MAXDYNFREEBUFF];
03412 
03413   if (prref && (cell_opcode((CPtr)prref) != fail)) {
03414     if (PredOpCode(prref) == jump) {  /* should be trie-asserted */
03415       abolish_trie_asserted_stuff(CTXTc prref);
03416       return;
03417     }
03418     buffers_to_free[btop++] = prref->FirstClRef;
03419     while (btop > 0) {
03420       if (btop >= MAXDYNFREEBUFF) xsb_exit("Too many buffers to retract");
03421       buffer = buffers_to_free[--btop];
03422       switch (ClRefType(buffer)) {
03423       case SOB_RECORD: 
03424         if (another_buff(ClRefJumpInstr(buffer)))
03425           buffers_to_free[btop++] = (ClRef) ClRefFirstIndex(buffer);
03426         if (another_buff(ClRefTryInstr(buffer)))
03427           buffers_to_free[btop++] = ClRefNext(buffer);
03428         mem_dealloc((pb)ClRefAddr(buffer),ClRefSize(buffer),ASSERT_SPACE);
03429         if (xsb_profiling_enabled)
03430           remove_prog_seg((pb)buffer);
03431         break ;
03432       case UNINDEXED_CL: 
03433       case INDEXED_CL:
03434         if (another_buff(ClRefTryInstr(buffer)))
03435           buffers_to_free[btop++] = ClRefNext(buffer);
03436         if( ClRefNotRetracted(buffer) ) {
03437           /*            retract_clause(buffer,0) */
03438           /* really_delete_clause(buffer); */
03439           mem_dealloc((pb)ClRefAddr(buffer),ClRefSize(buffer),ASSERT_SPACE);
03440           if (xsb_profiling_enabled)
03441             remove_prog_seg((pb)buffer);
03442         }
03443         break;
03444       }
03445     }
03446     PrRef_FirstClRef(prref) = NULL;
03447     cell_opcode((CPtr)prref) = fail;
03448   }
03449 }
03450 
03451 /* Like retractall_prref() but used from access is from a DelFC, so we
03452    want to start with the old Prrefs first clref, rather than the
03453    prref (which by the time we gc could have a new set of clrefs
03454    associated with it)
03455 */
03456 void gc_retractall(CTXTdeclc ClRef clref) {
03457   int btop = 0;
03458   ClRef buffer;
03459   ClRef buffers_to_free[MAXDYNFREEBUFF];
03460 
03461     buffers_to_free[btop++] = clref;
03462     while (btop > 0) {
03463       if (btop >= MAXDYNFREEBUFF) xsb_exit("Too many buffers to retract");
03464       buffer = buffers_to_free[--btop];
03465       switch (ClRefType(buffer)) {
03466       case SOB_RECORD: 
03467         if (another_buff(ClRefJumpInstr(buffer)))
03468           buffers_to_free[btop++] = (ClRef) ClRefFirstIndex(buffer);
03469         if (another_buff(ClRefTryInstr(buffer)))
03470           buffers_to_free[btop++] = ClRefNext(buffer);
03471         mem_dealloc((pb)ClRefAddr(buffer),ClRefSize(buffer),ASSERT_SPACE);
03472         if (xsb_profiling_enabled)
03473           remove_prog_seg((pb)buffer);
03474         break ;
03475       case UNINDEXED_CL: 
03476       case INDEXED_CL:
03477         if (another_buff(ClRefTryInstr(buffer)))
03478           buffers_to_free[btop++] = ClRefNext(buffer);
03479         if( ClRefNotRetracted(buffer) ) {
03480           /*            retract_clause(buffer,0) */
03481           /* really_delete_clause(buffer); */
03482           mem_dealloc((pb)ClRefAddr(buffer),ClRefSize(buffer),ASSERT_SPACE);
03483           if (xsb_profiling_enabled)
03484             remove_prog_seg((pb)buffer);
03485         }
03486         break;
03487       }
03488     }
03489 }
03490 
03491 /* TLS change for gc.  Space is reclaimed if 
03492 
03493      The predicate is private OR there is a single active thread
03494      AND 
03495      a check of the CP stack determines that it is safe to
03496      reclaim spaces for the predicate,
03497      AND 
03498      if the predicate is tabled, there is no incomplete table
03499      for that predicate.
03500  */
03501 int gen_retract_all(CTXTdecl/* R1: +PredEP , R2: +PSC */)
03502 {
03503   PrRef prref = (PrRef)ptoc_int(CTXTc 1);
03504   Psc psc = (Psc)ptoc_int(CTXTc 2);
03505   int action = 0;
03506 
03507   prref = dynpredep_to_prref(CTXTc prref);
03508 
03509   /* Here, !prref can occur if the predicate is private but its
03510      thread-specific prref has not been created. */
03511 
03512   if (!prref || PrRef_FirstClRef(prref) == NULL) { /* nothing to retract */
03513     return TRUE;
03514   }
03515 
03516   if ((flags[NUM_THREADS] == 1 || !get_shared(psc))
03517       && pflags[CLAUSE_GARBAGE_COLLECT] == 1  && !dyntabled_incomplete(CTXTc psc)) {
03518 
03519     gc_dynamic(CTXT);    // part of gc strategy -- dont know how good
03520 
03521     action = check_cpstack_retractall(CTXTc prref);
03522   }  else action = 1;
03523   if (!action) {
03524     SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03525     //    fprintf(stderr,"abolishing prref (gen_retra) %p\n",prref);
03526     retractall_prref(CTXTc prref);
03527     SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03528   }
03529   else {
03530     //    fprintf(stderr,"Delaying retractall of prref in use: %s/%d\n",
03531     //    get_name(psc),get_arity(psc));
03532 #ifndef MULTI_THREAD
03533     check_insert_private_delcf_pred(prref,psc);
03534 #else
03535     if (!get_shared(psc)) {
03536       check_insert_private_delcf_pred(CTXT, prref,psc);
03537     }
03538     else {
03539       check_insert_shared_delcf_pred(CTXT, prref,psc);
03540     }
03541 #endif
03542     PrRef_FirstClRef(prref) = NULL;
03543     cell_opcode((CPtr)prref) = fail;
03544   }
03545   return TRUE;
03546 }
03547 
03548 /**************************************
03549    abolish/1
03550    
03551    I'm trying to approximate ISO semantics when 1 thread and
03552    non-tabled.  If the predicate is tabled and has an incomplete
03553    table, we throw an error as usual; otherwise if tabled the tables
03554    are abolished.  
03555 
03556    Unlike retractalls, this predicate throws an error if its unsafet
03557    to reclaim space immediately.  Note that for abolish, XSB reclaims
03558    based on the prref.  GC-ing a prref that has been abolished is
03559    problematic.  If you create a DelCF for the PrRef, you have a
03560    pointer to a reclaimed prref which isn't good; if you delay
03561    reclaiming the prref you lose ISO semantics.  You could create a
03562    3-rd type of DelCF frame for abolishes, and some special treatment,
03563    but I'm too lazy for that as I dont think that abolishing a
03564    predicate you're backtracking into is good programming practice.
03565 
03566 ********************************************/
03567 
03568 /* No longer available as builtin -- I think that's too dangerous now
03569    that we have prref gc -- TLS */
03570 void db_remove_prref_1( CTXTdeclc Psc psc ) 
03571 {
03572   SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03573   if (get_ep(psc) != ((byte *)(&(psc->load_inst)))) {
03574     free_prref(CTXTc (CPtr *)get_ep(psc),psc);
03575     set_type(psc, T_ORDI);
03576     set_ep(psc, ((byte *)(&(psc->load_inst))));
03577   }
03578   SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03579 }
03580 
03581 xsbBool db_abolish0(CTXTdecl/* R1: +PredEP , R2: +PSC */)
03582 {
03583   PrRef prref = (PrRef)ptoc_int(CTXTc 1);
03584   Psc psc = (Psc)ptoc_int(CTXTc 2);
03585   int action = 0;
03586   
03587   prref = dynpredep_to_prref(CTXTc prref);
03588 
03589   if (!prref) return TRUE;
03590 
03591   if (flags[NUM_THREADS] != 1) {
03592     xsb_abort("Cannot abolish a predicate when more than 1 thread is active");
03593   }
03594 
03595   if (get_tabled(psc)) {
03596     if (!is_completed_table(get_tip(CTXTc psc))) {
03597       xsb_table_error(CTXTc 
03598                     "Cannot abolish tabled predicate when table is incomplete");
03599     } else fast_abolish_table_predicate(CTXTc psc);
03600   }
03601 
03602   gc_dynamic(CTXT);    // part of gc strategy -- dont know how good
03603 
03604   action = check_cpstack_retractall(CTXTc prref);
03605   if (!action) {
03606     SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03607     // fprintf(stderr, "abolishing prref %p\n",prref);
03608     retractall_prref(CTXTc prref);
03609     db_remove_prref_1( CTXTc psc);
03610     SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03611   }
03612   else {
03613     xsb_abort("Cannot abolish a predicate with active backtrack points: use retractall");
03614   }
03615   return TRUE;
03616 }
03617 
03618 /*-----------------------------------------------------------------*/
03619 
03620 /* This function is used by ClRef-based retratall.  It has close to
03621    the same semantics as retract_clause(), but the CP stack marking
03622    and unmarking has been factored out into surrounding routines for
03623    efficiency.  In fact, the first condition could also be factored
03624    out, if we wanted to. */
03625 
03626 static void retractall_clause(CTXTdeclc ClRef Clause, Psc psc, int flag ) { 
03627   PrRef prref; 
03628   int really_deleted = 0;
03629 
03630   
03631   mark_for_deletion(CTXTc Clause);
03632 
03633     if ((flags[NUM_THREADS] == 1 || !get_shared(psc))
03634         && pflags[CLAUSE_GARBAGE_COLLECT] == 1  
03635         && !dyntabled_incomplete(CTXTc psc) && !flag) {
03636 
03637     if(!(clref_is_marked(Clause)) && 
03638         determine_if_safe_to_delete(Clause)) {
03639       really_delete_clause(Clause);
03640       really_deleted = 1;
03641     }
03642   }
03643   if (!really_deleted) {
03644     /* retracting only if unifying -- dont worry abt. NULL return for d_to_p */
03645     prref = dynpredep_to_prref(CTXTc get_ep(psc));
03646     //    fprintf(stderr,"Delaying retractall of clref in use: %s/%d\n",
03647     //            get_name(psc),get_arity(psc));
03648 #ifndef MULTI_THREAD
03649     check_insert_private_delcf_clause(prref,psc,Clause);
03650 #else
03651     if (!get_shared(psc)) {
03652       check_insert_private_delcf_clause(CTXT, prref,psc,Clause);
03653     }
03654     else {
03655       check_insert_shared_delcf_clause(CTXT, prref,psc,Clause);
03656     }
03657 #endif
03658   }
03659 }
03660 
03661 /* * * * * * * * * * * * */
03662 
03663 void db_retractall0( CTXTdecl /* (Switch) ClRef, retract_nr */ )
03664 {
03665   ClRef clause = (ClRef)ptoc_int(CTXTc 2) ;
03666   int cantReclaim = (int)ptoc_int(CTXTc 3) ;
03667   
03668   Psc psc = (Psc)ptoc_int(CTXTc 4);
03669   retractall_clause(CTXTc clause, psc, cantReclaim ) ;
03670 }
03671 
03672 /* * * * * * * * * * * * */
03673 
03674 /* At some point should probably move some of the following into here: 
03675  DB_GET_LAST_CLAUSE  DB_RETRACT0   DB_GET_CLAUSE    DB_BUILD_PRREF      
03676  DB_ABOLISH0     DB_RECLAIM0     DB_GET_PRREF */
03677 
03678 void init_dbclause_cgc_blocks(void) {
03679   Psc psc;
03680   int new;
03681 
03682   psc = ((Pair)insert("db_get_clauses1", 11, 
03683                       pair_psc(insert_module(0, "dbclause")), &new)) -> psc_ptr;
03684   dbclause_cgc_block_gl = (CPtr) (get_ep(psc) + 0xc8);
03685 }
03686 
03687 void init_standard_cgc_blocks(void) {
03688   Psc psc;
03689   int new;
03690 
03691   psc = ((Pair)insert(";", 2, 
03692                       pair_psc(insert_module(0, "standard")), &new))-> psc_ptr;
03693   standard_cgc_block_begin_gl = (CPtr) (get_ep(psc));
03694   standard_cgc_block_end_gl = (CPtr) (get_ep(psc) + 0x94);
03695 }
03696 
03697 
03698 xsbBool dynamic_code_function( CTXTdecl ) 
03699 {
03700   switch (ptoc_int(CTXTc 1)) {
03701 
03702   case MARK_CPSTACK_RETRACTALL: 
03703     ctop_int(CTXTc 2,mark_cpstack_retractall(CTXT));
03704     break;
03705 
03706   case UNMARK_CPSTACK_RETRACT: 
03707     unmark_cpstack_retract(CTXT);
03708     break;
03709 
03710   case DB_RETRACTALL0: 
03711     db_retractall0(CTXT);
03712     break;
03713 
03714   case INIT_DBCLAUSE_CGC_BLOCKS:
03715     init_dbclause_cgc_blocks();
03716     break;
03717 
03718   case INIT_STANDARD_CGC_BLOCKS:
03719     init_standard_cgc_blocks();
03720     break;
03721 
03722   }
03723 
03724   return TRUE;
03725 }
03726 
03727 /*===============================================================*/
03728 /* Trie Assert and Retract                                       */
03729 /*===============================================================*/
03730 
03731 static inline CPtr trie_asserted_clref(CPtr prref)
03732 {
03733   CPtr Clref;
03734 
03735   Clref = last_clref(prref);
03736   if (try_type_instr_fld(prref) != fail) {
03737     if ((code_to_run(Clref) == jump) &&
03738         (first_instr_to_run(Clref) == trie_assert_inst))
03739       return Clref;
03740   }
03741   return NULL;
03742 }
03743 
03744 /*---------------------------------------------------------------*/
03745 /* used for debugging trie_assert */
03746 
03747 static inline void print_bytes(CPtr x, int lo, int hi)
03748 {
03749   int i;
03750 
03751   xsb_dbgmsg((LOG_DEBUG, "addr %p ---------------------------------",x));
03752   for (i = lo; i <= hi ; i++) {
03753     xsb_dbgmsg((LOG_DEBUG," i = %d 4*i = %d  x[i] = %x ",i,4*i, (int)*(x+i)));
03754   }
03755   xsb_dbgmsg((LOG_DEBUG, "Instr = %s ---code to run %s----",
03756              (char *)inst_table[try_type_instr_fld(x)][0],
03757              (char *)inst_table[code_to_run(x)][0] ));
03758 }
03759 
03760 /*----------------------------------------------------------------*/
03761 
03762 BTNptr trie_asserted_trienode(CPtr clref) {
03763       if ((ClRefType(clref) == TRIE_CL) && clref_trie_asserted(clref))
03764         return((BTNptr)*(clref + 3));
03765       else return NULL;
03766 }
03767 
03768 /*----------------------------------------------------------------*/
03769 
03770 int trie_assert(CTXTdecl)
03771 {
03772   Cell Clause;
03773   Psc  psc;
03774   CPtr Prref;
03775 #ifdef DEBUG_VERBOSE
03776   int  Arity;
03777 #endif
03778   CPtr Trie_Asserted_Clref = NULL;
03779   BTNptr inst_node_ptr;
03780   int  found = 1;
03781 
03782   Clause = reg_term(CTXTc 1);
03783   psc    = (Psc)ptoc_int(CTXTc 2);
03784   Prref  = (CPtr)ptoc_int(CTXTc 4);
03785 
03786 #ifdef DEBUG_VERBOSE
03787   Arity  = ptoc_int(CTXTc 3);
03788   xsb_dbgmsg((LOG_DEBUG,"Prref bytes\n"));
03789   if (cur_log_level >= LOG_DEBUG)
03790     print_bytes(Prref,-2,2);
03791   xsb_dbgmsg((LOG_DEBUG,"Clause :"));
03792   dbg_printterm(LOG_DEBUG,stddbg,Clause,24);
03793   xsb_dbgmsg((LOG_DEBUG," Arity %d ", Arity));
03794   xsb_dbgmsg((LOG_DEBUG," Psc   %d ",(int)psc));
03795   xsb_dbgmsg((LOG_DEBUG," Prref %d ",(int)Prref));
03796   xsb_dbgmsg((LOG_DEBUG,"\n"));
03797 #endif
03798 
03799   Trie_Asserted_Clref = trie_asserted_clref(Prref);
03800 
03801   xsb_dbgmsg((LOG_ASSERT, " Trie_Asserted_Clref %p",Trie_Asserted_Clref));
03802 
03803   switch_to_trie_assert;
03804   SYS_MUTEX_LOCK( MUTEX_DYNAMIC );
03805   if(Trie_Asserted_Clref == NULL){
03806     /*
03807      * Allocate the trie node as in old trie assert: put it in a clref
03808      * block and pray.  See Note 1 below.
03809      */
03810     Trie_Asserted_Clref = ((CPtr)mem_alloc(6*sizeof(Cell),ASSERT_SPACE)) + 2;
03811     *(Trie_Asserted_Clref-2) = 6*sizeof(Cell)+TRIE_CL; /* store size, encode type */
03812     *(byte *)(Trie_Asserted_Clref +2) = jump;
03813 
03814     inst_node_ptr = newBasicTrie(CTXTc EncodeTriePSC(psc),ASSERT_TRIE_TT);
03815     Instr(inst_node_ptr) = trie_assert_inst;
03816 
03817     *(Trie_Asserted_Clref +3) = (Cell)inst_node_ptr;
03818 
03819     db_addbuff((byte)(get_arity(psc) + 1),(ClRef)Trie_Asserted_Clref,(PrRef)Prref,1,TRUE,2);
03820   }
03821   else
03822     inst_node_ptr = (BTNptr)*(Trie_Asserted_Clref +3);
03823 
03824   one_term_chk_ins(CTXTc (CPtr)Clause,inst_node_ptr,&found);
03825   SYS_MUTEX_UNLOCK( MUTEX_DYNAMIC );
03826   switch_from_trie_assert;      
03827   ctop_int(CTXTc 5,found);
03828   return TRUE;
03829 }
03830 
03831 /* 
03832    Note 1: In trie_assert, the ClRef is a dummy node, whose first cell
03833    is its buffer size (actually, only the size for the dummy ClRef),
03834    and whose second is the previous ClRef (0, since all info will be
03835    in the trie)
03836 
03837    ------------
03838    | BuffLength: 6*sizeof(Cell)+2  (??)
03839    ------------
03840    | Previous: 0
03841    ------------
03842    |         :                      <-- Trie_Asserted_Clref
03843    ------------
03844    |         : 
03845    ------------
03846    |         : jump
03847    ------------
03848    |         : inst_node_ptr
03849    ------------
03850 
03851    However, I dont presently know why 6 cells must be allocated?
03852  */
03853 /*-----------------------------------------------------------------*/
03854 
03855 int trie_retract(CTXTdecl)
03856 {
03857   CPtr Clref;
03858   BTNptr inst_node_ptr;
03859 
03860   Clref = (CPtr)ptoc_int(CTXTc 1);
03861   if (Clref == NULL) {
03862     Last_Nod_Sav = NULL;
03863     return TRUE;
03864   }
03865   else if (Last_Nod_Sav == NULL) {
03866     xsb_dbgmsg((LOG_DEBUG,"Last_Nod_Sav is NULL "));
03867     return FALSE;
03868   }
03869   else {
03870     inst_node_ptr = (BTNptr)*(Clref +3);
03871     xsb_dbgmsg((LOG_DEBUG, " Deleting from Instrn Node %p",  inst_node_ptr ));
03872     xsb_dbgmsg((LOG_DEBUG, 
03873                " Before: Child of Instrn Node %p", Child(inst_node_ptr)));
03874     switch_to_trie_assert;
03875     delete_branch(CTXTc Last_Nod_Sav, &(Child(inst_node_ptr)));
03876     switch_from_trie_assert;
03877     xsb_dbgmsg((LOG_DEBUG,
03878                " After : Child of Instrn Node %p", Child(inst_node_ptr)));
03879     return TRUE;
03880   }
03881 }
03882 
03883 /*-----------------------------------------------------------------*/
03884 
03885 /* Only mark the nodes in the branch as deleted. */
03886 
03887 int trie_retract_safe(CTXTdecl)
03888 { 
03889   if (Last_Nod_Sav == NULL)
03890     return FALSE;
03891   else {
03892     safe_delete_branch(Last_Nod_Sav);
03893     return TRUE;
03894   }
03895 }
03896 

Generated on Wed Jul 26 13:30:39 2006 for XSB by  doxygen 1.4.5