loader_xsb.c

00001 /* File:      loader_xsb.c
00002 ** Author(s): David S. Warren, Jiyang Xu, Terrance Swift, Kostis Sagonas
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 for
00016 ** more details.
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: loader_xsb.c,v 1.62 2006/06/23 14:53:10 tswift Exp $
00023 ** 
00024 */
00025 
00026 
00027 /************************************************************************/
00028 /*
00029         This file contains routines for loading a byte code
00030         file into the emulator's permanent work space (pspace).
00031 */
00032 /************************************************************************/
00033 
00034 #include "xsb_config.h"
00035 #include "xsb_debug.h"
00036 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 
00041 #include "auxlry.h"
00042 #include "context.h"
00043 #include "psc_xsb.h"
00044 #include "psc_defs.h"
00045 #include "loader_xsb.h"
00046 #include "extensions_xsb.h"
00047 #include "cell_xsb.h"
00048 #include "heap_xsb.h"
00049 #include "flags_xsb.h"
00050 #include "tries.h"
00051 #include "macro_xsb.h"
00052 #include "error_xsb.h"
00053 #include "io_builtins_xsb.h"
00054 #include "inst_xsb.h"
00055 #include "memory_xsb.h"
00056 #include "register.h"
00057 #include "varstring_xsb.h"
00058 #include "thread_xsb.h"
00059 
00060 #ifdef FOREIGN
00061 #include "dynload.h"
00062 #endif
00063 
00064 #include "debug_xsb.h"
00065  
00066 /* === stuff used from elsewhere ====================================== */
00067 
00068 extern TIFptr *get_tip_or_tdisp(Psc);
00069 
00070 extern int xsb_profiling_enabled;
00071 extern void add_prog_seg(Psc, byte *, long);
00072 extern void remove_prog_seg(byte *);
00073 extern void delete_predicate_table(CTXTdeclc TIFptr);
00074 
00075 /* === macros ========================================================= */
00076 
00077 #define st_ptrpsc(i_addr)  (cell(i_addr) = *reloc_table[cell(i_addr)])
00078 
00079 #define st_pscname(i_addr) (cell(i_addr) = \
00080         (Cell) get_name((Psc)(*reloc_table[cell(i_addr)])))
00081 
00082 #define gentry(opcode, arg1, arg2, ep) {        \
00083         (cell_opcode(ep)) = (opcode);           \
00084         (cell_operand1(ep)) = 0;                \
00085         (cell_operand2(ep)) = 0;                \
00086         (cell_operand3(ep)) = (arg1);           \
00087         (ep)++;                                 \
00088         cell(ep) = (Cell) (arg2);               \
00089         (ep)++; }
00090 
00091 #define gentabletry(opcode, arg1, arg2, arg3, ep)     { \
00092         gentry(opcode, arg1, arg2, ep);                 \
00093         cell(ep) = (Cell) (arg3);                       \
00094         (ep)++; }
00095 
00096 #define reloc_addr(offset, base) ((CPtr)((offset)<0 ? \
00097                 (pb)&fail_inst : ((pb)(base))+(long)(offset)*ZOOM_FACTOR))
00098 
00099 
00100 /* In the following, y is the number of bytes we want to read from fd   */
00101 #define get_obj_data(x,y)       (fread((char *)(x), 1, (y), fd))
00102 
00103 #define get_obj_byte(x)         (get_obj_data((x),1))
00104 #define get_obj_word(x)         (get_obj_data((x),OBJ_WORD_SIZE))
00105 #define get_obj_string(x,len)   (get_obj_data((x),(len)))
00106 
00107 #define get_obj_word_bb(x)    {get_obj_word(x) ; fix_bb(x) ; }
00108 #define get_obj_word_bbsig(x) {get_obj_word(x) ; fix_bb4(x) ;\
00109                                *(Cell *)(x) = makeint(*(int *)(x));}
00110 #define get_obj_word_bbsig_notag(x) {get_obj_word(x) ; fix_bb4(x) ; \
00111                                *(Integer *)(x) = *(int *)(x);}
00112                    
00113 
00114 /* === local declarations ============================================= */
00115 /* TLS: I think that l is the length of the indextab bucket chain when
00116    the hrec is part of the indextab array.  Otherwise, it is the
00117    pointer to the ep of the clause.  The link is the pointer to the
00118    next hrec in the bucket chain.  If last, link points to itself */
00119 
00120 struct hrec {
00121   long l;       
00122   CPtr link;
00123 } ;
00124 
00125 /*----------------------------------------------------------------------*/
00126 
00127 /* Number of entries in one "segment" of the index relocation table.
00128    The table isn't actually segmented, but it is allocated in
00129    chunks of this size. */
00130 #define NUM_INDEX_BLKS 256
00131 
00132 /* === variables also used in other parts of the system =============== */
00133 
00134 Psc global_mod; /* points to "global", whose ep is globallist */
00135 
00136 // First and last tifs / dispatch blocks.
00137 struct tif_list  tif_list = {NULL, NULL};
00138 struct TDispBlkHdr_t tdispblkhdr = {NULL, NULL};
00139 
00140 /* === working variables ============================================== */
00141 
00142 static pw   *reloc_table = NULL;
00143 static unsigned long reloc_table_size = 0;
00144 static pseg last_text = NULL;   /* permanent var, chain of text seg */
00145 static pseg current_seg;        /* starting address -- used for relocation */
00146 static CPtr *index_reloc;               /* index relocation table */
00147 static int  num_index_reloc;            /* number of chunks in index_reloc */
00148 static struct hrec *indextab;
00149 static TIFptr tab_info_ptr;
00150 static CPtr hptr;
00151 static pindex *index_block_chain;       /* index block chain */
00152 
00153 /* === return an appropriate hash table size ========================== */
00154 
00155 inline static int hsize(int numentry)
00156 {
00157   int i, j, temp;
00158 
00159   if (numentry > 16) temp = numentry; 
00160   else temp = 2 * numentry + 1;
00161   j = temp / 2 + 1;
00162   for (i = 2; i <= j; i++) {
00163     if ((i != temp) && ((temp % i) == 0)) {temp++; j = temp/2+1;}
00164   }
00165   return temp;
00166 }
00167 
00168 /* == unload a segment ================================================ */
00169 
00170 void unload_seg(pseg s)
00171 {
00172   pindex i1, i2 ;
00173   pseg prev, next ;
00174 
00175   /* free the index blocks */
00176   i1 = seg_index(s) ;
00177   while (i1) {
00178     i2 = i_next(i1) ;
00179     mem_dealloc((pb)i1, i_size(i1),COMPILED_SPACE);
00180     i1 = i2;
00181   }
00182   /* delete segment from segment dllist and dealloc it */
00183   next = seg_next(s) ;
00184   prev = seg_prev(s) ;
00185   if (next) seg_prev(next) = prev ;
00186   if (prev) seg_next(prev) = next ;
00187   if (last_text==s) last_text = prev ;
00188   mem_dealloc((pb)seg_hdr(s), seg_size(s),COMPILED_SPACE);
00189 }
00190 
00191 /*----------------------------------------------------------------------*/
00192 
00193 /* use heap top as temp place of hash link and entries; */
00194 /* heap top pointer is not alterred so nothing affects later heap use */
00195 
00196 inline static void inserth(CPtr label, struct hrec *bucket) 
00197 { 
00198   CPtr temp;
00199 
00200   bucket->l++;
00201   temp = (CPtr)&(bucket->link);
00202   if (bucket->l > 1) {
00203     temp = (CPtr)*temp;
00204     while ((CPtr)*temp != temp) 
00205       /*temp = (CPtr)*(++temp); */
00206       temp = (CPtr)*(temp+1);
00207   }
00208   *temp = (Cell)hptr;
00209   cell(hptr) = (Cell) label; hptr++;
00210   cell(hptr) = (Cell) hptr; hptr++;
00211 }
00212 
00213 /*----------------------------------------------------------------------*/
00214 
00215 Integer float_val_to_hash(Float Flt) {
00216   //  Float Fltval = Flt;
00217   return ((ID_BOXED_FLOAT << BOX_ID_OFFSET ) | (FLOAT_HIGH_16_BITS(Flt))) ^
00218     FLOAT_MIDDLE_24_BITS(Flt) ^ FLOAT_LOW_24_BITS(Flt);
00219 }
00220 
00221 /* this generates the index table, an array of pointers to hrecs (sort
00222    of, the typing is a little unclear).  Each bucket is a list of
00223    hrecs. */
00224 
00225 static int get_index_tab(FILE *fd, int clause_no)
00226 {
00227   long hashval, size, j;
00228   long count = 0;
00229   byte  type ;
00230   CPtr label;
00231   Integer ival;
00232   Cell val;
00233 
00234   size = hsize(clause_no);
00235 
00236   indextab = (struct hrec *)mem_alloc(size*sizeof(struct hrec),COMPILED_SPACE); 
00237 
00238   for (j = 0; j < size; j++) {
00239     indextab[j].l = 0;
00240     indextab[j].link = (CPtr)&(indextab[j].link);
00241   }
00242   for (j = 0; j < clause_no; j++) {
00243     get_obj_byte(&type);
00244     switch (type) {
00245     case 'i': get_obj_word_bbsig_notag(&ival);
00246       hashval = ihash((Cell) ival, size); 
00247       count += 9;
00248       break;
00249     case 'f': 
00250       get_obj_word_bbsig_notag(&ival);
00251       //      printf("sfloat: %f, %x\n",(*(float *)(&ival)), (*(Integer *)(&ival)) );
00252       val = float_val_to_hash(*(float *)(&ival));
00253       hashval = ihash((Cell) val, size); 
00254       hashval = ihash((Cell) val, size); 
00255       count += 9;
00256       break;
00257     case 'l': 
00258       hashval = ihash((Cell)(list_pscPair), size); 
00259       count += 5;
00260       break;
00261     case 'n': 
00262       hashval = ihash((Cell) 0, size);
00263       count += 5;
00264       break;
00265     case 'c': get_obj_word_bb(&ival);
00266       count += 9;
00267       val = (Cell)ival ;
00268       st_pscname(&val);
00269       hashval = ihash(val, size) ;
00270       break;
00271     case 's': get_obj_word_bb(&ival);
00272       count += 9;
00273       val = (Cell)ival ;
00274       st_ptrpsc(&val);
00275       hashval = ihash(val, size) ;
00276       break; 
00277     default:
00278       hashval = 0;
00279       xsb_exit("illegal format");
00280     }
00281 
00282     get_obj_word_bbsig_notag(&label);
00283     label = reloc_addr((Integer)label, seg_text(current_seg));
00284     inserth(label, &indextab[hashval]);
00285   }
00286   return count;
00287 }
00288 
00289 /*----------------------------------------------------------------------*/
00290 
00291 inline static pindex new_index_seg(int no_cells)
00292 {
00293   pindex new_i = (pindex)mem_alloc(SIZE_IDX_HDR + sizeof(Cell) * no_cells,COMPILED_SPACE ) ;
00294  
00295   /* initialize fields of new index segment header */
00296   i_next(new_i) = 0 ;
00297   i_size(new_i) = SIZE_IDX_HDR + sizeof(Cell) * no_cells ;
00298   
00299   /* append at tail of block chain */
00300   *index_block_chain = new_i ;
00301   index_block_chain = &i_next(new_i) ;
00302 
00303   return new_i ;
00304 }
00305 
00306 /*----------------------------------------------------------------------*/
00307 
00308 /* Once the indextab is set up (via get_index_tab()) traverse it to
00309    set up the try/retry/trust instructions using the l pointers */
00310 
00311 static void gen_index(xsbBool tabled, int clause_no, CPtr sob_arg_p, byte arity)
00312 {
00313   pindex new_i;
00314   CPtr   ep1, ep2, temp;
00315   int    j, size; 
00316  
00317   size = hsize(clause_no);
00318   new_i = new_index_seg(size);
00319 
00320   ep1 = i_block(new_i) ;
00321   cell(sob_arg_p) = (Cell)ep1 ;
00322   for (j = 0; j < size; j++) {
00323     if (indextab[j].l == 0) 
00324       cell(ep1) = (Cell) &fail_inst;
00325     else if (indextab[j].l == 1) {
00326       if (!tabled) {
00327         cell(ep1) = *(indextab[j].link);
00328       } else {  /* create tabletrysingle */
00329         cell(ep1) = cell(indextab[j].link);
00330         new_i = new_index_seg(3);
00331         ep2 = i_block(new_i);
00332         cell(ep1) = (Cell) ep2;
00333         temp = indextab[j].link;
00334         gentabletry(tabletrysingle, arity, *temp++, tab_info_ptr, ep2);
00335       }
00336     } else {
00337       /* otherwise create try/retry/trust instruction */
00338       new_i = new_index_seg(2*indextab[j].l+tabled);
00339       ep2 = i_block(new_i) ;
00340       cell(ep1) = (Cell) ep2 ;
00341       temp = (indextab[j].link) ;
00342       if (!tabled) {    /* generate "try" */
00343         gentry(try, arity, *temp, ep2);
00344       } else {
00345         gentabletry(tabletry, arity, *temp, tab_info_ptr, ep2);
00346       }
00347 
00348       for (temp++; *temp != (Cell)temp; temp++) {
00349         temp = (CPtr) cell(temp);               /* generate "retry" */
00350         gentry((tabled?tableretry:retry), arity, *temp, ep2);
00351       }
00352       /* change last "retry" to "trust" */
00353       cell_opcode(ep2-2) = tabled ? tabletrust : trust;
00354     }
00355     ep1++;
00356   }
00357 }
00358 
00359 /************************************************************************
00360 *                                                                       *
00361 *  load_text() loads the byte code intruction from a byte code file to  *
00362 *  the byte code program space.  References to indexes to the pcs table *
00363 *  are resolved with the use of the macro st_index.  New index relies   *
00364 *  on the symbol table array which is assigned values by load_sms.      *
00365 *  The routine assumes the current length 8/18/84 of byte code          *
00366 *  intructions when reading from the byte code file.                    *
00367 *  cf. inst_xsb.h for meaning of opcode types.
00368 *                                                                       *
00369 ************************************************************************/
00370 
00371 static int load_text(FILE *fd, int seg_num, int text_bytes, int *current_tab)
00372 {
00373   CPtr inst_addr, end_addr;
00374   int  current_opcode, oprand;
00375   Cell tab_config_hold; /* working pointer */
00376   
00377   *current_tab = -1;
00378   inst_addr = seg_text(current_seg);
00379   end_addr  = (CPtr)((pb)inst_addr + text_bytes * ZOOM_FACTOR);
00380   while (inst_addr<end_addr && get_obj_word(inst_addr) ) {
00381     current_opcode = cell_opcode(inst_addr);
00382     inst_addr ++;
00383     for (oprand=1; oprand<=4; oprand++) {
00384       switch (inst_table[current_opcode][oprand]) {
00385       case A:
00386       case V:
00387       case R:
00388       case P:
00389       case PP:
00390       case PPP:
00391       case PPR:
00392       case PRR:
00393       case RRR:
00394         break;
00395       case S:                         // structure
00396         get_obj_word_bb(inst_addr);
00397         st_ptrpsc(inst_addr);
00398         inst_addr ++;
00399         break;
00400       case C:                         // constant
00401         get_obj_word_bb(inst_addr);
00402         st_pscname(inst_addr);
00403         inst_addr ++;
00404         break;
00405       case L:                         // label
00406         get_obj_word_bbsig_notag(inst_addr);
00407         *(CPtr *)inst_addr = reloc_addr((Integer)cell(inst_addr),
00408                                         seg_text(current_seg));
00409         inst_addr ++;
00410         break;
00411       case G:                        // TLS: dont think this is used???
00412         get_obj_word_bb(inst_addr);
00413         st_pscname(inst_addr);
00414         inst_addr ++;
00415         break;
00416       case N: case F:                      // number, float, leave bit pattern
00417         get_obj_word_bbsig_notag(inst_addr);
00418         inst_addr ++;
00419         break;
00420       case B:                       // boxed integer
00421         get_obj_word_bbsig_notag(inst_addr);
00422         inst_addr ++;
00423         break;
00424       case I:                      // index of sob
00425         get_obj_word_bb(inst_addr);
00426         if (oprand==2) {        /* second operand of switchonbound */
00427           if (cell(inst_addr) >= (unsigned long)(NUM_INDEX_BLKS*num_index_reloc)) {
00428             int tmp_nir = num_index_reloc;
00429             num_index_reloc = (cell(inst_addr)/NUM_INDEX_BLKS)+1;
00430             index_reloc = (CPtr *)mem_realloc(index_reloc,tmp_nir,
00431                                               NUM_INDEX_BLKS*num_index_reloc*sizeof(CPtr),COMPILED_SPACE);
00432             if (!index_reloc) {
00433               xsb_error("Couldn't allocate index relocation space");
00434               return FALSE;
00435             }
00436           }
00437           index_reloc[cell(inst_addr)] = (CPtr)inst_addr;
00438         }
00439         else            /* third operand of switchonbound */
00440           cell(inst_addr) = hsize(cell(inst_addr));
00441         inst_addr ++;
00442         break;
00443       case X:                 // arg not used
00444         break;
00445       case T:                // tip ptr
00446         *current_tab = 1;       /* flag for load index */
00447         get_obj_word(&tab_config_hold);          /* space holder */
00448         cell(inst_addr) = (Cell)NULL; /* TIFptr will be set later when know PSC */
00449         inst_addr ++;
00450         break;
00451       default:
00452         break;
00453       }  /* switch */
00454     } /* for */
00455   }
00456   if (inst_addr != end_addr) {
00457     xsb_dbgmsg((LOG_DEBUG, "inst_addr %p, end_addr %p", inst_addr, end_addr));
00458     return FALSE;
00459   }
00460   else return TRUE;
00461 }  /* end of load_text */
00462 
00463 /*----------------------------------------------------------------------*/
00464 
00465 static void load_index(FILE *fd, int index_bytes, int table_num)
00466 {
00467   Integer index_bno, clause_no, t_len;
00468   byte    index_inst, arity;
00469   int     temp_space, count = 0;
00470   CPtr    sob_arg_p, temp_ptr;
00471 
00472   while (count < index_bytes) {
00473     get_obj_byte(&index_inst);
00474     get_obj_byte(&arity);
00475     get_obj_word_bb(&index_bno);
00476     sob_arg_p = index_reloc[index_bno];
00477     get_obj_word_bb(&clause_no);
00478     
00479     temp_space = clause_no * 2;
00480 #ifndef MULTI_THREAD
00481     if (top_of_localstk - hreg >= temp_space + 512)
00482       temp_ptr = hptr = hreg;
00483     else 
00484 #endif
00485        temp_ptr = hptr = (CPtr)mem_alloc(temp_space*sizeof(CPtr),COMPILED_SPACE);
00486     t_len = get_index_tab(fd, clause_no);
00487     
00488     gen_index((xsbBool)(table_num > 0), clause_no, sob_arg_p, arity);
00489     mem_dealloc(indextab,hsize(clause_no)*sizeof(struct hrec),COMPILED_SPACE);
00490 #ifndef MULTI_THREAD
00491     if (temp_ptr != hreg) mem_dealloc(temp_ptr,temp_space*sizeof(CPtr),COMPILED_SPACE);
00492 #else
00493     mem_dealloc(temp_ptr,temp_space*sizeof(CPtr),COMPILED_SPACE);
00494 #endif
00495     count += 10 + t_len;
00496   }
00497 }
00498 
00499 /*== the load_seg function =============================================*/
00500 
00501 static pseg load_seg(FILE *fd, int seg_num, int text_bytes, int index_bytes)
00502 {
00503    int current_tab;
00504 
00505    current_seg = (pseg) mem_alloc(ZOOM_FACTOR*text_bytes+SIZE_SEG_HDR,COMPILED_SPACE);
00506 
00507    /* Allocate first chunk of index_reloc */
00508    index_reloc = (CPtr *)mem_alloc(NUM_INDEX_BLKS*sizeof(CPtr),COMPILED_SPACE);
00509    if (!index_reloc) {
00510      xsb_error("Couldn't allocate index relocation space");
00511      return NULL;
00512    }
00513    num_index_reloc = 1;
00514 
00515    /* alloc space, include 16 bytes header */
00516    current_seg++;
00517    seg_next(current_seg)  = 0;
00518    seg_prev(current_seg)  = last_text;
00519    seg_index(current_seg) = 0;
00520    seg_size(current_seg)  = text_bytes*ZOOM_FACTOR + SIZE_SEG_HDR;
00521    /* fd = file; */
00522    if (!load_text(fd, seg_num, text_bytes, &current_tab)) {
00523      mem_dealloc((pb)seg_hdr(current_seg), text_bytes+SIZE_SEG_HDR,COMPILED_SPACE);
00524      return NULL;
00525    }
00526    index_block_chain = &seg_index(current_seg);
00527    load_index(fd, index_bytes, current_tab);
00528    mem_dealloc(index_reloc,NUM_INDEX_BLKS*sizeof(CPtr),COMPILED_SPACE);
00529    
00530    /* set text-index segment chain */
00531    if (last_text) seg_next(last_text) = current_seg;
00532    last_text = current_seg;
00533    return current_seg;
00534 }
00535 
00536 /************************************************************************/
00537 /*  Routines to check environment consistency.                          */
00538 /************************************************************************/
00539 
00540 #define T_NEW 3
00541 #define E_HIDDEN -1
00542 #define E_NOUSE -2
00543 
00544 static int env_check[4][5] = {
00545 /*                 T_EXPORT   T_LOCAL   T_IMPORTED   T_IMEX   T_GLOBAL  */
00546 /*======================================================================*/
00547 /* T_VISIBLE  */ { T_VISIBLE, T_HIDDEN, T_VISIBLE,  E_NOUSE, T_VISIBLE  },
00548 /* T_HIDDEN   */ { T_HIDDEN,  T_HIDDEN, E_HIDDEN,   E_NOUSE, T_VISIBLE  },
00549 /* T_UNLOADED */ { T_VISIBLE, E_HIDDEN, T_UNLOADED, E_NOUSE, T_UNLOADED },
00550 /* T_NEW      */ { T_VISIBLE, T_HIDDEN, T_UNLOADED, E_NOUSE, T_VISIBLE  }
00551 };
00552 
00553 void env_type_set(Psc psc, byte t_env, byte t_type, xsbBool is_new)
00554 {
00555   int env;
00556   byte type;
00557 
00558   if (is_new) {
00559     set_env(psc, env_check[T_NEW][t_env]);
00560     set_type(psc, t_type);
00561   } else {
00562     env = env_check[get_env(psc)][t_env];
00563     if (env < 0) {
00564       xsb_error("Environment conflict in the use of %s/%d !", 
00565                 get_name(psc), get_arity(psc));
00566       /* In the following I am not sure whether setting the environment */
00567       /* in the presense of an environment conflict error is the right  */
00568       /* thing to do!  But an "imported_from" vs "local" (non-exported) */
00569       /* symbol conflict must definitely be resolved in favour of the   */
00570       /* "local" declaration.                                           */
00571       if (env == E_HIDDEN) {
00572         if (t_env == T_IMPORTED) 
00573           /* Here the psc record of the symbol has already been created */
00574           /* by another module that imported (mistakenly) this symbol.  */
00575           set_env(psc, T_LOCAL);        
00576         else {/* We are trying to load a module
00577                 that imports sth not exported. */
00578           Psc mod_psc = get_data(psc);
00579           if (mod_psc != NULL) 
00580             fprintf(stderr,"               %s/%d is imported from %s but not exported\n",
00581                       get_name(psc),get_arity(psc),get_name(mod_psc));
00582           else fprintf(stderr,"               %s/%d is imported from somewhere but not exported\n",
00583                       get_name(psc),get_arity(psc));
00584         }
00585       }
00586     }
00587     else set_env(psc, env);
00588     type = get_type(psc);
00589     if (t_type && type && t_type != type) {
00590       if (t_type==T_UDEF && (type==T_PRED || type==T_DYNA || type==T_FORN)) ;
00591       else if (t_type==T_FORN && type==T_UDEF) set_type(psc, T_FORN);
00592       else xsb_error("incompatible types in the use of %s/%d (%x with %x)",
00593                      get_name(psc), get_arity(psc), type, t_type);
00594     } else set_type(psc, type | t_type);  
00595   }
00596 }
00597 
00598 /*----------------------------------------------------------------------*/
00599 
00600 unsigned int read_magic(FILE *fd)
00601 {
00602   unsigned int num;
00603 
00604   if (get_obj_word(&num) < 4) return 0;
00605   fix_bb4((byte *)&num);
00606   return num;
00607 }
00608 
00609 /*----------------------------------------------------------------------*/
00610 
00611 inline static void get_obj_atom(FILE *fd, VarString *atom)
00612 {
00613   byte x;
00614   unsigned int len;
00615   
00616   get_obj_data((&x),1);
00617   /* ``x'' gets the length of the string or > SHORT_LDOPTIONLEN.
00618      The latter means we have a long atom.
00619      In this case, the length is stored in 4 bytes & we use get_obj_word_bb */
00620   if (x > SHORT_LDOPTIONLEN) { /* handle unusual case specially */
00621     get_obj_word_bb(&len);
00622     /* xsb_dbgmsg(("get_obj_len = %d... Case is not handled yet!\n",len)); */
00623   } else
00624     len = x;
00625 
00626   XSB_StrEnsureSize(atom,len+1);
00627   get_obj_string(atom->string, len);
00628   atom->length = len;
00629   XSB_StrNullTerminate(atom);
00630 }
00631 
00632 /*----------------------------------------------------------------------*/
00633 
00634 static xsbBool load_one_sym(FILE *fd, Psc cur_mod, int count, int exp)
00635 {
00636   static XSB_StrDefine(str);
00637   int  is_new;
00638   byte t_arity, t_type, t_env, t_defined;
00639   Pair temp_pair;
00640   Psc  mod;
00641 
00642   get_obj_byte(&t_env);
00643   /* this simple check can avoid worse situations in case of compiler bugs */
00644   if (t_env&0x80)
00645     xsb_abort("[LOADER] The loaded object file %s%s is corrupted",
00646               cur_mod->nameptr, XSB_OBJ_EXTENSION_STRING);
00647 
00648   get_obj_byte(&t_type);  t_defined = t_type & T_DEFI; t_type = t_type & ~T_DEFI;
00649   get_obj_byte(&t_arity);
00650   get_obj_atom(fd, &str);
00651   if (t_type == T_MODU)
00652     temp_pair = insert_module(0, str.string);
00653   else {
00654     if ((t_env&0x7) == T_IMPORTED) {
00655       byte t_modlen;
00656       char modname[MAXNAME+1];
00657 
00658       get_obj_byte(&t_modlen);
00659       get_obj_string(modname, t_modlen);
00660       modname[t_modlen] = '\0';
00661       temp_pair = insert_module(0, modname);
00662       mod = temp_pair->psc_ptr;
00663     } else if ((t_env&0x7) == T_GLOBAL) 
00664       mod = global_mod;
00665     else 
00666       mod = cur_mod;
00667     temp_pair = insert(str.string, t_arity, mod, &is_new);
00668 /*     if (is_new && (t_env & 0x7)==T_IMPORTED) */
00669     /* make sure all data fields of predicates PSCs point to 
00670        their corresponding module */
00671     if (is_new ||
00672         (get_type(temp_pair->psc_ptr) == T_ORDI &&
00673          (t_type == T_DYNA || t_type == T_PRED || t_type == T_UDEF) &&
00674          get_data(temp_pair->psc_ptr) == NULL)) {
00675       set_data(temp_pair->psc_ptr, mod);
00676     }
00677     env_type_set(temp_pair->psc_ptr, (byte)(t_env&(T_ENV|T_GLOBAL)), t_type, (xsbBool)is_new);
00678 
00679     if (is_new || !get_shared(temp_pair->psc_ptr)) {
00680       if (!(get_ep(temp_pair->psc_ptr)) && (*(pb)get_ep(temp_pair->psc_ptr) == switchonthread))
00681         xsb_warn("Shared declaration ignored for %s/%d\n",
00682                 get_name(temp_pair->psc_ptr),get_arity(temp_pair->psc_ptr));
00683       else set_shared(temp_pair->psc_ptr, (t_env&T_SHARED));
00684     }
00685 
00686     if (t_env&T_TABLED_SUB_LOADFILE) 
00687       set_tabled(temp_pair->psc_ptr,((t_env&T_TABLED_VAR) | T_TABLED_SUB));
00688     else if (is_new || t_defined)
00689       set_tabled(temp_pair->psc_ptr,(t_env&T_TABLED_VAR));
00690     //    printf("sym loaded: %s/%d, tabled=%x, t_env=%x, t_type=%x, t_defined=%x\n",get_name(temp_pair->psc_ptr),get_arity(temp_pair->psc_ptr),get_tabled(temp_pair->psc_ptr),t_env,t_type,t_defined);
00691     /* dsw added following, maybe wrongly */
00692     if (exp && (t_env&0x7) == T_EXPORTED) {
00693       /* xsb_dbgmsg(("exporting: %s from: %s",name,cur_mod->nameptr)); */
00694       if (is_new) 
00695         set_data(temp_pair->psc_ptr, mod);
00696       link_sym(temp_pair->psc_ptr, (Psc)flags[CURRENT_MODULE]);
00697     }
00698   }
00699   if (!temp_pair) return FALSE;
00700   
00701   reloc_table[count] = (pw)temp_pair;
00702   return TRUE;
00703 }  /* load_one_sym */
00704 
00705 /************************************************************************
00706 *                                                                       *
00707  Load_syms loads a symbol table from a byte code file into an
00708  appropriate format in the psc table (i.e. e.g. a chain, or a hash
00709  table of chains if the module is global).  Among other functions, it
00710  
00711  -- resolves entry points for byte code intructions (call to
00712  relloc_addr), and maintains a tableau so that instructions with
00713  indices into the psc table may have those indices resolved before
00714  loading them in the intruction array (byte code program space).  The
00715  intructions are loaded by a separate function.  
00716 
00717  -- initizlizes psc records (via insert and sub-functions) so that the
00718  default entry points of new, imported predicates is the undefined
00719  predicate handler.  This e.p. will be over-written whenever the
00720  module for the predicate is loaded.
00721 
00722 *                                                                       *
00723 ************************************************************************/
00724 
00725 static xsbBool load_syms(FILE *fd, int psc_count, int count, Psc cur_mod, int exp)
00726 {
00727   int i;
00728   
00729   reloc_table = (pw *) mem_calloc((psc_count), sizeof(pw),COMPILED_SPACE);
00730   reloc_table_size = psc_count*sizeof(pw);
00731   /* xsb_dbgmsg(("reloc_table %x,psc_count %d",reloc_table,psc_count)); */
00732 
00733   for (i = count; i < psc_count; i++) {
00734     if (!load_one_sym(fd, cur_mod, i, exp)) return FALSE;
00735   }
00736   return TRUE;
00737 }
00738 
00739 #ifdef MULTI_THREAD
00740 
00741 static void new_tdispblk(CTXTdeclc TIFptr *instr_ptr, Psc psc) {
00742   struct TDispBlk_t *tdispblk;
00743 
00744   if (!(tdispblk = (struct TDispBlk_t *) 
00745         mem_calloc(sizeof(struct TDispBlk_t)+MAX_THREADS*sizeof(Cell),1,COMPILED_SPACE)))
00746     xsb_exit("No space for table dispatch block");  /* never deallocated */
00747   
00748   SYS_MUTEX_LOCK( MUTEX_TABLE );
00749 
00750   if (tdispblkhdr.firstDB) tdispblkhdr.firstDB->PrevDB = tdispblk;
00751   tdispblk->NextDB = tdispblkhdr.firstDB;
00752   tdispblkhdr.firstDB = tdispblk;
00753   if (!tdispblkhdr.lastDB) tdispblkhdr.lastDB = tdispblk;
00754 
00755   tdispblk->psc_ptr = psc;
00756   tdispblk->method = DISPATCH_BLOCK;
00757   tdispblk->MaxThread = MAX_THREADS;
00758   *instr_ptr = (TIFptr)tdispblk;
00759 
00760   SYS_MUTEX_UNLOCK( MUTEX_TABLE );
00761 
00762 }
00763 
00764 #endif
00765 
00766 /************************************************************************/
00767 static byte *loader1(CTXTdeclc FILE *fd, int exp)
00768 {
00769   char name[FOREIGN_NAMELEN], arity;
00770   byte name_len;
00771   int  is_new, seg_count;
00772   unsigned long psc_count;
00773   Integer text_bytes, index_bytes;
00774   pseg seg_first_inst, first_inst;
00775   Psc cur_mod;
00776   Pair ptr;
00777   TIFptr *instruct_tip;
00778  
00779   seg_count = 0; first_inst = 0;
00780   get_obj_byte(&name_len);
00781 
00782   if (name_len >= FOREIGN_NAMELEN)
00783     xsb_abort("[LOADER] Foreign module name is too long");
00784 
00785   get_obj_string(name, name_len);
00786   name[(int)name_len] = 0;
00787   if (name_len==0) cur_mod = global_mod;
00788   else {
00789     ptr = insert_module(T_MODU, name);
00790     cur_mod = ptr->psc_ptr;
00791   }
00792   get_obj_word_bb(&psc_count);
00793   if (!load_syms(fd, (int)psc_count, 0, cur_mod, exp)) 
00794     return FALSE;
00795   /*    xsb_dbgmsg(("symbol table of module %s loaded", name)); */
00796   do {
00797     /*          xsb_dbgmsg(("Seg count: %d",seg_count)); */
00798     if (read_magic(fd) != 0x11121306) break;
00799     seg_count++;
00800     /*          xsb_dbgmsg(("Seg count: %d",seg_count)); */
00801     /* get the header of the segment */
00802     get_obj_byte(&arity);
00803     get_obj_byte(&name_len);
00804 
00805     if (name_len >= FOREIGN_NAMELEN)
00806       xsb_abort("[LOADER] Module name is too long");
00807 
00808     get_obj_string(name, name_len);
00809     name[(int)name_len] = 0;
00810     get_obj_word_bb(&text_bytes);
00811     /*          xsb_dbgmsg(("Text Bytes %x %d",text_bytes,text_bytes));*/
00812     get_obj_word_bb(&index_bytes);
00813     /* load the text-index segment */
00814     seg_first_inst = load_seg(fd,seg_count,text_bytes,index_bytes);
00815     if (!seg_first_inst) return FALSE;
00816     if (seg_count == 1) first_inst = seg_first_inst;
00817     /* 1st inst of file */
00818     /* set the entry point of the predicate */
00819     ptr = insert(name, arity, cur_mod, &is_new);
00820     switch (get_type(ptr->psc_ptr)) {
00821     case T_ORDI:
00822     case T_UDEF:
00823       if (strcmp(name, "_$main")!=0) {
00824         set_type(ptr->psc_ptr, T_PRED);
00825         set_ep(ptr->psc_ptr, (pb)seg_first_inst);
00826         if (xsb_profiling_enabled)
00827           add_prog_seg(ptr->psc_ptr, (pb)seg_first_inst, text_bytes);
00828       }
00829       instruct_tip = get_tip_or_tdisp(ptr->psc_ptr);
00830       if (instruct_tip != NULL) {
00831 #ifdef MULTI_THREAD
00832         if (get_tabled(ptr->psc_ptr) && !get_shared(ptr->psc_ptr)) {
00833           new_tdispblk(CTXTc instruct_tip, ptr->psc_ptr);
00834         } else
00835 #endif
00836           *instruct_tip = New_TIF(CTXTc (ptr->psc_ptr));
00837       }
00838       //printf("table: %s/%d, psc_tabled: %x\n",get_name(ptr->psc_ptr),get_arity(ptr->psc_ptr),get_tabled(ptr->psc_ptr));
00839       break;
00840     case T_PRED:
00841       if (strcmp(name, "_$main")!=0) {
00842         if (xsb_profiling_enabled)
00843           remove_prog_seg((pb)get_ep(ptr->psc_ptr));
00844         unload_seg((pseg)get_ep(ptr->psc_ptr));
00845         set_ep(ptr->psc_ptr, (pb)seg_first_inst);
00846         if (xsb_profiling_enabled)
00847           add_prog_seg(ptr->psc_ptr, (pb)seg_first_inst, text_bytes);
00848       }
00849       instruct_tip = get_tip_or_tdisp(ptr->psc_ptr);
00850       if (instruct_tip != NULL) {
00851 #ifdef MULTI_THREAD
00852         if (get_tabled(ptr->psc_ptr) && !get_shared(ptr->psc_ptr)) {
00853           new_tdispblk(CTXTc instruct_tip, ptr->psc_ptr);
00854         } else
00855 #endif
00856           *instruct_tip = New_TIF(CTXTc (ptr->psc_ptr));
00857       }
00858       /* set data to point to module's psc */
00859       set_data(ptr->psc_ptr, cur_mod);
00860       break;
00861     case T_DYNA:
00862       unload_seg(seg_first_inst);
00863       xsb_abort("[LOADER] Trying to compile a dynamic predicate, %s/%d",
00864                 name, arity);
00865       return NULL;
00866     default:
00867       unload_seg(seg_first_inst);
00868       xsb_abort("[LOADER] The predicate %s/%d cannot be loaded", name, arity);
00869       return NULL;
00870     }
00871   } while (1==1);
00872   /*
00873     xsb_dbgmsg(("The first instruction of module %s is %x",
00874     get_name(cur_mod), first_inst));
00875   */
00876   return (pb)first_inst;
00877 } /* loader1 */
00878 
00879 /************************************************************************/
00880 /*  Routines for the foreign language interface.                        */
00881 /************************************************************************/
00882 
00883 #ifdef FOREIGN
00884 
00885 /* ldoption is specified in .H file and indicates library files, etc
00886    that need to be loaded. */
00887 static byte *loader_foreign(char *filename, FILE *fd, int exp)
00888 {
00889   byte name_len, *instr;
00890   char name[FOREIGN_NAMELEN];
00891   static XSB_StrDefine(ldoption);
00892   unsigned long psc_count;
00893   Psc  cur_mod;
00894   Pair ptr;
00895 
00896   get_obj_byte(&name_len);
00897   if (name_len >= FOREIGN_NAMELEN) {
00898     xsb_error("[LOADER] Foreign module name is too long");
00899     return FALSE;
00900   }
00901   get_obj_string(name, name_len);
00902   name[name_len] = 0;
00903   get_obj_atom(fd, &ldoption);
00904   ptr = insert_module(T_MODU, name);
00905   cur_mod = ptr->psc_ptr;
00906   get_obj_word_bb(&psc_count);
00907   if (!load_syms(fd, (int)psc_count, 0, cur_mod, exp)) return FALSE;
00908   instr = load_obj(filename, cur_mod, ldoption.string);
00909   return instr;
00910 } /* end of loader_foreign */
00911 #endif
00912 
00913 /************************************************************************/
00914 /*                                                                      */
00915 /* Loads the file into permanent space.                                 */
00916 /* Data segment first (mixed psc entries and name strings), then text   */
00917 /* segment.  Under normal circumstances it returns the address of first */
00918 /* instruction; if errors occur, it returns NULL.                       */
00919 /*                                                                      */
00920 /************************************************************************/
00921 
00922 static int warned_old_obj = 0;  /* warned the user about old object files ? */
00923 
00924 /* See description of magic numbers in foreign.P -- Is ...5 obsolete? */
00925 byte *loader(CTXTdeclc char *file, int exp)
00926 {
00927   FILE *fd;           /* file descriptor */
00928   unsigned int magic_num;
00929   byte *first_inst = NULL;
00930 
00931   fd = fopen(file, "rb"); /* "b" needed for DOS. -smd */
00932   if (!fd) return NULL;
00933   if (flags[HITRACE]) xsb_mesg("\n     ...... loading file %s", file);
00934   magic_num = read_magic(fd);
00935 
00936   if (magic_num == 0x11121304 || magic_num == 0x11121305) {
00937     if (!warned_old_obj) {
00938       xsb_warn("File \"%s\"\n"
00939                "\t   has old byte code format, which is likely to cause\n"
00940                "\t   unpredictable behavior.\n"
00941                "\t   Please recompile the file with XSB version > 2.01.",
00942                file);
00943       warned_old_obj = 1;
00944     }
00945   }
00946 
00947   if (magic_num == 0x11121307 || magic_num == 0x11121305)
00948     first_inst = loader1(CTXTc fd,exp);
00949   else if (magic_num == 0x11121308 || magic_num == 0x11121309) {
00950 #ifdef FOREIGN
00951     first_inst = loader_foreign(file, fd, exp);
00952 #else
00953     xsb_abort("Loading a foreign file: %s", file);
00954 #endif
00955   }
00956   else {
00957     xsb_abort("File: %s does not have proper byte code format...\n%s",
00958               file, "\t Please remove it and then recompile");
00959     first_inst = NULL;
00960   }
00961 
00962   fclose(fd);
00963   if (reloc_table) {
00964     mem_dealloc(reloc_table,reloc_table_size,COMPILED_SPACE);
00965     reloc_table = 0;
00966   }
00967   return first_inst;
00968 } /* loader */
00969 
00970 #ifdef MULTI_THREAD
00971 /* TLS: not currently used.
00972 | void thread_free_tab_blks(CTXTdecl) {
00973 |   struct TDispBlk_t *tdispblk;
00974 |   TIFptr tip;
00975 | 
00976 |   SYS_MUTEX_LOCK( MUTEX_TABLE );
00977 |   for (tdispblk=tdispblkhdr.firstDB ; tdispblk != NULL ; tdispblk=tdispblk->NextDB) {
00978 |     if (th->tid <= tdispblk->MaxThread) {
00979 |       tip = (&(tdispblk->Thread0))[th->tid];
00980 |       if (tip) {
00981 |       delete_predicate_table(CTXTc tip);
00982 |       (&(tdispblk->Thread0))[th->tid] = (TIFptr) NULL;
00983 |       }
00984 |     }
00985 |   }
00986 |   SYS_MUTEX_UNLOCK( MUTEX_TABLE );
00987 | }
00988 */
00989 #endif

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