home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Programming / sofa / archive / SmallEiffel.lha / SmallEiffel / sys / runtime / gc_lib.c < prev    next >
Text File  |  1999-06-05  |  14KB  |  643 lines

  1. /*
  2. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  3. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  4. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  5. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  6. -- this header is kept unaltered, and a notification of the changes is added.
  7. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  8. -- another product.
  9. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  10. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  11. --                       http://www.loria.fr/SmallEiffel
  12. --
  13. */
  14.  
  15. /* This file is automatically included when the Garbage Collector
  16.    is used (default, unless option -no_gc has been selected).
  17. */
  18.  
  19. void**stack_bottom;
  20. mch**gcmt=NULL;
  21. int gcmt_max=2048;
  22. int gcmt_used=0;
  23. fsoc*fsocfl=NULL;
  24. rsoc*rsocfl=NULL;
  25. int gc_is_off=1;
  26. unsigned int fsoc_count=0;
  27. unsigned int rsoc_count=0;
  28. void*gcmt_tail_addr=NULL;
  29.  
  30. void gc_sweep(void) {
  31.   mch** p2 = gcmt;
  32.   mch** p1 = gcmt+1;
  33.   mch**eogcmt=gcmt+gcmt_used;
  34.   if (FREE_CHUNK((*p2)->state_type)) {
  35.     if (RSO_FREE_CHUNK == ((*p2)->state_type)) {
  36.       ((rsoc*)(*p2))->next=NULL;
  37.       rsocfl=((rsoc*)(*p2));
  38.     }
  39.     else {
  40.       rsocfl=NULL;
  41.     }    
  42.   }
  43.   else {
  44.     ((*gcmt)->swfp)(*p2);
  45.     if (RSO_FREE_CHUNK==((*p2)->state_type)) {
  46.       ((rsoc*)(*p2))->next=NULL;
  47.       rsocfl=((rsoc*)(*p2));
  48.     }
  49.     else {
  50.       rsocfl=NULL;
  51.     }
  52.   }
  53.   while (p1 < eogcmt) {
  54.     if (FREE_CHUNK((*p1)->state_type)) {
  55.       if (RSO_FREE_CHUNK == ((*p1)->state_type)) {
  56.     if (RSO_FREE_CHUNK == ((*p2)->state_type)) {
  57.       if (((char*)(*p2))+(*p2)->size == ((char*)(*p1))) {
  58.         ((*p2)->size)+=((*p1)->size);
  59.         p1++;
  60.       }
  61.       else {
  62.         ((rsoc*)(*p1))->next=rsocfl;
  63.         rsocfl=((rsoc*)(*p1));
  64.         *(p2+1)=*p1; p2++; p1++;
  65.       }
  66.     }
  67.     else {
  68.       ((rsoc*)(*p1))->next=rsocfl;
  69.       rsocfl=((rsoc*)(*p1));
  70.       *(p2+1)=*p1; p2++; p1++;
  71.     }
  72.       }
  73.       else {
  74.     *(p2+1)=*p1; p2++; p1++;
  75.       }
  76.     }
  77.     else {
  78.       ((*p1)->swfp)(*p1);
  79.       if (RSO_FREE_CHUNK == ((*p1)->state_type)) {
  80.     if (RSO_FREE_CHUNK == ((*p2)->state_type)) {
  81.       if (((char*)(*p2))+(*p2)->size == ((char*)(*p1))) {
  82.         ((*p2)->size)+=((*p1)->size);
  83.         p1++;
  84.       }
  85.       else {
  86.         ((rsoc*)(*p1))->next=rsocfl;
  87.         rsocfl=((rsoc*)(*p1));
  88.         *(p2+1)=*p1; p2++; p1++;
  89.       }
  90.     }
  91.     else {
  92.       ((rsoc*)(*p1))->next=rsocfl;
  93.       rsocfl=((rsoc*)(*p1));
  94.       *(p2+1)=*p1; p2++; p1++;
  95.     }
  96.       }
  97.       else {
  98.     *(p2+1)=*p1; p2++; p1++;
  99.       }
  100.     }
  101.   }
  102.   gcmt_used=(p2-gcmt)+1;
  103. }
  104.  
  105. void gc_mark(void*p) {
  106.   if ((p>((void*)*gcmt))&&(p<=gcmt_tail_addr)) {
  107.     int i1=0;
  108.     int i2=gcmt_used-1;
  109.     int m=i2>>1;
  110.     mch*c;
  111.     for (;i2>i1;m=((i1+i2)>>1)) {
  112.       if (p<=((void*)gcmt[m+1])) {
  113.     i2=m;
  114.       }
  115.       else {
  116.     i1=m+1;
  117.       }
  118.     }
  119.     c=gcmt[i2];
  120.     if (!(FREE_CHUNK(c->state_type))) {
  121.       (c->amfp)(c,p);
  122.     }
  123.   }
  124. }
  125.  
  126. int gc_stack_size(void) {
  127.   void*stack_top[2]={NULL,NULL};
  128.   if (stack_top > stack_bottom) {
  129.     return ((void**)stack_top)-((void**)stack_bottom);
  130.   }
  131.   else {
  132.     return ((void**)stack_bottom)-((void**)stack_top);
  133.   }
  134. }
  135.  
  136. /*
  137.   To delay Garbage Collection when the stack is too large.
  138.   To allow fast increase of ceils.
  139. */
  140. #define FSOC_LIMIT (10240/((FSOC_SIZE)>>10))
  141. #define RSOC_LIMIT (10240/((RSOC_SIZE)>>10)) 
  142.  
  143. /*
  144.   When stack is too large, collection may be delayed.
  145. */
  146. #define GCLARGESTACK 50000
  147.  
  148. int garbage_delayed(void) {
  149.   if (gc_stack_size() > GCLARGESTACK) {
  150.     if (fsoc_count_ceil <= fsoc_count) {
  151.       if (rsoc_count_ceil <= rsoc_count) {
  152.     if ((fsoc_count<FSOC_LIMIT)&&(rsoc_count<RSOC_LIMIT)) {
  153.       fsoc_count_ceil++;
  154.       rsoc_count_ceil++;
  155.     return 1;
  156.     }
  157.     else return 0;
  158.       }
  159.       else {
  160.     if (fsoc_count<FSOC_LIMIT) {
  161.       fsoc_count_ceil++;
  162.       return 1;
  163.     }
  164.     else return 0;
  165.       }
  166.     }
  167.     else {
  168.       if (rsoc_count_ceil <= rsoc_count) {
  169.     if (rsoc_count<RSOC_LIMIT) {
  170.       rsoc_count_ceil++;
  171.       return 1;
  172.     }
  173.     else return 0;
  174.       }
  175.       else return 0;
  176.     }
  177.   }
  178.   else {
  179.     return 0;
  180.   }
  181. }
  182.  
  183. void gc_update_ceils(void) {
  184.   int c;
  185.  
  186.   /* Compute fsoc_count_ceil :
  187.    */
  188.   if (fsocfl==NULL) {
  189.     if (fsoc_count >= fsoc_count_ceil) {
  190.       if (fsoc_count_ceil<FSOC_LIMIT) {
  191.     fsoc_count_ceil<<=1;
  192.       }
  193.       else { 
  194.     c=fsoc_count+(fsoc_count/3);
  195.     if (fsoc_count_ceil < c)
  196.       fsoc_count_ceil=c;
  197.       }
  198.     }
  199.   }
  200.   else
  201.     if (fsoc_count_ceil < fsoc_count)
  202.       fsoc_count_ceil=fsoc_count;
  203.   /* Compute rsoc_count_ceil :
  204.    */
  205.   if (rsocfl==NULL) {
  206.     if (rsoc_count>=rsoc_count_ceil) {
  207.       if (rsoc_count_ceil<RSOC_LIMIT) {
  208.     rsoc_count_ceil<<=1;
  209.       }
  210.       else { 
  211.     c=rsoc_count+(rsoc_count/3);
  212.     if (rsoc_count_ceil < c)
  213.       rsoc_count_ceil=c;
  214.       }
  215.     }
  216.   }
  217.   else
  218.     if (rsoc_count_ceil < rsoc_count)
  219.       rsoc_count_ceil=rsoc_count;
  220. }
  221.  
  222. static void add_to_gcmt(mch*c) {
  223.   mch**p;
  224.   if (gcmt_used==gcmt_max) {
  225.     gcmt_max<<=1;
  226.     gcmt=realloc(gcmt,(gcmt_max+1)*sizeof(void*));
  227.   }
  228.   for(p=gcmt+(gcmt_used++ -1);(p>=gcmt)&&(*p>c);p--)
  229.     *(p+1)=*p;
  230.   *(p+1)=c;
  231. }
  232.  
  233. fsoc*new_fsoc(void) {
  234.   if(fsocfl!=NULL){
  235.     fsoc*r=fsocfl;
  236.     fsocfl=fsocfl->next;
  237.     return r;
  238.   }
  239.   else {
  240.     mch*r=malloc(FSOC_SIZE);
  241.     mch**p;
  242.     gc_update_ceils();
  243.     fsoc_count++;
  244.     if (gcmt_used==gcmt_max) {
  245.       gcmt_max<<=1;
  246.       gcmt=realloc(gcmt,(gcmt_max+1)*sizeof(void*));
  247.     }
  248.     for (p=gcmt+(gcmt_used++ -1);(p>=gcmt)&&(*p>r);p--)
  249.       *(p+1)=*p;
  250.     *(p+1)=r;
  251.     return (fsoc*)r;
  252.   }
  253. }
  254.  
  255. static char*rso_from_store(na_env*nae,int size) {
  256.   rsoh*r=(nae->store);
  257.   nae->store_left-=size;
  258.   if ((nae->store_left) > sizeof(rsoh)) {
  259.     r->header.size=size;
  260.     nae->store=((rsoh*)(((char*)(nae->store))+size));
  261.   }
  262.   else {
  263.     r->header.size=size+nae->store_left;
  264.     nae->store_left=0;
  265.   }
  266.   (r->header.magic_flag)=RSOH_UNMARKED;
  267.   ((void)memset((r+1),0,r->header.size-sizeof(rsoh)));
  268.   return (char*)(r+1);
  269. }
  270.  
  271. static void rsoc_sweep(rsoc*c) {
  272.   na_env*nae=c->nae;
  273.   rsoh*gp=(rsoh*)&(c->first_header);
  274.   rsoh*pp;
  275.   rsoh*eoc=((rsoh*)(((char*)c)+c->header.size));
  276.   c->free_list_of_large=NULL;
  277.   if (c->header.size > RSOC_SIZE) {
  278.     if (gp->header.magic_flag == RSOH_MARKED) {
  279.       gp->header.magic_flag=RSOH_UNMARKED;
  280.       c->next=nae->chunk_list;
  281.       nae->chunk_list=c;
  282.     }
  283.     else {
  284.       c->header.state_type=RSO_FREE_CHUNK;
  285.     }
  286.     return;
  287.   }
  288.   while (gp<eoc) {
  289.     while (gp->header.magic_flag == RSOH_MARKED) {
  290.       gp->header.magic_flag=RSOH_UNMARKED;
  291.       gp=((rsoh*)(((char*)gp)+gp->header.size));
  292.       if(gp>=eoc) {
  293.     c->next=nae->chunk_list;
  294.     nae->chunk_list=c;
  295.     return;
  296.       }
  297.     }
  298.     gp->header.magic_flag=RSOH_FREE;
  299.     pp=(rsoh*)(((char*)gp)+gp->header.size);
  300.     while ((pp<eoc)&&(pp->header.magic_flag != RSOH_MARKED)) {
  301.       pp->header.magic_flag=RSOH_FREE;
  302.       gp->header.size+=pp->header.size;
  303.       pp=((rsoh*)(((char*)pp)+pp->header.size));
  304.     }
  305.     if (gp->header.size >= RSOC_MIN_STORE) {
  306.       if (nae->store_left==0) {
  307.     nae->store_left=gp->header.size;
  308.     nae->store=gp;
  309.     nae->store_chunk=c;
  310.       }
  311.       else if (nae->store->header.size < gp->header.size) {
  312.     ((fll_rsoh*)nae->store)->nextflol=nae->store_chunk->free_list_of_large;
  313.     nae->store_chunk->free_list_of_large=((fll_rsoh*)nae->store);
  314.     nae->store_left=gp->header.size;
  315.     nae->store=gp;
  316.     nae->store_chunk=c;
  317.       }
  318.       else {
  319.     ((fll_rsoh*)gp)->nextflol=c->free_list_of_large;
  320.     c->free_list_of_large=((fll_rsoh*)gp);
  321.       }
  322.     }
  323.     gp=pp;
  324.   }
  325.   if (((rsoh*)(&c->first_header))->header.size >= 
  326.       (c->header.size-sizeof(rsoc)+sizeof(rsoh))){
  327.     c->header.state_type=RSO_FREE_CHUNK;
  328.     nae->store_chunk=NULL;
  329.     nae->store_left=0; 
  330.   }
  331.   else{
  332.     c->next=nae->chunk_list;
  333.     nae->chunk_list=c;
  334.   }
  335. }
  336.  
  337. static rsoc MRSOC = {
  338.     {
  339.     RSOC_SIZE,
  340.     RSO_USED_CHUNK,
  341.     ((void(*)(mch*,void*))gcna_align_mark),
  342.     ((void(*)(mch*))rsoc_sweep)
  343.     },
  344.     NULL,
  345.     NULL,
  346.     NULL,
  347.     {
  348.       {
  349.     0,
  350.     RSOH_MARKED
  351.       }
  352.     }
  353. };
  354.  
  355. static void rsoc_malloc(na_env*nae){
  356.   rsoc*r=malloc(RSOC_SIZE);
  357.   rsoc_count++;
  358.   *r=MRSOC;
  359.   r->nae=nae;
  360.   nae->store=(&(r->first_header));
  361.   nae->store_left=RSOC_SIZE-sizeof(rsoc)+sizeof(rsoh);
  362.   nae->store_chunk=r;
  363.   r->next=nae->chunk_list;
  364.   nae->chunk_list=r;
  365.   add_to_gcmt((mch*)r);
  366. }
  367.  
  368. static rsoc* rsocfl_best_fit(int size) {
  369.   int best_size;
  370.   rsoc *pc,*best_pc,*best_c, *c;
  371.   if (rsocfl==NULL)
  372.     return NULL;
  373.   pc=NULL;
  374.   best_pc=NULL;
  375.   best_c=NULL;
  376.   c=rsocfl;
  377.   while ((NULL!=c)&&(NULL==best_c)){
  378.     if (c->header.size>=size){
  379.       best_c=c;
  380.       best_pc=pc;
  381.       best_size=c->header.size;
  382.     }
  383.     pc=c;
  384.     c=c->next;
  385.   }
  386.   if (NULL==c){
  387.     if (best_pc != NULL)
  388.       best_pc->next=best_c->next;
  389.     else if (best_c==rsocfl)
  390.       rsocfl=best_c->next;
  391.     return best_c;
  392.   }
  393.   do{
  394.     if ((c->header.size>=size)&&(c->header.size<best_size)){    
  395.       best_c=c;
  396.       best_pc=pc;
  397.       best_size=c->header.size;
  398.     }
  399.     pc=c;
  400.     c=c->next;
  401.   } while(c!=NULL);
  402.   if (NULL==best_pc) {
  403.     rsocfl = best_c->next;
  404.   }
  405.   else {
  406.     best_pc->next=best_c->next;
  407.   }
  408.   return best_c;
  409. }
  410.  
  411. static int get_store_in(rsoc*c,int size) {
  412.   na_env*nae=c->nae;
  413.   fll_rsoh*pf=NULL;
  414.   fll_rsoh*f=c->free_list_of_large;
  415.   while (f != NULL) {
  416.     if (f->rsoh_field.size >= size) {
  417.       nae->store_left=f->rsoh_field.size;
  418.       nae->store=(rsoh*)f;
  419.       nae->store_chunk=c;
  420.       if (pf == NULL) {
  421.     c->free_list_of_large=f->nextflol;
  422.       }
  423.       else {
  424.     pf->nextflol=f->nextflol;
  425.       }
  426.       return 1;
  427.     }
  428.     pf = f;
  429.     f = f->nextflol;
  430.   }
  431.   return 0;
  432. }
  433.  
  434. char*new_na_from_chunk_list(na_env*nae,int size) {
  435.   rsoc*c=nae->chunk_list;
  436.   int csize;
  437.   while (c != NULL) {
  438.     if (get_store_in(c,size)) {
  439.       return rso_from_store(nae,size);
  440.     }    
  441.     c = c->next;
  442.   }
  443.   csize=size+(sizeof(rsoc)-sizeof(rsoh));
  444.   c=rsocfl_best_fit(csize);
  445.   if (c != NULL){
  446.     if ((c->header.size > RSOC_SIZE)
  447.     &&
  448.     (c->header.size-csize > RSOC_MIN_STORE*4)) {
  449.       int csize_left=c->header.size-csize;
  450.       if ((csize_left%sizeof(double))!=0) {
  451.     csize_left-=(csize_left%sizeof(double));
  452.     csize=c->header.size-csize_left;
  453.       }
  454.       c->header.size=csize_left;
  455.       c->next=rsocfl;
  456.       rsocfl=c;
  457.       c=(rsoc*)(((char*)c)+csize_left);
  458.       add_to_gcmt((mch*)c);
  459.       c->header.amfp=(void(*)(mch*,void*))gcna_align_mark;
  460.       c->header.swfp=(void(*)(mch*))rsoc_sweep;
  461.     }
  462.     else {
  463.       csize=c->header.size;
  464.     }
  465.     c->header.size=csize;
  466.     c->header.state_type=RSO_USED_CHUNK;
  467.     c->free_list_of_large=NULL;
  468.     c->nae=nae;
  469.     nae->store=(&(c->first_header));
  470.     nae->store_left=csize-sizeof(rsoc)+sizeof(rsoh);
  471.     nae->store_chunk=c;
  472.     c->next=nae->chunk_list;
  473.     nae->chunk_list=c;
  474.     return rso_from_store(nae,size);
  475.   }
  476.   return NULL;
  477. }
  478.  
  479. char*new_na(na_env*nae,int size) { 
  480.   if (nae->store_left>0) {
  481.     nae->store->header.size=nae->store_left;
  482.     nae->store->header.magic_flag=RSOH_FREE;
  483.     if (nae->store_left >= RSOC_MIN_STORE) {
  484.       ((fll_rsoh*)(nae->store))->nextflol=nae->store_chunk->free_list_of_large;
  485.       nae->store_chunk->free_list_of_large=((fll_rsoh*)nae->store);
  486.     }
  487.     nae->store_left=0;
  488.   }
  489.   if ((nae->store_chunk!=NULL)&&(get_store_in(nae->store_chunk,size))) {
  490.     return rso_from_store(nae,size);
  491.   }
  492.   {
  493.     char*r=new_na_from_chunk_list(nae,size);
  494.     if (r!=NULL)
  495.       return r;
  496.   }
  497.   if (rsoc_count<rsoc_count_ceil) {
  498.     if((size+sizeof(rsoc)-sizeof(rsoh))>RSOC_SIZE){
  499.       rsoc*c=malloc(size+sizeof(rsoc)-sizeof(rsoh));
  500.       rsoh*r=(&(c->first_header));
  501.       rsoc_count++;
  502.       *c=MRSOC;
  503.       c->header.size=size+sizeof(rsoc)-sizeof(rsoh);
  504.       c->nae=nae;
  505.       c->next=nae->chunk_list;
  506.       nae->chunk_list=c;
  507.       add_to_gcmt((mch*)c);
  508.       r->header.size=size;
  509.       (r->header.magic_flag)=RSOH_UNMARKED;
  510.       ((void)memset((r+1),0,size-sizeof(rsoh)));
  511.       return (char*)(r+1);
  512.     }
  513.     else {
  514.       rsoc_malloc(nae);
  515.       return rso_from_store(nae,size);
  516.     }
  517.   }
  518.   gc_start();
  519.   if (size<=(nae->store_left)) {
  520.     return rso_from_store(nae,size);
  521.   }
  522.   {
  523.     char*r=new_na_from_chunk_list(nae,size);
  524.     if (r!=NULL) {
  525.       return r;
  526.     }
  527.   }
  528.   if((size+sizeof(rsoc)-sizeof(rsoh))>RSOC_SIZE){
  529.     rsoc*c=malloc(size+sizeof(rsoc)-sizeof(rsoh));
  530.     rsoh*r=(&(c->first_header));
  531.     rsoc_count++;
  532.     *c=MRSOC;
  533.     c->header.size=size+sizeof(rsoc)-sizeof(rsoh);
  534.     c->nae=nae;
  535.     c->next=nae->chunk_list;
  536.     nae->chunk_list=c;
  537.     add_to_gcmt((mch*)c);
  538.     r->header.size=size;
  539.     (r->header.magic_flag)=RSOH_UNMARKED;
  540.     ((void)memset((r+1),0,size-sizeof(rsoh)));
  541.     gc_update_ceils();
  542.     return (char*)(r+1);
  543.   }
  544.   else {
  545.     rsoc_malloc(nae);
  546.     gc_update_ceils();
  547.     return rso_from_store(nae,size);
  548.   }
  549. }
  550.  
  551. void gcna_align_mark(rsoc*c,void*o) {
  552.   na_env* nae = c->nae;
  553.   fll_rsoh* f;
  554.   fll_rsoh* pf;
  555.   char* b = (char*)&(c->first_header);
  556.   if (((char*)o) > (((char*)c)+c->header.size)) {
  557.       return;
  558.   }
  559.   if (((((char*)o)-((char*)c))%sizeof(int)) != 0) {
  560.       return;
  561.   }
  562.   if ((((rsoh*)o)-1)->header.magic_flag != RSOH_UNMARKED) {
  563.       return;
  564.   }
  565.   if (((char*)o) < ((char*)(c+1))) {
  566.       return;
  567.   }
  568.   if (c->header.size > RSOC_SIZE) {
  569.       if (o == (c+1)) {
  570.       nae->gc_mark(o);
  571.       }
  572.       return;
  573.   }
  574.   pf=NULL;
  575.   f=c->free_list_of_large;
  576.   while ((f != NULL) && (f < ((fll_rsoh*)o))) {
  577.       pf=f;
  578.       f=f->nextflol;
  579.   }
  580.   if (pf == NULL) {
  581.       pf=(fll_rsoh*)b;
  582.   }
  583.   while ((((rsoh*)pf)+1) < (rsoh*)o) {
  584.       pf = ((fll_rsoh*)(((char*)pf)+pf->rsoh_field.size));
  585.   }
  586.   {void* tmp = (((rsoh*)pf)+1);
  587.   if (o == tmp) {
  588.       nae->gc_mark(o);
  589.   } 
  590.   } 
  591. }
  592.  
  593. int rsocfl_count(void) {
  594.   int r=0;
  595.   rsoc*p=rsocfl;
  596.   while (p!=NULL) {
  597.     r++;
  598.     p=p->next;
  599.   }
  600.   return r;
  601. }
  602.  
  603. int fsocfl_count(void) {
  604.   int r=0;
  605.   fsoc*p=fsocfl;
  606.   while (p!=NULL) {
  607.     r++;
  608.     p=p->next;
  609.   }
  610.   return r;
  611. }
  612.  
  613. void rsocfl_info(void) {
  614.   int max=0;
  615.   rsoc*p=rsocfl;
  616.   printf(" rsocfl count = %d\n",rsocfl_count());
  617.   if (p!=NULL) {
  618.     printf(" rsocfl = [");
  619.     p=rsocfl;
  620.     while (p!=NULL) {
  621.       printf("%d",p->header.size);
  622.       if(max < p->header.size) max=p->header.size;
  623.       p=p->next;
  624.       if (p!=NULL)printf(",");
  625.     }
  626.     printf("]\n");
  627.     printf(" rsocfl max = %d\n",max);
  628.   }
  629. }
  630.  
  631. void gc_dispose_before_exit(void) {
  632.   mch** p = gcmt;
  633.   mch**eogcmt=gcmt+gcmt_used;
  634.     
  635.   while (p < eogcmt) {
  636.     if (((*p)->state_type == FSO_STORE_CHUNK) || 
  637.     ((*p)->state_type == FSO_USED_CHUNK)) {
  638.       ((*p)->swfp)(*p);
  639.     }
  640.     p++;
  641.   }
  642. }
  643.