large number of bug corrections
[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
13 #ifdef DMALLOC
14 #include "dmalloc.h"
15 #endif
16 #ifdef DSTM
17 #include "dstm.h"
18 #endif
19 #ifdef STM
20 #include "tm.h"
21 #endif
22
23 #define NUMPTRS 100
24
25 #define INITIALHEAPSIZE 128*1024*1024
26 #define GCPOINT(x) ((int)((x)*0.95))
27 /* This define takes in how full the heap is initially and returns a new heap size to use */
28 #define HEAPSIZE(x,y) ((int)(x+y))*2
29
30 #ifdef TASK
31 extern struct genhashtable * activetasks;
32 #ifndef MULTICORE
33 extern struct parameterwrapper * objectqueues[NUMCLASSES];
34 #endif
35 extern struct genhashtable * failedtasks;
36 extern struct taskparamdescriptor *currtpd;
37 extern struct ctable *forward;
38 extern struct ctable *reverse;
39 extern struct RuntimeHash *fdtoobject;
40 #endif
41
42 #if defined(THREADS) || defined(DSTM) || defined(STM)
43 int needtocollect=0;
44 struct listitem * list=NULL;
45 int listcount=0;
46 #endif
47
48 //Need to check if pointers are transaction pointers
49 //this also catches the special flag value of 1 for local copies
50 #ifdef DSTM
51 #define ENQUEUE(orig, dst) \
52   if ((!(((unsigned int)orig)&0x1))) { \
53     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
54       void *copy; \
55       if (gc_createcopy(orig,&copy)) \
56         enqueue(orig);\
57       dst=copy; \
58     } \
59   }
60 #elif defined(STM)
61 #define ENQUEUE(orig, dst) \
62   if (orig>=curr_heapbase&&orig<curr_heaptop) { \
63     void *copy; \
64     if (gc_createcopy(orig,&copy)) \
65       enqueue(orig);\
66     dst=copy; \
67   }
68 #define SENQUEUE(orig, dst) \
69   { \
70     void *copy; \
71     if (gc_createcopy(orig,&copy)) \
72       enqueue(orig);\
73     dst=copy; \
74   }
75 #elif defined(FASTCHECK)
76 #define ENQUEUE(orig, dst) \
77   if (((unsigned int)orig)!=1) { \
78     void *copy; \
79     if (gc_createcopy(orig,&copy)) \
80       enqueue(orig);\
81     dst=copy; }
82 #else
83 #define ENQUEUE(orig, dst) \
84   void *copy; \
85   if (gc_createcopy(orig,&copy)) \
86     enqueue(orig);\
87   dst=copy
88 #endif
89
90 struct pointerblock {
91   void * ptrs[NUMPTRS];
92   struct pointerblock *next;
93 };
94
95 void * curr_heapbase=0;
96 void * curr_heapptr=0;
97 void * curr_heapgcpoint=0;
98 void * curr_heaptop=0;
99
100 void * to_heapbase=0;
101 void * to_heapptr=0;
102 void * to_heaptop=0;
103 long lastgcsize=0;
104
105 struct pointerblock *head=NULL;
106 int headindex=0;
107 struct pointerblock *tail=NULL;
108 int tailindex=0;
109 struct pointerblock *spare=NULL;
110
111 void enqueue(void *ptr) {
112   if (headindex==NUMPTRS) {
113     struct pointerblock * tmp;
114     if (spare!=NULL) {
115       tmp=spare;
116       spare=NULL;
117     } else
118       tmp=malloc(sizeof(struct pointerblock));
119     head->next=tmp;
120     head=tmp;
121     headindex=0;
122   }
123   head->ptrs[headindex++]=ptr;
124 }
125
126 void * dequeue() {
127   if (tailindex==NUMPTRS) {
128     struct pointerblock *tmp=tail;
129     tail=tail->next;
130     tailindex=0;
131     if (spare!=NULL)
132       free(tmp);
133     else
134       spare=tmp;
135   }
136   return tail->ptrs[tailindex++];
137 }
138
139 #ifdef STM
140 void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
141   unsigned int mask=(tc_size<<1)-1;
142   chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
143   chashlistnode_t *ptr=*tc_table;
144   chashlistnode_t *curr;
145   unsigned int i;
146   unsigned int index;
147   int isfirst;
148   for(i=0;i<tc_size;i++) {
149     curr=&ptr[i];
150     isfirst=1;
151     do {                      //Inner loop to go through linked lists
152       void * key;
153       chashlistnode_t *tmp,*next;
154       
155       if ((key=(void *)curr->key) == 0) {             //Exit inner loop if there the first element is 0
156         break;                  //key = val =0 for element if not present within the hash table
157       }
158       SENQUEUE(key, key);
159       if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
160         SENQUEUE(curr->val, curr->val);
161       } else {
162         //rewrite transaction cache entry
163         void *vptr=curr->val;
164         int type=((int *)vptr)[0];
165         unsigned int *pointer=pointerarray[type];
166         if (pointer==0) {
167           //array of primitives - do nothing
168           struct ArrayObject *ao=(struct ArrayObject *) vptr;
169           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
170         } else if (((int)pointer)==1) {
171           //array of pointers
172           struct ArrayObject *ao=(struct ArrayObject *) vptr;
173           int length=ao->___length___;
174           int i;
175           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
176           for(i=0; i<length; i++) {
177             void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
178             SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
179           }
180         } else {
181           int size=pointer[0];
182           int i;
183           for(i=1; i<=size; i++) {
184             unsigned int offset=pointer[i];
185             void * objptr=*((void **)(((int)vptr)+offset));
186             SENQUEUE(objptr, *((void **)(((int)vptr)+offset)));
187           }
188         }
189       }
190
191       next = curr->next;
192       index = (((unsigned int)key) & mask) >>1;
193
194       curr->key=(unsigned int)key;
195       tmp=&node[index];
196       // Insert into the new table
197       if(tmp->key == 0) {
198         tmp->key = curr->key;
199         tmp->val = curr->val;
200         if (!isfirst) {
201           free(curr);
202         }
203       } else if (isfirst) {
204         chashlistnode_t *newnode= calloc(1, sizeof(chashlistnode_t));
205         newnode->key = curr->key;
206         newnode->val = curr->val;
207         newnode->next = tmp->next;
208         tmp->next=newnode;
209       } else {
210         curr->next=tmp->next;
211         tmp->next=curr;
212       }
213       isfirst = 0;
214       curr = next;
215     } while(curr!=NULL);
216   }
217   free(ptr);
218   (*tc_table)=node;
219 }
220 #endif
221
222 int moreItems() {
223   if ((head==tail)&&(tailindex==headindex))
224     return 0;
225   return 1;
226 }
227
228 #ifdef TASK
229 struct pointerblock *taghead=NULL;
230 int tagindex=0;
231
232 void enqueuetag(struct ___TagDescriptor___ *ptr) {
233   if (tagindex==NUMPTRS) {
234     struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
235     tmp->next=taghead;
236     taghead=tmp;
237     tagindex=0;
238   }
239   taghead->ptrs[tagindex++]=ptr;
240 }
241 #endif
242
243
244 void collect(struct garbagelist * stackptr) {
245 #if defined(THREADS)||defined(DSTM)||defined(STM)
246   needtocollect=1;
247   pthread_mutex_lock(&gclistlock);
248   while(1) {
249     if ((listcount+1)==threadcount) {
250       break; /* Have all other threads stopped */
251     }
252     pthread_cond_wait(&gccond, &gclistlock);
253   }
254 #endif
255
256   if (head==NULL) {
257     headindex=0;
258     tailindex=0;
259     head=tail=malloc(sizeof(struct pointerblock));
260   }
261
262 #ifdef TASK
263   if (taghead==NULL) {
264     tagindex=0;
265     taghead=malloc(sizeof(struct pointerblock));
266     taghead->next=NULL;
267   }
268 #endif
269
270 #ifdef STM
271     if (c_table!=NULL)
272       fixtable(&c_table, c_size);
273 #endif
274
275   /* Check current stack */
276 #if defined(THREADS)||defined(DSTM)||defined(STM)
277   {
278     struct listitem *listptr=list;
279     while(1) {
280 #endif
281
282   while(stackptr!=NULL) {
283     int i;
284     for(i=0; i<stackptr->size; i++) {
285       void * orig=stackptr->array[i];
286       ENQUEUE(orig, stackptr->array[i]);
287     }
288     stackptr=stackptr->next;
289   }
290 #if defined(THREADS)||defined(DSTM)||defined(STM)
291   /* Go to next thread */
292   if (listptr!=NULL) {
293 #ifdef THREADS
294     void * orig=listptr->locklist;
295     ENQUEUE(orig, listptr->locklist);
296 #endif
297 #ifdef STM
298     if ((*listptr->tc_table)!=NULL)
299       fixtable(listptr->tc_table, listptr->tc_size);
300 #endif
301     stackptr=listptr->stackptr;
302     listptr=listptr->next;
303   } else
304     break;
305 }
306 }
307 #endif
308
309 #ifdef FASTCHECK
310   ENQUEUE(___fcrevert___, ___fcrevert___);
311 #endif
312
313 #ifdef TASK
314   {
315     /* Update objectsets */
316     int i;
317     for(i=0; i<NUMCLASSES; i++) {
318 #if !defined(MULTICORE)
319       struct parameterwrapper * p=objectqueues[i];
320       while(p!=NULL) {
321         struct ObjectHash * set=p->objectset;
322         struct ObjectNode * ptr=set->listhead;
323         while(ptr!=NULL) {
324           void *orig=(void *)ptr->key;
325           ENQUEUE(orig, *((void **)(&ptr->key)));
326           ptr=ptr->lnext;
327         }
328         ObjectHashrehash(set); /* Rehash the table */
329         p=p->next;
330       }
331 #endif
332     }
333   }
334
335 #ifndef FASTCHECK
336   if (forward!=NULL) {
337     struct cnode * ptr=forward->listhead;
338     while(ptr!=NULL) {
339       void * orig=(void *)ptr->key;
340       ENQUEUE(orig, *((void **)(&ptr->key)));
341       ptr=ptr->lnext;
342     }
343     crehash(forward); /* Rehash the table */
344   }
345
346   if (reverse!=NULL) {
347     struct cnode * ptr=reverse->listhead;
348     while(ptr!=NULL) {
349       void *orig=(void *)ptr->val;
350       ENQUEUE(orig, *((void**)(&ptr->val)));
351       ptr=ptr->lnext;
352     }
353   }
354 #endif
355
356   {
357     struct RuntimeNode * ptr=fdtoobject->listhead;
358     while(ptr!=NULL) {
359       void *orig=(void *)ptr->data;
360       ENQUEUE(orig, *((void**)(&ptr->data)));
361       ptr=ptr->lnext;
362     }
363   }
364
365   {
366     /* Update current task descriptor */
367     int i;
368     for(i=0; i<currtpd->numParameters; i++) {
369       void *orig=currtpd->parameterArray[i];
370       ENQUEUE(orig, currtpd->parameterArray[i]);
371     }
372
373   }
374
375   /* Update active tasks */
376   {
377     struct genpointerlist * ptr=activetasks->list;
378     while(ptr!=NULL) {
379       struct taskparamdescriptor *tpd=ptr->src;
380       int i;
381       for(i=0; i<tpd->numParameters; i++) {
382         void * orig=tpd->parameterArray[i];
383         ENQUEUE(orig, tpd->parameterArray[i]);
384       }
385       ptr=ptr->inext;
386     }
387     genrehash(activetasks);
388   }
389
390   /* Update failed tasks */
391   {
392     struct genpointerlist * ptr=failedtasks->list;
393     while(ptr!=NULL) {
394       struct taskparamdescriptor *tpd=ptr->src;
395       int i;
396       for(i=0; i<tpd->numParameters; i++) {
397         void * orig=tpd->parameterArray[i];
398         ENQUEUE(orig, tpd->parameterArray[i]);
399       }
400       ptr=ptr->inext;
401     }
402     genrehash(failedtasks);
403   }
404 #endif
405
406   while(moreItems()) {
407     void * ptr=dequeue();
408     void *cpy=((void **)ptr)[1];
409     int type=((int *)cpy)[0];
410     unsigned int * pointer;
411 #ifdef TASK
412     if(type==TAGTYPE) {
413       /* Enqueue Tag */
414       /* Nothing is inside */
415       enqueuetag(ptr);
416       continue;
417     }
418 #endif
419     pointer=pointerarray[type];
420     if (pointer==0) {
421       /* Array of primitives */
422       /* Do nothing */
423 #if defined(DSTM)||defined(FASTCHECK)
424       struct ArrayObject *ao=(struct ArrayObject *) ptr;
425       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
426       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
427       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
428 #endif
429 #if defined(STM)
430       struct ArrayObject *ao=(struct ArrayObject *) ptr;
431       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
432       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
433 #endif
434     } else if (((int)pointer)==1) {
435       /* Array of pointers */
436       struct ArrayObject *ao=(struct ArrayObject *) ptr;
437       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
438 #if (defined(DSTM)||defined(FASTCHECK))
439       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
440       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
441 #endif
442 #if defined(STM)
443       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
444 #endif
445       int length=ao->___length___;
446       int i;
447       for(i=0; i<length; i++) {
448         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
449         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
450       }
451     } else {
452       int size=pointer[0];
453       int i;
454       for(i=1; i<=size; i++) {
455         unsigned int offset=pointer[i];
456         void * objptr=*((void **)(((int)ptr)+offset));
457         ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
458       }
459     }
460   }
461 #ifdef TASK
462   fixtags();
463 #endif
464
465 #if defined(THREADS)||defined(DSTM)||defined(STM)
466   needtocollect=0;
467   pthread_mutex_unlock(&gclistlock);
468 #endif
469 }
470
471 #ifdef TASK
472 /* Fix up the references from tags.  This can't be done earlier,
473    because we don't want tags to keep objects alive */
474 void fixtags() {
475   while(taghead!=NULL) {
476     int i;
477     struct pointerblock *tmp=taghead->next;
478     for(i=0; i<tagindex; i++) {
479       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
480       struct ___Object___ *obj=tagd->flagptr;
481       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
482       if (obj==NULL) {
483         /* Zero object case */
484       } else if (obj->type==-1) {
485         /* Single object case */
486         copy->flagptr=((struct ___Object___**)obj)[1];
487       } else if (obj->type==OBJECTARRAYTYPE) {
488         /* Array case */
489         struct ArrayObject *ao=(struct ArrayObject *) obj;
490         int livecount=0;
491         int j;
492         int k=0;
493         struct ArrayObject *aonew;
494
495         /* Count live objects */
496         for(j=0; j<ao->___cachedCode___; j++) {
497           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
498           if (tobj->type==-1)
499             livecount++;
500         }
501
502         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
503         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
504         memcpy(aonew, ao, sizeof(struct ArrayObject));
505         aonew->type=OBJECTARRAYTYPE;
506         aonew->___length___=livecount;
507         copy->flagptr=aonew;
508         for(j=0; j<ao->___cachedCode___; j++) {
509           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
510           if (tobj->type==-1) {
511             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
512             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
513           }
514         }
515         aonew->___cachedCode___=k;
516         for(; k<livecount; k++) {
517           ARRAYSET(aonew, struct ___Object___*, k, NULL);
518         }
519       } else {
520         /* No object live anymore */
521         copy->flagptr=NULL;
522       }
523     }
524     free(taghead);
525     taghead=tmp;
526     tagindex=NUMPTRS;
527   }
528 }
529 #endif
530
531 void * tomalloc(int size) {
532   void * ptr=to_heapptr;
533   if ((size&7)!=0)
534     size+=(8-(size%8));
535   to_heapptr+=size;
536   return ptr;
537 }
538
539 #if defined(THREADS)||defined(DSTM)||defined(STM)
540 void checkcollect(void * ptr) {
541   struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
542   pthread_mutex_lock(&gclock); // Wait for GC
543   restartaftergc(tmp);
544   pthread_mutex_unlock(&gclock);
545 }
546
547 #ifdef DSTM
548 void checkcollect2(void * ptr) {
549   int ptrarray[]={1, (int)ptr, (int) revertlist};
550   struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
551   pthread_mutex_lock(&gclock); // Wait for GC
552   restartaftergc(tmp);
553   pthread_mutex_unlock(&gclock);
554   revertlist=(struct ___Object___*)ptrarray[2];
555 }
556 #endif
557
558
559 struct listitem * stopforgc(struct garbagelist * ptr) {
560   struct listitem * litem=malloc(sizeof(struct listitem));
561   litem->stackptr=ptr;
562 #ifdef THREADS
563   litem->locklist=pthread_getspecific(threadlocks);
564 #endif
565 #ifdef STM
566   litem->tc_size=c_size;
567   litem->tc_table=&c_table;
568 #endif
569   litem->prev=NULL;
570   pthread_mutex_lock(&gclistlock);
571   litem->next=list;
572   if(list!=NULL)
573     list->prev=litem;
574   list=litem;
575   listcount++;
576   pthread_cond_signal(&gccond);
577   pthread_mutex_unlock(&gclistlock);
578   return litem;
579 }
580
581 void restartaftergc(struct listitem * litem) {
582   pthread_mutex_lock(&gclistlock);
583 #ifdef THREADS
584   pthread_setspecific(threadlocks, litem->locklist);
585 #endif
586   if (litem->prev==NULL) {
587     list=litem->next;
588   } else {
589     litem->prev->next=litem->next;
590   }
591   if (litem->next!=NULL) {
592     litem->next->prev=litem->prev;
593   }
594   listcount--;
595   pthread_mutex_unlock(&gclistlock);
596   free(litem);
597 }
598 #endif
599
600 void * mygcmalloc(struct garbagelist * stackptr, int size) {
601   void *ptr;
602 #if defined(THREADS)||defined(DSTM)||defined(STM)
603   if (pthread_mutex_trylock(&gclock)!=0) {
604     struct listitem *tmp=stopforgc(stackptr);
605     pthread_mutex_lock(&gclock);
606     restartaftergc(tmp);
607   }
608 #endif
609   ptr=curr_heapptr;
610   if ((size&7)!=0)
611     size+=(8-(size%8));
612   curr_heapptr+=size;
613   if (curr_heapptr>curr_heapgcpoint) {
614     if (curr_heapbase==0) {
615       /* Need to allocate base heap */
616       curr_heapbase=malloc(INITIALHEAPSIZE);
617       bzero(curr_heapbase, INITIALHEAPSIZE);
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       to_heaptop=to_heapbase+INITIALHEAPSIZE;
624       to_heapptr=to_heapbase;
625       ptr=curr_heapbase;
626 #if defined(THREADS)||defined(DSTM)||defined(STM)
627       pthread_mutex_unlock(&gclock);
628 #endif
629       return ptr;
630     }
631
632     /* Grow the to heap if necessary */
633     {
634       int curr_heapsize=curr_heaptop-curr_heapbase;
635       int to_heapsize=to_heaptop-to_heapbase;
636       int last_heapsize=0;
637       if (lastgcsize>0) {
638         last_heapsize=HEAPSIZE(lastgcsize, size);
639         if ((last_heapsize&7)!=0)
640           last_heapsize+=(8-(last_heapsize%8));
641       }
642       if (curr_heapsize>last_heapsize)
643         last_heapsize=curr_heapsize;
644       if (last_heapsize>to_heapsize) {
645         free(to_heapbase);
646         to_heapbase=malloc(last_heapsize);
647         if (to_heapbase==NULL) {
648           printf("Error Allocating enough memory\n");
649           exit(-1);
650         }
651         to_heaptop=to_heapbase+last_heapsize;
652         to_heapptr=to_heapbase;
653       }
654     }
655
656     /* Do our collection */
657     collect(stackptr);
658
659     /* Update stat on previous gc size */
660     lastgcsize=(to_heapptr-to_heapbase)+size;
661
662 #ifdef GARBAGESTATS
663     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
664     printf("New space: %u\n", to_heapptr-to_heapbase);
665     printf("Total space: %u\n", to_heaptop-to_heapbase);
666 #endif
667     /* Flip to/curr heaps */
668     {
669       void * tmp=to_heapbase;
670       to_heapbase=curr_heapbase;
671       curr_heapbase=tmp;
672
673       tmp=to_heaptop;
674       to_heaptop=curr_heaptop;
675       curr_heaptop=tmp;
676
677       tmp=to_heapptr;
678       curr_heapptr=to_heapptr+size;
679       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
680       to_heapptr=to_heapbase;
681
682       /* Not enough room :(, redo gc */
683       if (curr_heapptr>curr_heapgcpoint) {
684 #if defined(THREADS)||defined(DSTM)||defined(STM)
685         pthread_mutex_unlock(&gclock);
686 #endif
687         return mygcmalloc(stackptr, size);
688       }
689
690       bzero(tmp, curr_heaptop-tmp);
691 #if defined(THREADS)||defined(DSTM)||defined(STM)
692       pthread_mutex_unlock(&gclock);
693 #endif
694       return tmp;
695     }
696   } else {
697 #if defined(THREADS)||defined(DSTM)||defined(STM)
698     pthread_mutex_unlock(&gclock);
699 #endif
700     return ptr;
701   }
702 }
703
704
705 int gc_createcopy(void * orig, void ** copy_ptr) {
706   if (orig==0) {
707     *copy_ptr=NULL;
708     return 0;
709   } else {
710     int type=((int *)orig)[0];
711     if (type==-1) {
712       *copy_ptr=((void **)orig)[1];
713       return 0;
714     }
715     if (type<NUMCLASSES) {
716       /* We have a normal object */
717 #ifdef STM
718       int size=classsize[type]+sizeof(objheader_t);
719       void *newobj=tomalloc(size);
720       memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
721       newobj=((char *)newobj)+sizeof(objheader_t);
722 #else
723       int size=classsize[type];
724       void *newobj=tomalloc(size);
725       memcpy(newobj, orig, size);
726 #endif
727       ((int *)orig)[0]=-1;
728       ((void **)orig)[1]=newobj;
729       *copy_ptr=newobj;
730       return 1;
731     } else {
732       /* We have an array */
733       struct ArrayObject *ao=(struct ArrayObject *)orig;
734       int elementsize=classsize[type];
735       int length=ao->___length___;
736 #ifdef STM
737       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
738       void *newobj=tomalloc(size);
739       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
740       newobj=((char *)newobj)+sizeof(objheader_t);
741 #else
742       int size=sizeof(struct ArrayObject)+length*elementsize;
743       void *newobj=tomalloc(size);
744       memcpy(newobj, orig, size);
745 #endif
746
747       ((int *)orig)[0]=-1;
748       ((void **)orig)[1]=newobj;
749       *copy_ptr=newobj;
750       return 1;
751     }
752   }
753 }