switch to spaces only..
[IRC.git] / Robust / src / Runtime / garbage.c
1 #include "garbage.h"
2 #include "runtime.h"
3 #include "structdefs.h"
4 #include "Queue.h"
5 #include "SimpleHash.h"
6 #include "chash.h"
7 #include "GenericHashtable.h"
8 #include <string.h>
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
10 #include "thread.h"
11 #endif
12 #ifdef MLP
13 #include "workschedule.h"
14 #endif
15
16 #ifdef DMALLOC
17 #include "dmalloc.h"
18 #endif
19 #ifdef DSTM
20 #ifdef RECOVERY
21 #include <DSTM/interface_recovery/dstm.h>
22 #else
23 #include <DSTM/interface/dstm.h>
24 #endif
25 #endif
26 #ifdef STM
27 #include "tm.h"
28 #endif
29 #ifdef DELAYCOMP
30 #include "delaycomp.h"
31 #endif
32
33
34 #ifndef INITIALHEAPSIZE_MB
35 #define INITIALHEAPSIZE_MB (256)
36 #endif
37
38 #define INITIALHEAPSIZE INITIALHEAPSIZE_MB*1024*1024L
39 #define GCPOINT(x) ((INTPTR)((x)*0.99))
40 /* This define takes in how full the heap is initially and returns a new heap size to use */
41 #define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
42
43 #ifdef GARBAGESTATS
44 #define MAXSTATS 500
45 long garbagearray[MAXSTATS];
46 #endif
47
48 #if defined(THREADS) || defined(DSTM) || defined(STM)||defined(MLP)
49 int needtocollect=0;
50 struct listitem * list=NULL;
51 int listcount=0;
52 #ifndef MAC
53 __thread struct listitem litem;
54 #endif
55 #endif
56
57 //Need to check if pointers are transaction pointers
58 //this also catches the special flag value of 1 for local copies
59
60 void * curr_heapbase=0;
61 void * curr_heapptr=0;
62 void * curr_heapgcpoint=0;
63 void * curr_heaptop=0;
64
65 void * to_heapbase=0;
66 void * to_heapptr=0;
67 void * to_heaptop=0;
68 long lastgcsize=0;
69
70
71 struct pointerblock *head=NULL;
72 int headindex=0;
73 struct pointerblock *tail=NULL;
74 int tailindex=0;
75 struct pointerblock *spare=NULL;
76
77 void enqueue(void *ptr) {
78   if (headindex==NUMPTRS) {
79     struct pointerblock * tmp;
80     if (spare!=NULL) {
81       tmp=spare;
82       spare=NULL;
83     } else tmp=malloc(sizeof(struct pointerblock));
84     head->next=tmp;
85     head=tmp;
86     headindex=0;
87   }
88   head->ptrs[headindex++]=ptr;
89 }
90
91 void * dequeue() {
92   if (tailindex==NUMPTRS) {
93     struct pointerblock *tmp=tail;
94     tail=tail->next;
95     tailindex=0;
96     if (spare!=NULL)
97       free(tmp);
98     else
99       spare=tmp;
100   }
101   return tail->ptrs[tailindex++];
102 }
103
104 #ifdef STM
105 void fixobjlist(struct objlist * ptr) {
106   while(ptr!=NULL) {
107     int i;
108     for(i=0; i<ptr->offset; i++) {
109       SENQUEUE(ptr->objs[i], ptr->objs[i]);
110     }
111     ptr=ptr->next;
112   }
113 }
114
115 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
116   unsigned int mask=(tc_size<<4)-1;
117   chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
118   chashlistnode_t *ptr=*tc_table;
119   chashlistnode_t *curr;
120   unsigned int i;
121   unsigned int index;
122   int isfirst;
123   chashlistnode_t *newlist=NULL;
124   for(i=0; i<tc_size; i++) {
125     curr=&ptr[i];
126     isfirst=1;
127     do {                      //Inner loop to go through linked lists
128       void * key;
129       chashlistnode_t *tmp,*next;
130
131       if ((key=(void *)curr->key) == 0) {             //Exit inner loop if there the first element is 0
132         break;                  //key = val =0 for element if not present within the hash table
133       }
134       SENQUEUE(key, key);
135       if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
136         SENQUEUE(curr->val, curr->val);
137       } else {
138         //rewrite transaction cache entry
139         void *vptr=curr->val;
140         int type=((int *)vptr)[0];
141         unsigned INTPTR *pointer=pointerarray[type];
142         if (pointer==0) {
143           //array of primitives - do nothing
144           struct ArrayObject *ao=(struct ArrayObject *) vptr;
145           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
146         } else if (((INTPTR)pointer)==1) {
147           //array of pointers
148           struct ArrayObject *ao=(struct ArrayObject *) vptr;
149           int length=ao->___length___;
150           int i;
151           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
152 #ifdef STMARRAY
153           int lowindex=ao->lowindex;
154           int highindex=ao->highindex;
155           int j;
156           for(j=lowindex; j<=highindex; j++) {
157             unsigned int lockval;
158             GETLOCKVAL(lockval, ao, j);
159             if (lockval!=STMNONE) {
160               int lowi=(j<<INDEXSHIFT)/sizeof(void *);
161               int highi=lowi+(INDEXLENGTH/sizeof(void *));
162               for(i=lowi; i<highi; i++) {
163 #else
164           for(i=0; i<length; i++) {
165 #endif
166                 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
167                 SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
168               }
169 #ifdef STMARRAY
170             }
171           }
172 #endif
173             } else {
174               INTPTR size=pointer[0];
175               int i;
176               for(i=1; i<=size; i++) {
177                 unsigned int offset=pointer[i];
178                 void * objptr=*((void **)(((char *)vptr)+offset));
179                 SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
180               }
181             }
182           }
183
184           next = curr->next;
185           index = (((unsigned INTPTR)key) & mask) >>4;
186
187           curr->key=key;
188           tmp=&node[index];
189           // Insert into the new table
190           if(tmp->key == 0) {
191             tmp->key = curr->key;
192             tmp->val = curr->val;
193             tmp->lnext=newlist;
194             newlist=tmp;
195           } else if (isfirst) {
196             chashlistnode_t *newnode;
197             if ((*cstr)->num<NUMCLIST) {
198               newnode=&(*cstr)->array[(*cstr)->num];
199               (*cstr)->num++;
200             } else {
201               //get new list
202               cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
203               tcl->next=*cstr;
204               *cstr=tcl;
205               newnode=&tcl->array[0];
206               tcl->num=1;
207             }
208             newnode->key = curr->key;
209             newnode->val = curr->val;
210             newnode->next = tmp->next;
211             newnode->lnext=newlist;
212             newlist=newnode;
213             tmp->next=newnode;
214           } else {
215             curr->lnext=newlist;
216             newlist=curr;
217             curr->next=tmp->next;
218             tmp->next=curr;
219           }
220           isfirst = 0;
221           curr = next;
222         }
223         while(curr!=NULL) ;
224       }
225       free(ptr);
226       (*tc_table)=node;
227       (*tc_list)=newlist;
228     }
229 #endif
230
231 int moreItems() {
232   if ((head==tail)&&(tailindex==headindex))
233     return 0;
234   return 1;
235 }
236
237
238 #if defined(STM)||defined(THREADS)||defined(MLP)
239 #ifndef MAC
240 __thread char * memorybase=NULL;
241 __thread char * memorytop=NULL;
242 #endif
243 #endif
244
245 void initqueues() {
246   if (head==NULL) {
247     headindex=0;
248     tailindex=0;
249     head=tail=malloc(sizeof(struct pointerblock));
250   }
251
252 #ifdef TASK
253   if (taghead==NULL) {
254     tagindex=0;
255     taghead=malloc(sizeof(struct pointerblock));
256     taghead->next=NULL;
257   }
258 #endif
259 }
260
261 void doinitstuff() {
262 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
263   needtocollect=1;
264   pthread_mutex_lock(&gclistlock);
265   while(1) {
266     if ((listcount+1)==threadcount) {
267       break; /* Have all other threads stopped */
268     }
269     pthread_cond_wait(&gccond, &gclistlock);
270   }
271 #endif
272
273 #ifdef GARBAGESTATS
274   {
275     int i;
276     for(i=0; i<MAXSTATS; i++)
277       garbagearray[i]=0;
278   }
279 #endif
280   initqueues();
281
282 #ifdef STM
283   litem.tc_size=c_size;
284   litem.tc_table=&c_table;
285   litem.tc_list=&c_list;
286   litem.tc_structs=&c_structs;
287   litem.objlist=newobjs;
288 #ifdef STMSTATS
289   litem.lockedlist=lockedobjs;
290 #endif
291 #endif
292 #if defined(STM)||defined(THREADS)||defined(MLP)
293 #ifdef MAC
294   struct listitem *litem=pthread_getspecific(litemkey);
295   litem->base=((char **)pthread_getspecific(memorybasekey));
296 #else
297   litem.base=&memorybase;
298 #endif
299 #endif
300 }
301
302 void searchglobalroots() {
303 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
304   {
305     int i;
306     struct garbagelist * stackptr=(struct garbagelist *)global_defs_p;
307     for(i=0; i<stackptr->size; i++) {
308       void * orig=stackptr->array[i];
309       ENQUEUE(orig, stackptr->array[i]);
310     }
311   }
312 #endif
313 }
314
315 void searchstack(struct garbagelist *stackptr) {
316   while(stackptr!=NULL) {
317     int i;
318     for(i=0; i<stackptr->size; i++) {
319       void * orig=stackptr->array[i];
320       ENQUEUE(orig, stackptr->array[i]);
321     }
322     stackptr=stackptr->next;
323   }
324 }
325
326 #ifdef JNI
327 void searchjnitable(struct jnireferences *jniptr) {
328   while(jniptr!=NULL) {
329     int i;
330     //update table
331     for(i=0; i<jniptr->index; i++) {
332       ENQUEUE((struct ___Object___ *)jniptr->array[i].ref, *((struct ___Object___**)&jniptr->array[i].ref));
333     }
334     //go to next table
335     jniptr=jniptr->next;
336   }
337 }
338 #endif
339
340 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
341 void searchthreadroots(struct garbagelist * stackptr) {
342   /* Check current stack */
343   struct listitem *listptr=list;
344 #ifdef MAC
345   struct listitem *litem=pthread_getspecific(litemkey);
346   litem->stackptr=stackptr;
347 #else
348   litem.stackptr=stackptr;
349 #endif
350
351   while(listptr!=NULL) {
352     searchstack(listptr->stackptr);
353 #ifdef THREADS
354     struct lockvector * lvector=listptr->lvector;
355     int i;
356     for(i=0; i<lvector->index; i++) {
357       struct ___Object___ *orig=lvector->locks[i].object;
358       ENQUEUE(orig, lvector->locks[i].object);
359     }
360 #endif
361 #ifdef JNI
362     searchjnitable(*listptr->jnirefs);
363 #endif
364 #ifdef STM
365     if ((*listptr->tc_table)!=NULL) {
366       fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
367       fixobjlist(listptr->objlist);
368 #ifdef STMSTATS
369       fixobjlist(listptr->lockedlist);
370 #endif
371     }
372 #endif
373 #if defined(STM)||defined(THREADS)||defined(MLP)
374     *(listptr->base)=NULL;
375 #endif
376 #ifdef MLP
377     // update forward list & memory queue for all running SESEs.
378     if (listptr->seseCommon!=NULL) {
379       updateForwardList(&((SESEcommon*)listptr->seseCommon)->forwardList,FALSE);
380       updateMemoryQueue((SESEcommon*)(listptr->seseCommon));
381     }
382 #endif
383     listptr=listptr->next;
384   }
385 }
386 #endif
387
388 void searchroots(struct garbagelist * stackptr) {
389 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
390   searchthreadroots(stackptr);
391 #else
392   searchstack(stackptr);
393 #endif
394 #ifdef FASTCHECK
395   ENQUEUE(___fcrevert___, ___fcrevert___);
396 #endif
397   searchglobalroots();
398 #ifdef TASK
399   searchtaskroots();
400 #endif
401 #ifdef MLP
402   searchoojroots();
403 #endif
404 }
405
406 void collect(struct garbagelist * stackptr) {
407   doinitstuff();
408
409 #ifdef DELAYCOMP
410   ptrstack.prev=stackptr;
411   stackptr=(struct garbagelist *) &ptrstack;
412 #if defined(STMARRAY)&&!defined(DUALVIEW)
413   arraystack.prev=stackptr;
414   stackptr=(struct garbagelist *) &arraystack;
415 #endif
416 #endif
417
418   searchroots(stackptr);
419
420   while(moreItems()) {
421     void * ptr=dequeue();
422     void *cpy=ptr;
423     int type=((int *)cpy)[0];
424     unsigned INTPTR * pointer;
425 #ifdef TASK
426     if(type==TAGTYPE) {
427       /* Enqueue Tag */
428       /* Nothing is inside */
429       enqueuetag(ptr);
430       continue;
431     }
432 #endif
433     pointer=pointerarray[type];
434     if (pointer==0) {
435       /* Array of primitives */
436       /* Do nothing */
437 #if defined(DSTM)||defined(FASTCHECK)
438       struct ArrayObject *ao=(struct ArrayObject *) ptr;
439       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
440       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
441       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
442 #endif
443 #if defined(STM)
444       struct ArrayObject *ao=(struct ArrayObject *) ptr;
445       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
446       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
447 #endif
448     } else if (((INTPTR)pointer)==1) {
449       /* Array of pointers */
450       struct ArrayObject *ao=(struct ArrayObject *) ptr;
451       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
452 #if (defined(DSTM)||defined(FASTCHECK))
453       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
454       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
455 #endif
456 #if defined(STM)
457       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
458 #endif
459       int length=ao->___length___;
460       int i;
461       for(i=0; i<length; i++) {
462         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
463         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
464       }
465     } else {
466       INTPTR size=pointer[0];
467       int i;
468       for(i=1; i<=size; i++) {
469         unsigned int offset=pointer[i];
470         void * objptr=*((void **)(((char *)ptr)+offset));
471         ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
472       }
473     }
474   }
475 #ifdef TASK
476   fixtags();
477 #endif
478
479 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
480   needtocollect=0;
481   pthread_mutex_unlock(&gclistlock);
482 #endif
483 }
484
485 void * tomalloc(int size) {
486   void * ptr=to_heapptr;
487   if ((size&7)!=0)
488     size+=(8-(size%8));
489   to_heapptr+=size;
490   return ptr;
491 }
492
493 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
494 void checkcollect(void * ptr) {
495   stopforgc((struct garbagelist *)ptr);
496   restartaftergc();
497 }
498
499 #ifdef DSTM
500 void checkcollect2(void * ptr) {
501   int ptrarray[]={1, (int)ptr, (int) revertlist};
502   stopforgc((struct garbagelist *)ptrarray);
503   restartaftergc();
504   revertlist=(struct ___Object___*)ptrarray[2];
505 }
506 #endif
507
508 void stopforgc(struct garbagelist * ptr) {
509 #ifdef DELAYCOMP
510   //just append us to the list
511   ptrstack.prev=ptr;
512   ptr=(struct garbagelist *) &ptrstack;
513 #if defined(STMARRAY)&&!defined(DUALVIEW)
514   arraystack.prev=ptr;
515   ptr=(struct garbagelist *) &arraystack;
516 #endif
517 #endif
518 #ifndef MAC
519   litem.stackptr=ptr;
520 #if defined(STM)||defined(THREADS)||defined(MLP)
521   litem.base=&memorybase;
522 #endif
523 #ifdef STM
524   litem.tc_size=c_size;
525   litem.tc_table=&c_table;
526   litem.tc_list=&c_list;
527   litem.tc_structs=&c_structs;
528   litem.objlist=newobjs;
529 #ifdef STMSTATS
530   litem.lockedlist=lockedobjs;
531 #endif
532 #endif
533 #else
534   //handle MAC
535   struct listitem *litem=pthread_getspecific(litemkey);
536   litem->stackptr=ptr;
537 #if defined(STM)||defined(THREADS)||defined(MLP)
538   litem->base=pthread_getspecific(memorybasekey);
539 #endif
540 #endif
541   pthread_mutex_lock(&gclistlock);
542   listcount++;
543   if ((listcount+1)==threadcount) {
544     //only do wakeup if we are ready to GC
545     pthread_cond_signal(&gccond);
546   }
547   pthread_mutex_unlock(&gclistlock);
548 }
549
550 void restartaftergc() {
551   if (needtocollect) {
552     pthread_mutex_lock(&gclock); // Wait for GC
553     pthread_mutex_unlock(&gclock);
554   }
555   pthread_mutex_lock(&gclistlock);
556   listcount--;
557   pthread_mutex_unlock(&gclistlock);
558 #ifdef THREADS
559 #ifdef MAC
560   struct listitem *litem=pthread_getspecific(litemkey);
561 #endif
562 #endif
563 }
564 #endif
565
566 #if defined(STM)||defined(THREADS)||defined(MLP)
567 #define MEMORYBLOCK 65536
568 void * helper(struct garbagelist *, int);
569 void * mygcmalloc(struct garbagelist * stackptr, int size) {
570   if ((size&7)!=0)
571     size=(size&~7)+8;
572 #ifdef MAC
573   char * memorybase=*(char **)pthread_getspecific(memorybasekey);
574   char * memorytop=*(char **)pthread_getspecific(memorytopkey);
575 #endif
576   if (memorybase==NULL||size>(memorytop-memorybase)) {
577     int toallocate=(size>MEMORYBLOCK) ? size : MEMORYBLOCK;
578     memorybase=helper(stackptr, toallocate);
579     bzero(memorybase, toallocate);
580     memorytop=memorybase+toallocate;
581   }
582   char *retvalue=memorybase;
583   memorybase+=size;
584 #ifdef MAC
585   *(char **)pthread_getspecific(memorybasekey)=memorybase;
586   *(char **)pthread_getspecific(memorytopkey)=memorytop;
587 #endif
588   return retvalue;
589 }
590
591 void * helper(struct garbagelist * stackptr, int size) {
592 #else
593 void * mygcmalloc(struct garbagelist * stackptr, int size) {
594 #endif
595   void *ptr;
596 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
597   while (pthread_mutex_trylock(&gclock)!=0) {
598     stopforgc(stackptr);
599     restartaftergc();
600   }
601 #endif
602   ptr=curr_heapptr;
603   if ((size&7)!=0)
604     size=(size&~7)+8;
605   curr_heapptr+=size;
606   if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
607     if (curr_heapbase==0) {
608       /* Need to allocate base heap */
609       curr_heapbase=malloc(INITIALHEAPSIZE);
610       if (curr_heapbase==NULL) {
611         printf("malloc failed.  Garbage colletcor couldn't get enough memory.  Try changing heap size.\n");
612         exit(-1);
613       }
614 #if defined(STM)||defined(THREADS)||defined(MLP)
615 #else
616       bzero(curr_heapbase, INITIALHEAPSIZE);
617 #endif
618       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
619       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
620       curr_heapptr=curr_heapbase+size;
621
622       to_heapbase=malloc(INITIALHEAPSIZE);
623       if (to_heapbase==NULL) {
624         printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
625         exit(-1);
626       }
627
628       to_heaptop=to_heapbase+INITIALHEAPSIZE;
629       to_heapptr=to_heapbase;
630       ptr=curr_heapbase;
631 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
632       pthread_mutex_unlock(&gclock);
633 #endif
634       return ptr;
635     }
636
637     /* Grow the to heap if necessary */
638     {
639       INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
640       INTPTR to_heapsize=to_heaptop-to_heapbase;
641       INTPTR last_heapsize=0;
642       if (lastgcsize>0) {
643         last_heapsize=HEAPSIZE(lastgcsize, size);
644         if ((last_heapsize&7)!=0)
645           last_heapsize+=(8-(last_heapsize%8));
646       }
647       if (curr_heapsize>last_heapsize)
648         last_heapsize=curr_heapsize;
649       if (last_heapsize>to_heapsize) {
650         free(to_heapbase);
651         to_heapbase=malloc(last_heapsize);
652         if (to_heapbase==NULL) {
653           printf("Error Allocating enough memory\n");
654           exit(-1);
655         }
656         to_heaptop=to_heapbase+last_heapsize;
657         to_heapptr=to_heapbase;
658       }
659     }
660
661     /* Do our collection */
662     collect(stackptr);
663
664     /* Update stat on previous gc size */
665     lastgcsize=(to_heapptr-to_heapbase)+size;
666
667 #ifdef GARBAGESTATS
668     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
669     printf("New space: %u\n", to_heapptr-to_heapbase);
670     printf("Total space: %u\n", to_heaptop-to_heapbase);
671     {
672       int i;
673       for(i=0; i<MAXSTATS; i++) {
674         if (garbagearray[i]!=0)
675           printf("Type=%d Size=%u\n", i, garbagearray[i]);
676       }
677     }
678 #endif
679     /* Flip to/curr heaps */
680     {
681       void * tmp=to_heapbase;
682       to_heapbase=curr_heapbase;
683       curr_heapbase=tmp;
684
685       tmp=to_heaptop;
686       to_heaptop=curr_heaptop;
687       curr_heaptop=tmp;
688
689       tmp=to_heapptr;
690       curr_heapptr=to_heapptr+size;
691       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
692       to_heapptr=to_heapbase;
693
694       /* Not enough room :(, redo gc */
695       if (curr_heapptr>curr_heapgcpoint) {
696 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
697         pthread_mutex_unlock(&gclock);
698 #endif
699         return mygcmalloc(stackptr, size);
700       }
701
702       bzero(tmp, curr_heaptop-tmp);
703 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
704       pthread_mutex_unlock(&gclock);
705 #endif
706       return tmp;
707     }
708   } else {
709 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
710     pthread_mutex_unlock(&gclock);
711 #endif
712     return ptr;
713   }
714 }
715
716 int gc_createcopy(void * orig, void ** copy_ptr) {
717   if (orig==0) {
718     *copy_ptr=NULL;
719     return 0;
720   } else {
721     int type=((int *)orig)[0];
722     if (type==-1) {
723       *copy_ptr=((void **)orig)[1];
724       return 0;
725     }
726     if (type<NUMCLASSES) {
727       /* We have a normal object */
728 #ifdef STM
729       int size=classsize[type]+sizeof(objheader_t);
730       void *newobj=tomalloc(size);
731       memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
732       newobj=((char *)newobj)+sizeof(objheader_t);
733 #else
734       int size=classsize[type];
735       void *newobj=tomalloc(size);
736       memcpy(newobj, orig, size);
737 #endif
738 #ifdef GARBAGESTATS
739       garbagearray[type]+=size;
740 #endif
741       ((int *)orig)[0]=-1;
742       ((void **)orig)[1]=newobj;
743       *copy_ptr=newobj;
744       return 1;
745     } else {
746       /* We have an array */
747       struct ArrayObject *ao=(struct ArrayObject *)orig;
748       int elementsize=classsize[type];
749       int length=ao->___length___;
750 #ifdef STM
751 #ifdef STMARRAY
752       int basesize=length*elementsize;
753       basesize=(basesize+LOWMASK)&HIGHMASK;
754       int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
755       int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
756       void *newobj=tomalloc(size);
757       memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
758       newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
759 #else
760       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
761       void *newobj=tomalloc(size);
762       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
763       newobj=((char *)newobj)+sizeof(objheader_t);
764 #endif
765 #else
766       int size=sizeof(struct ArrayObject)+length*elementsize;
767       void *newobj=tomalloc(size);
768       memcpy(newobj, orig, size);
769 #endif
770 #ifdef GARBAGESTATS
771       garbagearray[type]+=size;
772 #endif
773       ((int *)orig)[0]=-1;
774       ((void **)orig)[1]=newobj;
775       *copy_ptr=newobj;
776       return 1;
777     }
778   }
779 }
780
781 int within(void *ptr) { //debug function
782   if(ptr>curr_heapptr || ptr<curr_heapbase) {
783     __asm__ __volatile__ ("int $3");  // breakpoint
784   }
785 }