vmemory.c
上传用户:dgyhgb
上传日期:2007-01-07
资源大小:676k
文件大小:51k
源码类别:

SQL Server

开发平台:

Unix_Linux

  1. /*
  2.  *  vmemory.c  - simulated virtual memory manager of GNU SQL compiler
  3.  *
  4.  *  This file is a part of GNU SQL Server
  5.  *
  6.  *  Copyright (c) 1996, 1997, Free Software Foundation, Inc
  7.  *  Developed at the Institute of System Programming, Russia
  8.  *  This file is written by Michael Kimelman
  9.  *
  10.  *  This program is free software; you can redistribute it and/or modify
  11.  *  it under the terms of the GNU General Public License as published by
  12.  *  the Free Software Foundation; either version 2 of the License, or
  13.  *  (at your option) any later version.
  14.  *
  15.  *  This program is distributed in the hope that it will be useful,
  16.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  *  GNU General Public License for more details.
  19.  *
  20.  *  You should have received a copy of the GNU General Public License
  21.  *  along with this program; if not, write to the Free Software
  22.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23.  *
  24.  *  Contact:  gss@ispras.ru
  25.  *
  26.  */
  27. /* $Id: vmemory.c,v 1.247 1997/04/24 17:45:01 kml Exp $ */
  28. /*=====================================================================
  29.   
  30.                     Simulated virtual memory 
  31.                                 
  32.         1. User interface
  33.         Simululated virtual memory  looks from the  user point of
  34. view as a   set  of VM  segments, each  of  them assotiated  with
  35. independently compiled or  used piece  of  interpretator code  or
  36. compiler tree (just like object modules in ordinary OS). User can
  37. create, link, unlink  and  store out segments during  the program
  38. execution.  Virtual space  is shared by  all  linked segments and
  39. each   of  them  assotiated   with  it's   own   range of virtual
  40. addresses. To allow intersegment references each segment contains
  41. table  of  relocable virtual  addresses  and table of names which
  42. segment exports. Relocation  table used by  VM manager to correct
  43. listed addresses when the segment linked.
  44.         VM  manager support    special  conception of   "current"
  45. segment, allowing local references inside  segments.  The segment
  46. marked as a  current by 'create', 'link' or 'set_current_segment'
  47. calls. 'vmemory.h'  included   some  specific  comment   to  part
  48. of VMinterface calls.
  49.         2. Virtual Memory Inside
  50.         Virtual  memory      is  realized  like    "segment-page"
  51. adressation in computer. But in   this case it was impossible  to
  52. use fixed    size   pages.  So   memory  divided  to  "segments",
  53. associated  with independently   compiled or used   piece of code
  54. (like object modules).  Each segment  represented by small header
  55. and one-directional list  of pages of different size,  associated
  56. to pieces  of virtual memory. Each virtual  memory page  (vmp) in
  57. turn  has  page descriptor contained pointer  to  page data area,
  58. offset of the page in segment (so there can be holes in vm space)
  59. and other page realated  information. Space on the page allocated
  60. by  a virtual memory  blocks (vmb). Each vmb descriptor specifies
  61. the vmb size (while  consequece of free  vmbs appears it's joined
  62. to one) and mode (alignment of  data or 0  for free vmb). Because
  63. each  free vmb has  to contain  at  least  4 bytes of  free space
  64. (otherwise it doesn't worth to consider it as a free space), this
  65. space used for storing pointers needed  for bidirectional link of
  66. free   blocks.  Using relative   offsets  as a  pointers for this
  67. purpose allows to join pages'  areas (when it's needed) without a
  68. problem.
  69.         The only one available by  user element of VM is segment.
  70. VM manager is  responsible for  creating, storing, unlinking  and
  71. linking  segments and  holds for  this  purpose internal  segment
  72. table (segment_table). Virtual address (i4_t) of any data contain
  73. segment identifier (index  of segment  in segment table),   which
  74. occupied high bits of address, and offset  in segment.  Number of
  75. bits used for offset defined by  SEGMENT_OFFSET_SIZE and equal 20
  76. now.   Segment identifier 0 is used  for reference inside current
  77. segment (there  is a  special  identifier of  "current" segment).
  78. Size of page limited now by 64K  (16bit offset). For intersegment
  79. addressation we use relocation table (contain relocable addresses
  80. inside segment), and  exported name table (contain exported names
  81. and assotiated with  them relocable addresses of exported objects
  82. - structures of data, routines   and so on). The information   of
  83. exported data can  be got by  direct  'resolve_reference' call as
  84. well  as by using special form  of  address used for dynamic name
  85. resolution    (I   mean  'vpointer'    resolves   these cases  by
  86. itself).    This    kind    of    addresses   is     created   by
  87. 'external_reference'   call.  Actually  it's  almost  ordinal  VM
  88. pointer to locally saved imported name, but segment identifier of
  89. it is bit inverted (~seg_id).
  90. ==================================================================*/
  91.      
  92. #include "setup_os.h"
  93. #include "xmem.h"
  94. #include "vmemory.h"
  95. #include "sql_decl.h"
  96. #include <assert.h>
  97. /*------------------------------------------------------*/
  98. #define SEGMENT_OFFSET_SIZE      20
  99. /* Maximum size of the virtual segment */
  100. #define SEGMENT_LIMIT           (1<<SEGMENT_OFFSET_SIZE)
  101. #define SEG_ID(adr)    ((adr)>>SEGMENT_OFFSET_SIZE)
  102. #define SEG_BASE(s_id) ((s_id)<<SEGMENT_OFFSET_SIZE)
  103. #define SEG_IND(adr)   vm_segment_ind(adr)
  104. #define SEG_OFF(adr)   (adr&(SEGMENT_LIMIT-1))
  105. #define SEG_PTR(adr)   (&(segment_table.entries[SEG_IND(adr)]))
  106. #if HAVE_LONG_DOUBLE
  107. #  define HUGEST_MACHINE_TYPE     long double
  108. #  define PAGE_ALIGN              sizeof(HUGEST_MACHINE_TYPE)
  109. #else
  110. #  define HUGEST_MACHINE_TYPE     double
  111. #  define PAGE_ALIGN              sizeof(HUGEST_MACHINE_TYPE)
  112. #endif
  113. int debug_vmemory = 0;
  114. #define DV(mask) (debug_vmemory & (mask))
  115. typedef i2_t Offset;           /* offset on the page, computed in bytes */
  116. /* virtual memory block descriptor -- "VMB descr"  */
  117. typedef struct area
  118. {
  119.   i2_t size;
  120.   i2_t mode;                   /* 0-free; other 'mode' bytes alignment */
  121. } *pdesc;
  122. #define DSC_SZ sizeof(struct area)
  123. /* VMB descr for unused space */
  124. typedef struct f_area
  125. {
  126.   struct area desc;
  127.   Offset      next,             /* double linked list of free blocks */
  128.               prev;
  129. } *pdescf;
  130. #define FDS_SZ sizeof(struct f_area)
  131. #define NEXT(ds)  ((pdescf)((byte*)ds+ds->next))
  132. #define PREV(ds)  ((pdescf)((byte*)ds+ds->prev))
  133. /********* Page **********************/
  134. typedef struct virtual_memory_page *P_vmpage;
  135. struct virtual_memory_page/* VMP  ===========================================*/
  136. {                         /*                                                 */
  137.   P_vmpage  next;         /* points to the next page descriptor              */
  138.   i4_t       base;         /* offset of the page in  segment                  */
  139.   i4_t       size;         /* size of the current page                        */
  140.   i4_t       used;         /* size of used space on the page                  */
  141.   i4_t       free_ptr;     /* points to free space - just after descriptor of */
  142.                           /* the first free vmb on the page                  */
  143.   i4_t       lfree_ptr;    /* points to free space - just after descriptor of */
  144.                           /* the last free vmb on the page                   */
  145.   i4_t       flags;        /* nonzero to avoiding freeing memory-the same     */
  146.                           /* meaning as 'dont_remove' below                  */
  147.   byte     *page;         /* have to be aligned to "i4_t double"             */
  148. };                        /*=================================================*/
  149. /********* Segment *******************/
  150. typedef struct            /* Relocation table================================*/
  151. {                         /*                                                 */
  152.   i4_t  used_ent;         /* number of used entries                          */
  153.   i4_t  ent_nmb;          /* number of entries                               */
  154.   i4_t  dont_remove;      /* nonzero if the memory, used by table, will be   */
  155.                           /* fried later                                     */
  156.   VADR *entries;          /* scalable array with local addresses of          */
  157.                           /* relocable pointers                              */
  158. } reloc_tbl;              /*=================================================*/
  159. typedef struct            /* Name table - this table contains names and =====*/
  160. {                         /* adresses of entry points: routines amd variables*/
  161.   i4_t    ent_nmb;        /* number of entries                               */
  162.   i4_t    dont_remove;    /* nonzero if the memory, used by table, will be   */
  163.                           /* fried later                                     */
  164.   struct                  /*                                                 */
  165.   {                       /*                                                 */
  166.     VADR   name;          /* address in the segment of the exported name     */
  167.     VADR   adr;           /* relocable address in the segment of the object  */
  168.   }      *entries;        /* scalable array of exported entries              */
  169. } export_tbl;             /*=================================================*/
  170. typedef struct virtual_memory_segment /* Virtual memory segment descriptor ==*/
  171. {                                 /*                                         */
  172.   P_vmpage    base;               /* pointer to the chain of segment's pages */
  173.   i4_t        used;               /*                                         */
  174.   reloc_tbl   relocation_table;   /* relocation table of the segment         */
  175.   export_tbl  export_table;       /* exported names table                    */
  176.   void       *loaded_block_address; /* address of the segment - used for     */
  177.                                   /* latter freeing memory if it was loaded  */
  178.                                   /* from outside as a whole piece           */
  179. } vmsegment;                      /*=========================================*/
  180. /********** Global manipulation tables *********/
  181. typedef struct            /* Local table of loaded segments  ================*/
  182. {                         /*                                                 */
  183.   i4_t       ent_nmb;     /* number of segments                              */
  184.   i4_t       dont_remove; /* used just for compatibility in macro            */
  185.   i4_t       current;     /* number (identifier) of the current segment -    */
  186.                           /* used if segment id in VADR==0                   */
  187.   vmsegment *entries;     /* scalable array of segment's descriptors -       */
  188.                           /* Attention! entries[0] never used                */
  189. } SEGM_TBL;               /*=================================================*/
  190. static SEGM_TBL segment_table =
  191. {0, 0, 0, NULL};
  192. #define REALLOC(p,sz) l_realloc(p,sz)
  193. #define FREE(p)       l_free(p)
  194. #ifndef USE_XVM
  195. #define MALLOC(size)   xmalloc(size)
  196. #define AREALLOC(p,sz) xrealloc(p,sz)
  197. #define AFREE(p)       xfree(p)
  198. #else
  199. static void *lmalloc(i4_t size);
  200. static void *lrealloc(void *p,i4_t size);
  201. static void  lfree __P((void *p));
  202. static VADR xmemory_segment = VNULL;
  203. #define MALLOC(size)  lmalloc(size)
  204. #define AREALLOC(p,sz) lrealloc(p,sz)
  205. #define AFREE(p)       lfree(p)
  206. #endif
  207. #define TBL_PORTION 32
  208. #define TBL_ELEM_SZ(tbl) sizeof(*(tbl.entries))
  209. #define TBL_SIZE(tbl)  
  210. ((TBL_PORTION+(tbl.ent_nmb))*TBL_ELEM_SZ(tbl))
  211. #define ADD_ENTRY(tbl) 
  212. {
  213.   if(tbl.ent_nmb%TBL_PORTION==0)
  214.     {
  215.       register void *tmp_ptr=MALLOC(TBL_SIZE(tbl)); 
  216.       if (tbl.ent_nmb >0)
  217.         {
  218.           bcopy(tbl.entries,tmp_ptr,TBL_ELEM_SZ(tbl)*tbl.ent_nmb); 
  219.           if(tbl.dont_remove)tbl.dont_remove=0;
  220.           else               FREE((void*)(tbl.entries)); 
  221.         }
  222.       tbl.entries=tmp_ptr;
  223.     }
  224.   tbl.ent_nmb++; 
  225. }
  226. /************************************************************************
  227. ************  CACHE  *****************************************************
  228. ************************************************************************/
  229. static void *
  230. cache_proc(VADR n, void *p,i4_t action)
  231. {
  232. #define CACHE_SIZE 5
  233.   struct c_el {
  234.     VADR  v;
  235.     void *p;
  236.   };
  237.   static   struct c_el cache[CACHE_SIZE];
  238.   register i4_t         i;
  239.   switch(action)
  240.     {
  241.     case -1: /* flush */
  242. #define  flush_cache() cache_proc(VNULL, NULL, -1)
  243.       for (i = 0; i < CACHE_SIZE; i ++ )
  244.         cache[i].v = 0;
  245.       return NULL;
  246.     case 0: /* check */
  247. #define  check_cache(n) cache_proc(n, NULL, 0)
  248.       assert(n);
  249.       i = (i4_t)(( n >> 4 ) % CACHE_SIZE);
  250.       return ( n == cache[i].v ? cache[i].p : NULL );
  251.     case 1: /* update */
  252. #define  update_cache(n,p) cache_proc(n,p, 1)
  253.       i = (i4_t)(( n >> 4 ) % CACHE_SIZE);
  254.       cache[i].v = n;
  255.       cache[i].p = p;
  256.       return NULL;
  257.     default:
  258.       assert("vm cache_proc unrecognized action");
  259.     }
  260.   return NULL;
  261. #undef CACHE_SIZE
  262. }
  263. static void *
  264. l_realloc(void *p,i4_t size)
  265. {
  266.   flush_cache();
  267.   return AREALLOC(p,size);
  268. }
  269. static void
  270. l_free(void *p)
  271. {
  272.   flush_cache();
  273.   AFREE(p);
  274. }
  275. /************************************************************************
  276. **************************************************************************
  277. ************************************************************************/
  278. static i4_t enable_auto_create = 0;
  279. static i4_t force_free         = 0;
  280. static long
  281. vm_segment_ind (register VADR ptr)
  282. {
  283.   register i4_t p = SEG_ID (ptr);
  284.   if (p == 0)
  285.     {
  286.       if (segment_table.current > 0)
  287. return segment_table.current;
  288.       else if (enable_auto_create)
  289. {
  290.   fprintf (STDERR, "Virtual memory handler: warning :"
  291.    "auto-creating new segmentn");
  292.   create_segment ();
  293.   p = segment_table.current;
  294. }
  295.       else
  296. return p;
  297.     }
  298.   else if (p < 0)
  299.     p = ~p;
  300.   if (p == 0 || p >= segment_table.ent_nmb || !segment_table.entries[p].used)
  301.     yyfatal ("Virtual memory handler: incorrect segment identifier");
  302.   return p;
  303. }
  304. static P_vmpage 
  305. check_for_null_page (register P_vmpage vmp)
  306. {
  307.   if (vmp && vmp->size == 0)
  308.     {
  309.       register P_vmpage vmp1 = vmp;
  310.       vmp = vmp->next;
  311.       vmp1->next = 0;
  312.       if (vmp1->flags == 0)     /* in other case it'll be freed later */
  313.         {
  314.           FREE (vmp1->page);
  315.           FREE (vmp1);
  316.         }
  317.     }
  318.   return vmp;
  319. }
  320. static i4_t 
  321. check_free_memory_on_page (register P_vmpage vmp)
  322. {
  323.   register pdescf a;
  324.   register i4_t    sz = 0;
  325.   assert(!vmp->free_ptr == !vmp->lfree_ptr);
  326.   assert(vmp->free_ptr>=0 && vmp->free_ptr<vmp->size);
  327.   assert(vmp->lfree_ptr>=0 && vmp->lfree_ptr<vmp->size);
  328.   if (DV(0xf) <= 2 )
  329.     return vmp->size - vmp->used;
  330.   if (vmp->free_ptr )
  331.     for (a = (pdescf) (vmp->page + vmp->free_ptr - DSC_SZ);
  332.          a;
  333.          a = a->next ? NEXT (a) : 0)
  334.       {
  335.         if (!(a->desc.size > 0))
  336.           yyfatal ("Virtual memory handler: memory block size <=0 ");
  337.         if (a->desc.mode > 0)
  338.           yyfatal ("Virtual memory handler: VMB mode !=0 in free list");
  339.         sz += a->desc.size + DSC_SZ;
  340.       }
  341.   assert (vmp->used + sz == vmp->size);
  342.   return sz;
  343. }
  344. static int
  345. check_integrity (register P_vmpage vmp)
  346. {
  347.   register pdesc a;
  348.   register i4_t   sz = 0;
  349.   if (vmp == 0)
  350.     return 0;
  351.   vmp->next = check_for_null_page (vmp->next);
  352.   if (vmp->page == 0)
  353.     {
  354.       assert (vmp->used == 0 && vmp->size == 0);
  355.       return 0;
  356.     }
  357.   
  358.   sz = vmp->size - vmp->used;
  359.   
  360.   if (DV(0xf) > 1)
  361.     {
  362.       for (sz = 0,a = (pdesc) (vmp->page);
  363.            (byte *) a < (vmp->page + vmp->size);
  364.            a = (pdesc) ((byte *) a + DSC_SZ + a->size))
  365.         {
  366.           if (!(a->size > 0))
  367.             yyfatal ("Virtual memory handler: memory block size <=0 ");
  368.           if(a->mode)
  369.             {
  370.               register i4_t mode;
  371.               for (mode=1; mode <= PAGE_ALIGN; mode *= 2)
  372.                 if( mode == a->mode)
  373.                   break;
  374.               if (mode > PAGE_ALIGN)
  375.                 yyfatal ("Virtual memory handler: integrity checking failed"
  376.                          " (alignment info destroyed)");
  377.             }
  378.           else /* a->mode==0 */ if (DV(0xf) >=4)
  379.             {
  380.               i4_t
  381.                 *p = (i4_t*)a + FDS_SZ/sizeof(i4_t),
  382.                 *e = p + (a->size + DSC_SZ - FDS_SZ)/sizeof(i4_t);
  383.               while(p<e)
  384.                 if(*p++)
  385.                   yyfatal ("virtual memory handler: free memory not 0");
  386.             }
  387.           sz += a->size + DSC_SZ;
  388.           if (force_free == 2 && a->mode)
  389.             {
  390.               register byte *ptr /* ,*endptr */;
  391.               register FILE *f = stderr;
  392.               register i4_t  ss;
  393.               ptr = (byte*)a + DSC_SZ;
  394.               if ( ((i4_t)ptr) % a->mode )
  395.                 {
  396.                   ptr += a->mode;
  397.                   ptr -= ((i4_t)ptr) % a->mode ;
  398.                 }
  399.               ss = (i4_t)ptr - (i4_t)vmp->page + vmp->base;
  400.               fprintf(f,"/* vmblock:%x (%d)*/ %d,n",ss,a->size,ss);
  401. #if 0
  402.               for ( ptr = (byte*)a + DSC_SZ , endptr = ptr + a->size ; 
  403.                     ptr < endptr;
  404.                     ptr++
  405.                     )
  406.                 fprintf(f,"%c",*ptr);
  407.               fputs(" --- ",f);
  408.               for ( ptr = (byte*)a + DSC_SZ, endptr = ptr + a->size ; 
  409.                     ptr < endptr;
  410.                     ptr++
  411.                     )
  412.                 fprintf(f," %x",(i4_t)(*ptr));
  413.               fputs("n -4b- ",f);
  414.               for ( ptr = (byte*)a + DSC_SZ, endptr = ptr + a->size ; 
  415.                     ptr < endptr;
  416.                     ptr += 4
  417.                     )
  418.                 fprintf(f,"%lx ",*(i4_t*)(ptr));
  419.               fputs("n",f);
  420. #endif
  421.             }
  422.         }
  423.       assert (sz == vmp->size);
  424.     }
  425.   if (DV(0xf) > 0)
  426.     sz = check_free_memory_on_page (vmp);
  427.   return sz;
  428. }
  429. static void 
  430. join_fvmb (register pdescf vmb_a, register P_vmpage vmp)
  431. {
  432.   register pdescf vmb_b;
  433.   register i2_t off;
  434.   check_integrity (vmp);
  435.   if (vmb_a->next == 0)
  436.     return;
  437.   assert (vmb_a->next > 0);
  438.   vmb_b = NEXT (vmb_a);
  439.   off = vmb_a->desc.size + DSC_SZ;
  440.   if ((off + (byte *) vmb_a) != (byte *) (vmb_b))
  441.     return;
  442.   /* join with next area */
  443.   vmb_a->desc.size += DSC_SZ + vmb_b->desc.size;
  444.   assert (vmb_a->desc.size > 0);
  445.   if (vmb_b->next)
  446.     {
  447.       vmb_a->next = vmb_b->next + off;
  448.       NEXT (vmb_a)->prev -= off;
  449.     }
  450.   else
  451.     {
  452.       vmb_a->next = 0;
  453.       vmp->lfree_ptr = (byte *) vmb_a - (byte *) (vmp->page) + DSC_SZ;
  454.     }
  455.   bzero(vmb_b,FDS_SZ);
  456.   join_fvmb (vmb_a, vmp);
  457. }
  458. static void 
  459. insert_fvmb (register pdescf vmb_a, register P_vmpage vmp)
  460. {
  461.   register i4_t off;
  462.   flush_cache();
  463.   check_integrity (vmp);
  464.   assert (vmb_a->desc.size > 0);
  465.   bzero((char*)vmb_a + DSC_SZ, vmb_a->desc.size);
  466.   if (vmp->free_ptr == 0)
  467.     {
  468.       vmp->used -= vmb_a->desc.size + DSC_SZ;
  469.       vmp->free_ptr = vmp->lfree_ptr = 
  470.         (byte *) vmb_a - (byte *) vmp->page + DSC_SZ;
  471.       vmb_a->desc.mode = 0;
  472.       vmb_a->next = vmb_a->prev = 0;
  473.     }
  474.   else
  475.     {                           /* update free areas list */
  476.       register pdescf vmb_b = (pdescf) (vmp->page + vmp->free_ptr - DSC_SZ);
  477.       while (((byte *) vmb_b < (byte *) vmb_a)
  478.              && (vmb_b->next > 0))
  479.         vmb_b = NEXT (vmb_b);
  480.       assert (vmb_b->desc.size > 0);
  481.       assert (vmb_b->desc.mode == 0);
  482.       check_integrity (vmp);
  483.       off = (byte *) vmb_b - (byte *) vmb_a;
  484.       if ((off == 0) || (off % DSC_SZ != 0))
  485.         yyfatal ("Virtual memory handler: incorrect offset of memory block");
  486.       vmb_a->desc.mode = 0;
  487.       vmp->used -= vmb_a->desc.size + DSC_SZ;
  488.       if (off < 0)
  489.         {                       /* b < a */
  490.           vmb_a->prev = off;
  491.           if (vmb_b->next > 0)
  492.             {
  493.               vmb_a->next = vmb_b->next + off;
  494.               NEXT (vmb_a)->prev -= off;
  495.             }
  496.           else
  497.             {
  498.               assert (vmb_b->next == 0);
  499.               vmb_a->next = 0;
  500.               vmp->lfree_ptr = (byte *) vmb_a - (byte *) (vmp->page) + DSC_SZ;
  501.             }
  502.           vmb_b->next = -off;
  503.           join_fvmb (vmb_b, vmp);
  504.         }
  505.       else
  506.         /*  a < b */
  507.         {
  508.           vmb_a->next = off;
  509.           if (vmb_b->prev < 0)
  510.             {
  511.               vmb_a->prev = vmb_b->prev + off;
  512.               PREV (vmb_a)->next -= off;
  513.             }
  514.           else
  515.             {
  516.               assert (vmb_b->prev == 0);
  517.               vmb_a->prev = 0;
  518.               vmp->free_ptr = (byte *) vmb_a - (byte *) (vmp->page) + DSC_SZ;
  519.             }
  520.           vmb_b->prev = -off;
  521.           if (vmb_a->prev)
  522.             join_fvmb (PREV (vmb_a), vmp);
  523.           else
  524.             join_fvmb (vmb_a, vmp);
  525.         }
  526.     }
  527.   check_integrity (vmp);
  528. }
  529. static void 
  530. delete_fvmb (pdescf vmb_a, P_vmpage vmp)
  531. {
  532.   /* let be paranoid about caching */
  533.   flush_cache(); 
  534.   if ( ((DV(0xf00)>>8) > 1) && (DV(0xf) > 2))
  535.     fprintf (STDERR, "(%d free bef del-ing)...", check_integrity (vmp));
  536.   
  537.   if (vmb_a->next)
  538.     {
  539.       if (vmb_a->prev)
  540.         {
  541.           NEXT (vmb_a)->prev += vmb_a->prev;
  542.           PREV (vmb_a)->next += vmb_a->next;
  543.         }
  544.       else
  545.         {
  546.           NEXT (vmb_a)->prev = 0;
  547.           vmp->free_ptr += vmb_a->next;
  548.         }
  549.     }
  550.   else
  551.     {
  552.       if (vmb_a->prev)
  553.         {
  554.           vmp->lfree_ptr += vmb_a->prev;
  555.           PREV (vmb_a)->next = 0;
  556.         }
  557.       else
  558.         {
  559.           vmp->free_ptr = 0;
  560.           vmp->lfree_ptr = 0;
  561.         }
  562.     }
  563.   vmb_a->desc.mode = 1;
  564.   vmp->used += vmb_a->desc.size + DSC_SZ;
  565. }
  566. static void 
  567. split_vmb (register pdescf vmb_a,
  568.            register P_vmpage vmp,
  569.            register i4_t off)
  570. /* "off" - offset on the page - place to split current vmb. Data stored
  571.  * in the vmb ended here.
  572.  */
  573. {
  574.   ALIGN (off, DSC_SZ);
  575.   if (off + FDS_SZ < 
  576.       (i4_t) ((byte *) vmb_a - vmp->page) + vmb_a->desc.size + DSC_SZ)
  577.     {                           /* create new free vmb */
  578.       register pdescf vmb_b = (pdescf) (vmp->page + off);
  579.       if ( ((DV(0xf00)>>8) > 1) && (DV(0xf) > 2))
  580.         fprintf (STDERR, "(%d free bef rep-ing)...",
  581.                  check_integrity (vmp));
  582.       
  583.       off -= (i4_t) ((byte *) vmb_a - vmp->page);
  584.       vmb_b->desc.size = vmb_a->desc.size - off;
  585.       assert (vmb_b->desc.size > 0);
  586.       vmb_a->desc.size = off - DSC_SZ;
  587.       assert (vmb_a->desc.size > 0);
  588.       vmb_b->desc.mode = 0;
  589.       insert_fvmb (vmb_b, vmp);
  590.     }
  591. }
  592. static void 
  593. find_vmb (P_vmpage * pvmp, register VADR n, pdescf * pvmb_a)
  594. {
  595.   register byte *p = (byte *) n;
  596.   register P_vmpage vmp;
  597.   register pdescf vmb_a;
  598.   
  599.   vmp = SEG_PTR (n)->base;
  600.   n = SEG_OFF (n);
  601.   while (vmp
  602.          && (check_integrity (vmp) >= 0)
  603.          && (n > vmp->base + vmp->size)
  604.     )
  605.     vmp = vmp->next;
  606.   if (!vmp)
  607.     yyfatal ("Virtual memory handler: required page not found");
  608.   *pvmp = vmp;
  609.   if (pvmb_a==NULL)
  610.     return;
  611.   /* looking for pvmb_a */
  612.   p = vmp->page + (n - vmp->base);
  613.   for (vmb_a = (pdescf) vmp->page;
  614.        (byte *) vmb_a < vmp->page + vmp->size;
  615.        vmb_a = (pdescf) ((byte *) vmb_a + vmb_a->desc.size + DSC_SZ))
  616.     {
  617.       if (!(vmb_a->desc.size > 0))
  618.         yyfatal ("Virtual memory handler: size <=0 on level 1");
  619.       if ((p >= (byte *) vmb_a + DSC_SZ) &&
  620.           (p < (byte *) vmb_a + DSC_SZ + vmb_a->desc.size) &&
  621.           (vmb_a->desc.mode > 0)
  622.         )
  623.         {
  624.           *pvmb_a = vmb_a;
  625.           return;
  626.         }
  627.     }
  628.   yyfatal ("Virtual memory handler: can't find required block on page");
  629. }
  630. static P_vmpage 
  631. new_vmpage (i4_t base, i4_t size)
  632. {
  633.   register P_vmpage ptr;
  634.   register pdescf vmb_a;
  635.   ALIGN (size, PAGE_ALIGN);
  636.   {
  637.     register Offset s = size-DSC_SZ;
  638.     if (size-DSC_SZ != s)
  639.       yyfatal ("Too large virtual memory segment required");
  640.   }
  641.   ptr = MALLOC (sizeof (*ptr));
  642.   ptr->page = MALLOC (size);
  643.   ptr->size = size;
  644.   ptr->base = base;
  645.   vmb_a = (pdescf) (ptr->page);
  646.   vmb_a->desc.mode = 0;
  647.   vmb_a->desc.size = size - DSC_SZ;
  648.   vmb_a->next = vmb_a->prev = 0;
  649.   ptr->used = 0;
  650.   ptr->lfree_ptr = ptr->free_ptr = DSC_SZ;
  651.   check_integrity (ptr);
  652.   return ptr;
  653. }
  654. static P_vmpage 
  655. resize_vmpage (P_vmpage vmp, i4_t size)
  656. {
  657. #define ret(v)  { debug_vmemory -=1; return (v); }
  658.   debug_vmemory +=1;
  659.   check_integrity (vmp);
  660.   
  661.   ALIGN (size, PAGE_ALIGN);
  662.   
  663.   {
  664.     register Offset s = size - DSC_SZ;
  665.     if (size-DSC_SZ != s)
  666.       {
  667.         lperror("Too large virtual memory segment required (%d > 32k)",
  668.                 size);
  669. yyfatal ("");
  670.       }
  671.   }
  672.   if (size > vmp->size)
  673.     {                                           /* increasing page size      */
  674.       register pdescf vmb_a;
  675.       if (vmp->flags==0)
  676.         vmp->page = REALLOC (vmp->page, size); /* may be explicitly copy? ?!! */
  677.       else
  678.         {
  679.           void *p = MALLOC(size);
  680.           bcopy(vmp->page,p,vmp->size);
  681.           vmp->page = p;
  682.         }
  683.       check_integrity (vmp); /* let's check if it was copied correctly       */
  684.       vmb_a = (pdescf) (vmp->page + vmp->size);
  685.       vmb_a->desc.size = size - vmp->size - DSC_SZ;
  686.       vmb_a->desc.mode = DSC_SZ;
  687.       vmp->used += size - vmp->size;
  688.       vmp->size = size;
  689.       check_integrity (vmp);  /* a lot of pseudo-used memory added to page   */
  690.       insert_fvmb (vmb_a, vmp);
  691.     }
  692.   else if (size < vmp->size)  /* request to decrease page size               */
  693.     {                         /* size must be equal "0" or "lfree_ptr-DSC_SZ"*/
  694.       register byte *p;
  695.       register pdescf vmb_a;
  696.       if ( ! vmp->lfree_ptr)              /* if there is no free space       */
  697.         ret (vmp);                        /* this request has to be rejected */
  698.       {
  699.         register i4_t sz = vmp->lfree_ptr - DSC_SZ;
  700.         ALIGN(sz, PAGE_ALIGN);
  701.         if (vmp->size == sz)       /* if there is only a tiny piece of space */
  702.           ret (vmp);               /* it doen't worth to do anything         */
  703.       }
  704.       vmb_a = (pdescf) (vmp->page + vmp->lfree_ptr - DSC_SZ);
  705.       p = (byte *) vmb_a + DSC_SZ + vmb_a->desc.size - vmp->size;
  706.       if (p < vmp->page)           /* if free space is only in the middle of */
  707.         ret (vmp);                 /* page we reject this request too        */
  708.       if (p > vmp->page)
  709.         yyfatal ("Virtual memory handler: segmentation fault on level 1");
  710.       assert (p == vmp->page);
  711.       
  712.       if ((vmb_a->desc.size + DSC_SZ < sizeof (*vmp)) &&/*IF rest of page is tiny*/
  713.           vmp->next &&                                 /*and there is a next page*/
  714.           (vmp->next->base > vmp->base + vmp->size) && /* just after this one    */
  715.           vmp->used                                    /*and there are some data */
  716.         )                                              /*on this page            */
  717.         ret (vmp);                        /* THEN it doesn't worth to strip page */
  718.       
  719.       delete_fvmb (vmb_a, vmp);
  720.       
  721.       {                                        /* test for page size "alignment" */
  722.         register i4_t sz1,sz = vmp->size - vmb_a->desc.size - DSC_SZ;
  723.         sz1 = sz;
  724.         ALIGN (sz, PAGE_ALIGN);
  725.         if (sz != sz1)
  726.           while (sz < sz1 + FDS_SZ)
  727.             sz += PAGE_ALIGN;
  728.         if (size && size != sz)
  729.           yyerror ("Virtual memory handler: "
  730.                    "incorrect size in request for resizing page");
  731.         size = vmp->size;       /* just save previous size of page           */
  732.         vmp->used -= vmp->size - sz;
  733.         vmp->size = sz;         /*                                           */
  734.         if ( sz != sz1 )        /* if page size alignment requires to have a */
  735.           {                     /* bit more space than it really need        */
  736.             vmb_a->desc.size = sz - sz1 - DSC_SZ;  /* add tiny free block at */
  737.             insert_fvmb(vmb_a,vmp);                /* the end of page        */
  738.           }
  739.       }
  740.       check_integrity (vmp);
  741.       if (vmp->size)
  742.         {
  743.           if(!vmp->flags)
  744.             vmp->page = REALLOC (vmp->page, vmp->size);
  745.         }
  746.       else
  747.         /* if no data on the page */
  748.         {
  749.           register P_vmpage vmp1 = vmp->next;
  750.           if(!vmp->flags)
  751.             FREE (vmp->page);
  752.           vmp->page = NULL;
  753.           if (vmp1)
  754.             {
  755.               bcopy ((void *) vmp1, (void *) vmp, sizeof (*vmp));
  756.               FREE ((void *) vmp1);
  757.             }
  758.         }
  759.     }
  760.   check_integrity (vmp);
  761.   ret (vmp);
  762. #undef ret
  763. }
  764. static P_vmpage 
  765. free_vmpage (P_vmpage ptr)
  766. {
  767.   if (ptr)
  768.     {
  769.       check_integrity (ptr);
  770.       ptr->next = free_vmpage (ptr->next);
  771.       if (ptr->next)
  772.         return ptr;
  773.       if ((ptr->used && (force_free == 0)))
  774.         return ptr;
  775.       if (ptr->flags == 0)      /* in other case it'll be freed later */
  776.         {
  777.           FREE (ptr->page);
  778.           FREE (ptr);
  779.         }
  780.     }
  781.   return NULL;
  782. }
  783. static P_vmpage 
  784. join_memory (register P_vmpage vmp)
  785. {
  786.   register P_vmpage vmp1;
  787.   register i4_t size;
  788.     
  789.   check_integrity (vmp);
  790.   if (vmp == NULL)
  791.     return NULL;
  792.   if (vmp->next)
  793.     vmp->next = join_memory (vmp->next);
  794.   vmp = resize_vmpage (vmp, 0);
  795.   if (vmp->next == 0)
  796.     return vmp;
  797.   if (vmp->next->base > vmp->base + vmp->size)
  798.     return vmp;
  799.   assert (vmp->next->base == vmp->base + vmp->size);
  800.   vmp1 = vmp->next;
  801.   size = vmp->size + vmp1->size;
  802.   {
  803.     register Offset s = size;
  804.     if (s != size)
  805.       return vmp;
  806.   }
  807.   /* We CAN join the page with follow one !!!*/
  808.   vmp->next = vmp1->next;
  809.   size=vmp->size;
  810.   vmp = resize_vmpage (vmp, vmp->size+vmp1->size);
  811.   /* correct last free_vmb */
  812.   {
  813.     register pdescf vmb_a, vmb_b;
  814.     vmb_a = (pdescf) (vmp->page + vmp->lfree_ptr - DSC_SZ);
  815.     delete_fvmb (vmb_a, vmp);
  816.     if ((byte *) vmb_a < vmp->page + size)
  817.       {
  818. vmb_a->desc.size = vmp->page + size - (byte *) vmb_a - DSC_SZ;
  819. insert_fvmb (vmb_a, vmp);
  820.       }
  821.     bcopy (vmp1->page, vmp->page + size, vmp1->size);
  822.     assert(size + vmp1->size == vmp->size);
  823.     vmp->used += vmp1->used - vmp1->size;
  824.     if (vmp1->free_ptr) /* Increasing space is not expected */ 
  825.       {
  826. if (vmp->lfree_ptr)
  827.   {
  828.     vmb_a = (pdescf) (vmp->page + vmp->lfree_ptr - DSC_SZ);
  829.     vmb_b = (pdescf) (vmp->page + size + vmp1->free_ptr-DSC_SZ);
  830.     vmb_b->prev = vmb_a->next = (byte *) vmb_b - (byte *) vmb_a;
  831.     vmp->lfree_ptr = size + vmp1->lfree_ptr;
  832.   }
  833. else
  834.   {
  835.     vmp->free_ptr = size + vmp1->free_ptr;
  836.     vmp->lfree_ptr = size + vmp1->lfree_ptr;
  837.   }
  838.       }
  839.   }
  840.   vmp1->next = 0;
  841.   {
  842.     i4_t ff = force_free;
  843.     force_free=1;
  844.     assert (free_vmpage (vmp1) == 0);
  845.     force_free=ff;
  846.   }
  847.   debug_vmemory +=1;
  848.   check_integrity (vmp);
  849.   debug_vmemory -=1;
  850.   return vmp;
  851. }
  852. static void 
  853. compress_data (register vmsegment * seg)
  854. {
  855.   register P_vmpage vmp;
  856.   flush_cache();
  857.   vmp = seg->base = check_for_null_page (free_vmpage (seg->base));
  858.   if (vmp == NULL)
  859.     return;
  860.   seg->base = check_for_null_page (join_memory (seg->base));
  861. }
  862. static VADR 
  863. ob_alloc (i4_t size, i4_t align, vmsegment * seg)
  864. {
  865.   register i4_t ptr;
  866.   register P_vmpage vmp = seg->base;
  867.   register pdescf vmb_a;
  868.   i4_t pg_size = 0x1000;         /* 32k */
  869.   i4_t os_needs = 0x40;
  870.   if (size == 0)
  871.     return (VADR)NULL;
  872.   if (align != sizeof (i4_t) && align != PAGE_ALIGN )
  873.     if ((align > 0) && (align < sizeof (i4_t)))
  874.         align = sizeof (i4_t);
  875.     else
  876.       {
  877.         align = sizeof (i4_t);
  878.         while ((align < size) && (align<PAGE_ALIGN) )
  879.           align <<= 1;
  880.         if (align > PAGE_ALIGN)
  881.           align >>= 1;
  882.       }
  883.   while ((size + DSC_SZ + align) >= (pg_size - os_needs))
  884.     pg_size <<= 1;
  885.   if (!vmp)
  886.     vmp = seg->base = new_vmpage (0, pg_size);
  887.   ptr = 0;
  888.   for (;;)                   /* check free space for new adding new data and */
  889.     {                        /*  add additional pages if it's needed         */
  890.       check_integrity (vmp);
  891.       if (vmp->free_ptr)     /* if there are some free vmb on page           */
  892.         {
  893.           register Offset p = vmp->free_ptr;
  894.           for (;;)           /* check each of them                           */
  895.             {
  896.               vmb_a = (pdescf) (vmp->page + p - DSC_SZ);
  897.               ptr = p % align;
  898.               if (ptr)
  899.                 ptr = align - ptr;
  900.               if (vmb_a->desc.size >= (size + ptr))
  901.                 {
  902.                   ptr += p;
  903.                   break;
  904.                 }
  905.               ptr = 0;
  906.               if (vmb_a->next == 0)
  907.                 break;
  908.               p += vmb_a->next;
  909.             }
  910.           if (ptr)
  911.             break;
  912.         }
  913.       if (vmp->next)
  914.         vmp = vmp->next;
  915.       else
  916.         {
  917.           vmb_a = (pdescf) (vmp->page + vmp->lfree_ptr - DSC_SZ);
  918.           if (                  /* there is no large free tail on the page */
  919.                vmp->lfree_ptr == 0
  920.                || (vmp->lfree_ptr > vmp->size * 3 / 4)
  921.                || (vmp->lfree_ptr + vmb_a->desc.size < vmp->size)
  922.                || (pg_size > vmp->size)
  923. #ifdef USE_XVM
  924.                || (SEG_PTR(xmemory_segment) == seg) /* don't move xmalloc pages */
  925. #endif
  926.             )
  927.             vmp = vmp->next = new_vmpage (vmp->base + vmp->size,
  928.                                           pg_size-os_needs);
  929.           else                  /* realloc page for large vmb */
  930.             resize_vmpage (vmp, vmp->size + pg_size);
  931.         }
  932.     }
  933.   /* now "vmb_a" points to free vmb descriptor
  934.    * and "ptr"   is offset on page to aligned position of data inside this vmb.
  935.    */
  936.   delete_fvmb (vmb_a, vmp);
  937.   split_vmb (vmb_a, vmp, ptr + size);
  938.   vmb_a->desc.mode = align;
  939.   bzero ((byte *) vmb_a + DSC_SZ, vmb_a->desc.size);
  940.   ptr = vmp->base + ptr;
  941.   {
  942.     register i4_t sz = check_integrity (vmp);
  943.     if ( ((DV(0xf00)>>8) > 1) && (DV(0xf) > 2))
  944.       fprintf (STDERR,
  945.                "Allocated %3X(%3X),aligned %2X at %5x (used %5X/free %5X)n",
  946.                size, vmb_a->desc.size, align, ptr, vmp->used, sz);
  947.   }
  948. #if 0
  949.   {
  950.     VADR critical_regions[] = {0};
  951.     register i4_t i = sizeof(critical_regions)/sizeof(VADR);
  952.     while ( i--)
  953.       if ( critical_regions[i]==(VADR)ptr )
  954. {
  955.   yyerror("? ?");
  956. }
  957.   }
  958. #endif
  959.   return (VADR) ptr;
  960. }
  961. static void
  962. check_segment_integrity(register i4_t s_id)
  963. {
  964.   i4_t     i;
  965.   i4_t     dv;
  966.   P_vmpage vmp;
  967.   pdescf   vmb_a;
  968.   assert (s_id >= 0 && s_id < segment_table.ent_nmb);
  969.   
  970.   if( DV(0xf0) == 0)
  971.     return;
  972.   dv = debug_vmemory;
  973.   debug_vmemory &= 0xf0f ;
  974.   /*
  975.    * looking for entries in relocation table which have to be deleted 
  976.    */
  977. #define TBL segment_table.entries[s_id]
  978.   for(vmp= TBL.base;vmp;vmp = vmp->next)
  979.     check_integrity(vmp);
  980. #undef TBL
  981.   debug_vmemory = 0;
  982. #define TBL segment_table.entries[s_id].relocation_table
  983.   for (i = 0; i < TBL.ent_nmb; i++ )
  984.     if(TBL.entries[i])
  985.       find_vmb (&vmp, SEG_BASE (s_id) + TBL.entries[i], &vmb_a);
  986. #undef TBL
  987.   
  988.   /*
  989.    * looking for entries in export name table which have to be deleted 
  990.    */
  991. #define TBL segment_table.entries[s_id].export_table
  992.   for (i = 0; i < TBL.ent_nmb; i++ )
  993.     if(TBL.entries[i].adr)
  994.       {
  995.         find_vmb (&vmp, SEG_BASE (s_id) + TBL.entries[i].adr, &vmb_a);
  996.         find_vmb (&vmp, SEG_BASE (s_id) + TBL.entries[i].name, &vmb_a);
  997.       }
  998. #undef TBL
  999.   debug_vmemory = dv;
  1000. }
  1001. static void
  1002. check_vm_integrity(void)
  1003. {
  1004.   i4_t  i;
  1005.   i4_t dv;
  1006.   if( DV(0xf0) == 0x10)
  1007.     return;
  1008.   
  1009.   dv = debug_vmemory;
  1010.   debug_vmemory &= 0xf1f ;
  1011.   
  1012.   for( i = 1; i < segment_table.ent_nmb; i++)
  1013.     check_segment_integrity(i);
  1014.   
  1015.   debug_vmemory = dv;
  1016. }
  1017. VADR 
  1018. vmrealloc (VADR old_ptr, i4_t new_size)
  1019. {
  1020.   P_vmpage vmp;
  1021.   pdescf vmb_a;
  1022.   register i4_t old_size;
  1023.   check_vm_integrity();
  1024.   if (SEG_OFF (old_ptr) == 0)
  1025.     return vmalloc (new_size);
  1026.   find_vmb (&vmp, old_ptr, &vmb_a);
  1027.   old_size = (i4_t) ((byte *) vmb_a - vmp->page) /*   vmb offset on page     */
  1028.     + DSC_SZ + vmb_a->desc.size                  /* + block size             */
  1029.     - (SEG_OFF (old_ptr) - vmp->base);           /* - offset of data on page */
  1030.   if (new_size + FDS_SZ <= old_size)
  1031.     /* decrease memory block size and create new free vmb */
  1032.     split_vmb (vmb_a, vmp, SEG_OFF (old_ptr) - vmp->base + new_size);
  1033.   else if (new_size > old_size)
  1034.     {
  1035.       register pdescf vmb_b = (pdescf) ((byte *) vmb_a + DSC_SZ +
  1036.                                         vmb_a->desc.size);
  1037.       if (((byte *)vmb_b < vmp->page + vmp->size ) &&
  1038.           (vmb_b->desc.mode == 0) &&
  1039.           (new_size <= old_size+DSC_SZ + vmb_b->desc.size))
  1040.         {                      /* append following free block to current one */
  1041.           delete_fvmb (vmb_b, vmp);
  1042.           vmb_a->desc.size += vmb_b->desc.size + DSC_SZ;
  1043.         }
  1044.       else
  1045.         {                     /* allocate another block with required length */
  1046.           register VADR n = ob_alloc (new_size, vmb_a->desc.mode,
  1047.                                       SEG_PTR (old_ptr));
  1048.           bcopy (vpointer (old_ptr), vpointer (n), old_size);
  1049.           insert_fvmb (vmb_a, vmp);
  1050.           return n;
  1051.         }
  1052.     }
  1053.   /* in other case we don't need to do anything */
  1054.   check_segment_integrity(SEG_IND(old_ptr));
  1055.   check_vm_integrity();
  1056.   return old_ptr;
  1057. }
  1058. void 
  1059. vmfree (VADR ptr)
  1060. {
  1061.   P_vmpage vmp;
  1062.   pdescf   vmb_a;
  1063.   i4_t      s_id;
  1064.   
  1065.   check_vm_integrity();
  1066.   if (SEG_OFF (ptr) == 0)
  1067.     return;
  1068.   find_vmb (&vmp, ptr, &vmb_a);
  1069.   s_id = SEG_IND(ptr);
  1070.   if ( ((DV(0xf00)>>8) > 2) && (DV(0xf) > 2))
  1071.     fprintf (STDERR, "Deallocated %X at %X (used %X/free %X)... ",
  1072.              vmb_a->desc.size + DSC_SZ, SEG_OFF(ptr), vmp->used, check_integrity (vmp));
  1073.   
  1074.   /*
  1075.    * looking for entries in relocation table which have to be deleted 
  1076.    */
  1077. #define TBL SEG_PTR(ptr)->relocation_table
  1078.   { 
  1079.     register i4_t i;
  1080.     register i4_t lo,hi,p;
  1081.     lo = vmp->base + ((char*)vmb_a - (char*)vmp->page) + DSC_SZ;
  1082.     hi = lo + vmb_a->desc.size;
  1083.     for (i = 0; i < TBL.ent_nmb; i++ )
  1084.       {
  1085.         p = TBL.entries[i];
  1086.         if ( lo <= p  && p <= hi )
  1087.           {
  1088.             TBL.entries[i] = 0; /* mark the entry dummy */
  1089.             TBL.used_ent --;
  1090.           }
  1091.       }
  1092.   }
  1093. #undef TBL
  1094.   
  1095.   /*
  1096.    * looking for entries in export name table which have to be deleted 
  1097.    */
  1098. #define TBL SEG_PTR(ptr)->export_table
  1099.   { 
  1100.     register i4_t i;
  1101.     register i4_t lo,hi,p;
  1102.     lo = vmp->base + ((char*)vmb_a - (char*)vmp->page) + DSC_SZ;
  1103.     hi = lo + vmb_a->desc.size;
  1104.     for (i = 0; i < TBL.ent_nmb; i++ )
  1105.       {
  1106.         p = TBL.entries[i].adr;
  1107.         if ( lo <= p  && p <= hi )
  1108.   {
  1109.     TBL.entries[i].adr = 0;     /* mark the entry dummy */
  1110.     vmfree(TBL.entries[i].name);
  1111.   }
  1112.       }
  1113.   }
  1114. #undef TBL
  1115.   check_segment_integrity(s_id);
  1116.   insert_fvmb (vmb_a, vmp);
  1117.   check_segment_integrity(s_id);
  1118.   if ( ((DV(0xf00)>>8) > 2) && (DV(0xf) > 2))
  1119.     fprintf (STDERR, "Done (used %X/free %X)n",
  1120.              vmp->used, check_integrity (vmp));
  1121.   
  1122.   if (vmp == SEG_PTR (ptr)->base)
  1123.     SEG_PTR (ptr)->base = free_vmpage (vmp);
  1124.   else
  1125.     vmp->next = free_vmpage (vmp->next);
  1126.   check_vm_integrity();
  1127.   return;
  1128. }
  1129. void *
  1130. vpointer (VADR n)
  1131. {
  1132.   register byte *ret;
  1133.   VADR           n1 = n;
  1134.   P_vmpage vmp;
  1135.   if (SEG_OFF (n) == 0)
  1136.     return NULL;
  1137.   ret = check_cache(n);
  1138.   if (ret)
  1139.     return ret;
  1140.   check_vm_integrity();
  1141.   {                             /* import name processing */
  1142.     register i4_t s_id;
  1143.     s_id = SEG_ID (n);
  1144.     if (s_id < 0)
  1145.       n = resolve_reference (vpointer (SEG_BASE (~s_id) + SEG_OFF (n)));
  1146.   }
  1147.   find_vmb (&vmp, n, NULL);
  1148.   ret = vmp->page + (SEG_OFF (n) - vmp->base);
  1149.   
  1150.   check_vm_integrity();
  1151.   update_cache(n1, ret);
  1152.   return (void *) ret;
  1153. }
  1154. VADR 
  1155. vm_ob_alloc (i4_t size, i4_t align)
  1156. {
  1157.   register VADR obj;
  1158.   
  1159.   check_vm_integrity();
  1160.   enable_auto_create = 1;
  1161.   obj = ob_alloc (size, align, SEG_PTR (0));
  1162.   enable_auto_create = 0;
  1163.   
  1164.   check_segment_integrity(SEG_IND(obj));
  1165.   check_vm_integrity();
  1166.   return obj;
  1167. }
  1168. VADR 
  1169. get_vm_segment_id (VADR ptr)
  1170. {
  1171.   return SEG_BASE (SEG_IND (ptr));
  1172. }
  1173. VADR 
  1174. switch_to_segment (VADR ptr)
  1175. {
  1176.   segment_table.current = SEG_IND (ptr);
  1177.   return SEG_BASE (segment_table.current);
  1178. }
  1179. VADR 
  1180. create_segment (void)
  1181. {
  1182.   register i4_t p;
  1183.   for (p = segment_table.ent_nmb; --p > 0;)
  1184.     if (segment_table.entries[p].used == 0)
  1185.       break;
  1186.   if (p < 0)
  1187.     p = 0;
  1188.   if (!p)
  1189.     {
  1190.       ADD_ENTRY (segment_table);
  1191.       p = segment_table.ent_nmb - 1;
  1192.     }
  1193.   if (!p)                       /* index 0 is used for "current" segment. */
  1194.     {
  1195.       ADD_ENTRY (segment_table);
  1196.       p = segment_table.ent_nmb - 1;
  1197.     }
  1198.   segment_table.current = p;
  1199.   segment_table.entries[p].used = 1;
  1200.   check_segment_integrity(p);
  1201.   return (VADR) SEG_BASE (p);
  1202. }
  1203. int
  1204. unlink_segment (VADR s_id, i4_t enforce_free)
  1205. {
  1206.   register vmsegment *p = SEG_PTR (s_id);
  1207.   force_free = enforce_free;
  1208.   p->base = free_vmpage (p->base);
  1209.   force_free = 0;
  1210.   if (p->base)
  1211.     {
  1212.       if (debug_vmemory)
  1213. {
  1214.   i4_t u = 0;
  1215.   register P_vmpage vmp;
  1216.   for (vmp = p->base; vmp ; vmp = vmp->next )
  1217.     u += vmp->used;
  1218.   fprintf (STDERR,"There are %d bytes used in given segmentn",u);
  1219.   force_free = 2;
  1220.   p->base = free_vmpage (p->base);
  1221.   force_free = 0;
  1222. }
  1223.       return 0;
  1224.     }
  1225.   if (segment_table.current == SEG_IND (s_id))
  1226.     segment_table.current = 0;
  1227.   if (!p->relocation_table.dont_remove)
  1228.     FREE (p->relocation_table.entries);
  1229.   if (!p->export_table.dont_remove)
  1230.     FREE (p->export_table.entries);
  1231.   if (p->loaded_block_address)
  1232.     FREE (p->loaded_block_address);
  1233.   bzero ((void *) p, sizeof (vmsegment));
  1234.   return 1;
  1235. }
  1236. void *
  1237. export_segment (VADR s_id, i4_t *len, i4_t unlink_seg)
  1238. {
  1239.   register i4_t sz,seg_ind = SEG_IND(s_id);
  1240.   register P_vmpage vmp;
  1241.   register void *barr = NULL;
  1242.   register vmsegment *s1, *seg = SEG_PTR (s_id);
  1243.   i4_t      r_en, e_en;
  1244.   i4_t     dv = debug_vmemory;
  1245.   
  1246.   debug_vmemory |= 0x33;
  1247.   
  1248.   *len = 0;
  1249.   check_segment_integrity(seg_ind);
  1250.   compress_data (seg);
  1251.   check_segment_integrity(seg_ind);
  1252.   sz = sizeof (vmsegment);
  1253.   r_en = ( 1 + seg->relocation_table.ent_nmb / TBL_PORTION) * TBL_PORTION;
  1254.   if (seg->relocation_table.ent_nmb % TBL_PORTION ==0)
  1255.     r_en -= TBL_PORTION;
  1256.   sz += r_en * sizeof (*(seg->relocation_table.entries));
  1257.   
  1258.   e_en = ( 1 + seg->export_table.ent_nmb / TBL_PORTION) * TBL_PORTION;
  1259.   if (seg->export_table.ent_nmb % TBL_PORTION ==0)
  1260.     e_en -= TBL_PORTION;
  1261.   sz += e_en * sizeof (*(seg->export_table.entries));
  1262.   
  1263.   {
  1264.     register i4_t pgsp;
  1265.     for (pgsp = 0, vmp = seg->base; vmp; vmp = vmp->next)
  1266.       {
  1267.         pgsp += vmp->size;
  1268.         sz += sizeof (*vmp);
  1269.         check_integrity (vmp);
  1270.       }
  1271.     ALIGN (sz, PAGE_ALIGN);
  1272.     *len = sz + pgsp;
  1273.   }
  1274.   barr = MALLOC (*len);
  1275.   sz = 0;
  1276. #define ADD_BLK(p,l) {bcopy((p),((byte*)barr+sz),l);sz+=l;}
  1277.   ADD_BLK (seg, sizeof (vmsegment));
  1278.   s1 = (vmsegment *) barr;
  1279.   s1->relocation_table.entries = (void *) sz;
  1280.   ADD_BLK (seg->relocation_table.entries,
  1281.            s1->relocation_table.ent_nmb *
  1282.            sizeof (*(s1->relocation_table.entries)));
  1283.   sz = (i4_t) s1->relocation_table.entries  +
  1284.     r_en * sizeof (*(s1->relocation_table.entries));
  1285.   s1->export_table.entries = (void *) sz;
  1286.   ADD_BLK (seg->export_table.entries,
  1287.            s1->export_table.ent_nmb *
  1288.            sizeof (*(s1->export_table.entries)));
  1289.   sz = (i4_t) s1->export_table.entries  +
  1290.     e_en * sizeof (*(s1->export_table.entries));
  1291.   s1->base = (void *) sz;
  1292.   for (vmp = seg->base; vmp; vmp = vmp->next)
  1293.     {
  1294.       register P_vmpage pvmp = (P_vmpage) ((byte *) barr + sz);
  1295.       ADD_BLK (vmp, sizeof (*vmp));
  1296.       if (pvmp->next)
  1297.         pvmp->next = (void *) sz;
  1298.       pvmp->flags = 1;
  1299.     }
  1300.   ALIGN (sz, PAGE_ALIGN);
  1301.   for (vmp = s1->base; vmp;
  1302.        vmp = ((P_vmpage) ((byte *) barr + (i4_t) vmp))->next)
  1303.     {
  1304.       register P_vmpage pvmp = (P_vmpage) ((byte *) barr + (i4_t) vmp);
  1305.       register i4_t page_offset = sz;
  1306.       ADD_BLK (pvmp->page, pvmp->size);
  1307.       pvmp->page = (void *) page_offset;
  1308.     }
  1309. #undef ADD_BLK
  1310.   assert (sz == *len);
  1311.   check_segment_integrity(seg_ind);
  1312.   if (unlink_seg)
  1313.     unlink_segment (s_id, 1);
  1314.   
  1315.   debug_vmemory = dv;
  1316.   return barr;
  1317. }
  1318. VADR 
  1319. link_segment (void *buffer, i4_t size)
  1320. {
  1321.   register i4_t sz;
  1322.   register VADR s_id;
  1323.   register P_vmpage vmp;
  1324.   register vmsegment *s;
  1325.   i4_t     dv = debug_vmemory;
  1326.   debug_vmemory |= 0x33;
  1327.   s_id = create_segment ();
  1328.   s = SEG_PTR (0);
  1329. #define CORRECT_ADR(p) p=(void*)((byte*)buffer+(i4_t)(p))
  1330.   bcopy (buffer, s, sizeof (vmsegment));
  1331.   CORRECT_ADR (s->base);
  1332.   CORRECT_ADR (s->relocation_table.entries);
  1333.   if (s->relocation_table.ent_nmb==0)
  1334.     s->relocation_table.entries = NULL;
  1335.   s->relocation_table.dont_remove = 1;
  1336.   CORRECT_ADR (s->export_table.entries);
  1337.   if (s->export_table.ent_nmb==0)
  1338.     s->export_table.entries = NULL;
  1339.   s->export_table.dont_remove = 1;
  1340.   for (vmp = s->base; vmp; vmp = vmp->next)
  1341.     {
  1342.       if (vmp->page)
  1343.         CORRECT_ADR (vmp->page);
  1344.       if (vmp->next)
  1345.         CORRECT_ADR (vmp->next);
  1346.       check_integrity (vmp);
  1347.     }
  1348. #undef CORRECT_ADR
  1349.   
  1350.   for (sz = 0; sz < s->relocation_table.ent_nmb; sz++)
  1351.     if (s->relocation_table.entries[sz])
  1352.       {
  1353.         VADR *vp = (VADR *) vpointer (s->relocation_table.entries[sz]);
  1354.         if (*vp)
  1355.           *vp = SEG_OFF(*vp) +
  1356.             (SEG_ID(*vp)>=0 ? s_id : SEG_BASE(~SEG_ID(s_id)));
  1357.       }
  1358.   s->loaded_block_address = buffer;
  1359.   check_segment_integrity(SEG_IND(s_id));
  1360.   debug_vmemory = dv;
  1361.   return s_id;
  1362. }
  1363. #define CORRECT_ADR(ptr) 
  1364. {
  1365.   VADR *vp = &(ptr);
  1366.   if(*vp)
  1367.     *vp = SEG_OFF(*vp)+
  1368.       SEG_BASE(get_vm_segment_id(*vp)^(SEG_ID(*vp)>=0?0:~0)); 
  1369. }
  1370. void 
  1371. register_relocation_address (VADR ptr)
  1372. {
  1373.   register i4_t      p;
  1374.   register reloc_tbl *rt  = & (SEG_PTR(ptr)->relocation_table);
  1375. #define TBL (*rt)
  1376.   
  1377.   assert(SEG_OFF(ptr) != 0);
  1378.   
  1379.   /* self checking --- fix to be more smart */ 
  1380.   for (p = 0; p < TBL.ent_nmb; p++ )
  1381.     if ( TBL.entries[p] == SEG_OFF(ptr) )
  1382.       {
  1383.         yyerror("Internal error: relocation address registered twice");
  1384.         return;
  1385.       }
  1386.   /*---------------*/
  1387.   if ( TBL.used_ent == TBL.ent_nmb )
  1388.     p = TBL.ent_nmb;
  1389.   else
  1390.     for (p = TBL.ent_nmb; p > 0 ;)
  1391.       if ( TBL.entries[--p] == 0 ) /* IF there are holes in the table      */
  1392.         break;                     /* just use it instead of adding new entries */
  1393.   if ( p >= TBL.ent_nmb)
  1394.     {
  1395.       ADD_ENTRY (TBL);
  1396.       p = TBL.ent_nmb - 1;
  1397.       TBL.used_ent = TBL.ent_nmb;
  1398.     }
  1399.   TBL.entries[p] = SEG_OFF(ptr);
  1400.   CORRECT_ADR (*((VADR *) vpointer (ptr)));
  1401.   check_segment_integrity(SEG_IND(ptr));
  1402. #undef TBL
  1403. }
  1404. void 
  1405. register_export_name (VADR object_ptr, VADR name_ptr)
  1406. {
  1407. #define TBL seg->export_table
  1408.   register i4_t       p,p1 = -1;
  1409.   register char      *name;
  1410.   register vmsegment *seg;
  1411.   assert (SEG_IND (object_ptr) == SEG_IND (name_ptr));
  1412.   seg = SEG_PTR (object_ptr);
  1413.   name = vpointer (name_ptr);
  1414.   for (p = 0; p < TBL.ent_nmb; p++)
  1415.     if (TBL.entries[p].adr == 0)
  1416.       {
  1417. p1 = p;
  1418. continue;
  1419.       }
  1420.     else if (0 == strcmp (vpointer (TBL.entries[p].name), name))
  1421.       { /* IF given name has already registered */
  1422.         if (SEG_OFF (object_ptr) != SEG_OFF (TBL.entries[p].adr))
  1423.   {
  1424.     /* but the exported object isn't the same */
  1425.     yyerror ("Attempt to register different relocable"
  1426.      " objects with the same name");
  1427.   }
  1428.         return;
  1429.       }
  1430.   if ( p1 >= 0 )              /* IF there are holes in the table           */
  1431.     p = p1;                   /* just use it instead of adding new entries */
  1432.   else                        /* IF there is no holes in the table         */
  1433.     {                         /* add new entry there                       */
  1434.       ADD_ENTRY (TBL);
  1435.       p = TBL.ent_nmb - 1;
  1436.     }
  1437.   TBL.entries[p].adr  = SEG_OFF(object_ptr);
  1438.   TBL.entries[p].name = SEG_OFF(name_ptr);
  1439.   check_segment_integrity(SEG_IND(object_ptr));
  1440. #undef TBL
  1441. }
  1442. void 
  1443. register_export_address (VADR registered_adr, char *name)
  1444. {
  1445.   VADR name_ptr;
  1446.   register i4_t len;
  1447.   len = strlen (name) + 1;
  1448.   name_ptr = ob_alloc (len, 1, SEG_PTR (registered_adr));
  1449.   name_ptr += get_vm_segment_id (registered_adr);
  1450.   bcopy (name, vpointer (name_ptr), len);
  1451.   register_export_name (registered_adr, name_ptr);
  1452. }
  1453. static VADR 
  1454. resolve_reference_1 (char *name,i4_t local)
  1455. {
  1456. #define TBL  segment_table.entries[segment_table.current].export_table
  1457.   register i4_t p, s;
  1458.   register VADR obj = (VADR)NULL, cs = segment_table.current;
  1459.   for (s = 0; s < segment_table.ent_nmb; s++)
  1460.     {
  1461.       segment_table.current = s ? s : cs ;
  1462.       for (p = 0; p < TBL.ent_nmb; p++)
  1463. if (TBL.entries[p].adr == 0 )
  1464.   continue;
  1465. else if (0 == strcmp (vpointer (TBL.entries[p].name), name))
  1466.           {
  1467.             register VADR o;
  1468.     o = TBL.entries[p].adr + SEG_BASE (segment_table.current);
  1469.             if (!obj)
  1470.               obj = o;
  1471.             else if (obj != o)
  1472.               {
  1473.                 fprintf (STDERR, "Ambigous name reference '%s'n", 
  1474.                          (char *) vpointer (TBL.entries[p].name));
  1475.                 obj = TNULL;
  1476. goto EXIT;
  1477.               }
  1478.           }
  1479.       if (s == 0 && (obj || local))
  1480. goto EXIT;
  1481.     }
  1482. EXIT:
  1483.   segment_table.current = cs;
  1484.   return obj;
  1485. #undef TBL
  1486. }
  1487. VADR 
  1488. resolve_reference (char *name)
  1489. {
  1490.   return resolve_reference_1 (name, 0);
  1491. }
  1492. VADR 
  1493. resolve_local_reference (char *name)
  1494. {
  1495.   return resolve_reference_1 (name, 1);
  1496. }
  1497. VADR 
  1498. external_reference (char *name) 
  1499. { /* creating external reference to 'name' from 'current' segment */
  1500.   register VADR ptr;
  1501.   register i4_t len;
  1502.   len = strlen (name) + 1;
  1503.   ptr = vm_ob_alloc (len, 0); 
  1504.   bcopy (name, vpointer (ptr), len);
  1505.   /*
  1506.    * !!! It's a local reference - the name resolution has to be required  
  1507.    *     only while this segment marked as a 'current'
  1508.    */
  1509.   return SEG_OFF (ptr) + SEG_BASE (~SEG_ID (ptr));
  1510. }
  1511. #undef CORRECT_ADR
  1512. VADR
  1513. ptr2vadr(void *p)
  1514. {
  1515.   register i4_t i;
  1516.   register P_vmpage vmp;
  1517.   register vmsegment *s;
  1518.   for(i=0; i<segment_table.ent_nmb; i++)
  1519.     {
  1520.       s = &(segment_table.entries[i?i:segment_table.current]);
  1521.       for(vmp=s->base; vmp; vmp = vmp = vmp->next)
  1522.         if (vmp->page < (byte*)p && (byte*)p < vmp->page+vmp->size)
  1523.           return SEG_BASE(i?i:segment_table.current) +
  1524.             vmp->base + (i4_t)((byte*)p - vmp->page);
  1525.     }
  1526.   return VNULL;
  1527. }
  1528. #ifdef USE_XVM
  1529. /*******************************************************/
  1530. /*********$$$$$$$$$$$$$$$$$$$$$$$$$*********************/
  1531. /*******************************************************/
  1532. #define HPLIM 50
  1533. static void *huge_pieces[HPLIM];
  1534. static i4_t   hp_used = 0;
  1535. static void *
  1536. h1(void *p,i4_t size)
  1537. {
  1538.   i4_t i;
  1539.   for(i=hp_used;i--;)
  1540.     if(huge_pieces[i]==p)
  1541.       break;
  1542.   if(i<0)
  1543.     i=hp_used++;
  1544.   
  1545.   assert(i<HPLIM);
  1546.   if(size)
  1547.     huge_pieces[i] = (p?lrealloc(p,size):lmalloc(size));
  1548.   else
  1549.     {
  1550.       lfree(p);
  1551.       huge_pieces[i] = NULL;
  1552.     }
  1553.   return huge_pieces[i];
  1554. }
  1555. void *
  1556. xmalloc(i4_t size)
  1557. {
  1558.   VADR hold_seg = GET_CURRENT_SEGMENT_ID;
  1559.   void *ptr;
  1560.   if(size>=0x8000) /* 32k*/
  1561.     return h1(NULL,size);
  1562.   if(xmemory_segment==VNULL)
  1563.     xmemory_segment = create_segment();
  1564.   switch_to_segment(xmemory_segment);
  1565.   ptr = vpointer(vmalloc(size));
  1566.   switch_to_segment( hold_seg );
  1567.   return ptr;
  1568. }
  1569. void *
  1570. xcalloc (i4_t number, i4_t size)
  1571. {
  1572.   return xmalloc(number*size);
  1573. }
  1574. void *
  1575. xrealloc(void *p,i4_t size)
  1576. {
  1577.   VADR hold_seg = GET_CURRENT_SEGMENT_ID;
  1578.   void *ptr;
  1579.   if(size>=0x8000) /* 32k*/
  1580.     return h1(p,size);
  1581.   if(xmemory_segment==VNULL)
  1582.     xmemory_segment = create_segment();
  1583.   switch_to_segment(xmemory_segment);
  1584.   ptr = vpointer(vmrealloc(ptr2vadr(p),size));
  1585.   switch_to_segment( hold_seg );
  1586.   return ptr;
  1587. }
  1588. void
  1589. xfree(void *p)
  1590. {
  1591.   VADR hold_seg = GET_CURRENT_SEGMENT_ID;
  1592.   VADR v;
  1593.   if(xmemory_segment==VNULL)
  1594.     xmemory_segment = create_segment();
  1595.   switch_to_segment(xmemory_segment);
  1596.   v = ptr2vadr(p);
  1597.   if (v)
  1598.     vmfree(v);
  1599.   else
  1600.     h1(p,0);
  1601.   switch_to_segment( hold_seg );
  1602. }
  1603. #define L_DLT 0x100
  1604. static void *
  1605. lmalloc(i4_t size)
  1606. {
  1607.   void *p = malloc(2*L_DLT+size);
  1608.   if (p==NULL)
  1609.     yyfatal("Memory Full");
  1610.   p = (char*)p+L_DLT; 
  1611.   bzero (p, size);
  1612.   return p;
  1613. }
  1614. static void *
  1615. lrealloc(void *p,i4_t size)
  1616. {
  1617.   if(p)
  1618.     p = (char*)p-L_DLT;
  1619.   p = realloc(p,size + 2*L_DLT);
  1620.   if (p==NULL)
  1621.     yyfatal("Memory Full");
  1622.   /*  bzero (p, size); */
  1623.   return (char*)p + L_DLT;
  1624. }
  1625. static void
  1626. lfree(void *p)
  1627. {
  1628.   if(p)
  1629.     free((char*)p - L_DLT);
  1630. }
  1631. #endif