Polish multicore code
[IRC.git] / Robust / src / Runtime / bamboo / multicoregccompact.c
1 #ifdef MULTICORE_GC
2 #include "multicoregccompact.h"
3 #include "runtime_arch.h"
4 #include "multicoreruntime.h"
5
6 extern int corenum;
7
8 INLINE bool gc_checkCoreStatus_I() {
9   int i = 0;
10   for(i = 0; i < NUMCORES4GC; ++i) {
11     if(gccorestatus[i] != 0) {
12       break;
13     }  
14   }  
15   return (i == NUMCORES4GC);
16 }
17
18 INLINE void compact2Heaptophelper_I(unsigned int coren,
19                                     unsigned int* p,
20                                     unsigned int* numblocks,
21                                     unsigned int* remain) {
22   unsigned int b;
23   unsigned int memneed = gcrequiredmems[coren] + BAMBOO_CACHE_LINE_SIZE;
24   if(STARTUPCORE == coren) {
25     gctomove = true;
26     gcmovestartaddr = *p;
27     gcdstcore = gctopcore;
28     gcblock2fill = *numblocks + 1;
29   } else {
30     send_msg_4(coren, GCMOVESTART, gctopcore, *p, (*numblocks) + 1, false);
31   }
32   if(memneed < *remain) {
33     *p = *p + memneed;
34     gcrequiredmems[coren] = 0;
35     gcloads[gctopcore] += memneed;
36     *remain = *remain - memneed;
37   } else {
38     // next available block
39     *p = *p + *remain;
40     gcfilledblocks[gctopcore] += 1;
41     unsigned int newbase = 0;
42     BASEPTR(gctopcore, gcfilledblocks[gctopcore], &newbase);
43     gcloads[gctopcore] = newbase;
44     gcrequiredmems[coren] -= *remain - BAMBOO_CACHE_LINE_SIZE;
45     gcstopblock[gctopcore]++;
46     gctopcore = NEXTTOPCORE(gctopblock);
47     gctopblock++;
48     *numblocks = gcstopblock[gctopcore];
49     *p = gcloads[gctopcore];
50     BLOCKINDEX(*p, &b);
51     *remain=GC_BLOCK_REMAIN_SIZE(b, (*p));
52   }  
53   gcmovepending--;
54
55
56 INLINE void compact2Heaptop() {
57   // no cores with spare mem and some cores are blocked with pending move
58   // find the current heap top and make them move to the heap top
59   unsigned int p;
60   unsigned int numblocks = gcfilledblocks[gctopcore];
61   p = gcloads[gctopcore];
62   unsigned int b;
63   BLOCKINDEX(p, &b);
64   unsigned int remain=GC_BLOCK_REMAIN_SIZE(b, p);
65   // check if the top core finishes
66   BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
67   if(gccorestatus[gctopcore] != 0) {
68     // let the top core finishes its own work first
69     compact2Heaptophelper_I(gctopcore, &p, &numblocks, &remain);
70     BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
71     return;
72   }
73   BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
74
75   for(int i = 0; i < NUMCORES4GC; i++) {
76     BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
77     if((gccorestatus[i] != 0) && (gcrequiredmems[i] > 0)) {
78       compact2Heaptophelper_I(i, &p, &numblocks, &remain);
79       if(gccorestatus[gctopcore] != 0) {
80         BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
81         // the top core is not free now
82         return;
83       }
84     }  
85     BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
86   } 
87 }
88
89 INLINE void resolvePendingMoveRequest() {
90   int i;
91   int j;
92   bool nosparemem = true;
93   bool haspending = false;
94   bool hasrunning = false;
95   bool noblock = false;
96   unsigned int dstcore = 0;       // the core who need spare mem
97   unsigned int sourcecore = 0;       // the core who has spare mem
98   for(i = j = 0; (i < NUMCORES4GC) && (j < NUMCORES4GC); ) {
99     if(nosparemem) {
100       // check if there are cores with spare mem
101       if(gccorestatus[i] == 0) {
102     // finished working, check if it still have spare mem
103     if(gcfilledblocks[i] < gcstopblock[i]) {
104       // still have spare mem
105       nosparemem = false;
106       sourcecore = i;
107     }  
108       }
109       i++;
110     }  
111     if(!haspending) {
112       if(gccorestatus[j] != 0) {
113     // not finished, check if it has pending move requests
114     if((gcfilledblocks[j]==gcstopblock[j])&&(gcrequiredmems[j]>0)) {
115       dstcore = j;
116       haspending = true;
117     } else {
118       hasrunning = true;
119     } 
120       } 
121       j++;
122     }  
123     if(!nosparemem && haspending) {
124       // find match
125       unsigned int tomove = 0;
126       unsigned int startaddr = 0;
127       BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
128       gcrequiredmems[dstcore] = assignSpareMem_I(sourcecore,
129                                                  gcrequiredmems[dstcore],
130                                                  &tomove,
131                                                  &startaddr);
132       BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
133       if(STARTUPCORE == dstcore) {
134     gcdstcore = sourcecore;
135     gctomove = true;
136     gcmovestartaddr = startaddr;
137     gcblock2fill = tomove;
138       } else {
139     send_msg_4(dstcore, GCMOVESTART, sourcecore,startaddr, tomove, false);
140       }
141       gcmovepending--;
142       nosparemem = true;
143       haspending = false;
144       noblock = true;
145     }
146   }  
147
148   if(!hasrunning && !noblock) {
149     gcphase = SUBTLECOMPACTPHASE;
150     compact2Heaptop();
151   }
152
153
154
155 // If out of boundary of valid shared memory, return false, else return true
156 INLINE bool nextSBlock(struct moveHelper * orig) {
157   orig->blockbase = orig->blockbound;
158
159   bool sbchanged = false;
160   unsigned int origptr = orig->ptr;
161   unsigned int blockbase = orig->blockbase;
162   unsigned int blockbound = orig->blockbound;
163   unsigned int bound = orig->bound;
164 outernextSBlock:
165   // check if across a big block
166   // TODO now do not zero out the whole memory, maybe the last two conditions
167   // are useless now
168   if((blockbase>=bound)||(origptr>=bound)
169     ||((origptr!=NULL)&&(*((int*)origptr))==0)||((*((int*)blockbase))==0)) {
170 innernextSBlock:
171     // end of current heap block, jump to next one
172     orig->numblocks++;
173     BASEPTR(BAMBOO_NUM_OF_CORE, orig->numblocks, &(orig->base));
174     if(orig->base >= gcbaseva + BAMBOO_SHARED_MEM_SIZE) {
175       // out of boundary
176       orig->ptr = orig->base; // set current ptr to out of boundary too
177       return false;
178     }
179     orig->blockbase = orig->base;
180     orig->sblockindex = 
181     (unsigned int)(orig->blockbase-gcbaseva)/BAMBOO_SMEM_SIZE;
182     sbchanged = true;
183     unsigned int blocknum = 0;
184     BLOCKINDEX(orig->base, &blocknum);
185     if(bamboo_smemtbl[blocknum] == 0) {
186       // goto next block
187       goto innernextSBlock;
188     }
189     // check the bamboo_smemtbl to decide the real bound
190     orig->bound = orig->base + bamboo_smemtbl[blocknum];
191   } else if(0 == (orig->blockbase%BAMBOO_SMEM_SIZE)) {
192     orig->sblockindex += 1;
193     sbchanged = true;
194   }  
195
196   // check if this sblock should be skipped or have special start point
197   int sbstart = gcsbstarttbl[orig->sblockindex];
198   if(sbstart == -1) {
199     // goto next sblock
200     orig->sblockindex += 1;
201     orig->blockbase += BAMBOO_SMEM_SIZE;
202     goto outernextSBlock;
203   } else if((sbstart != 0) && (sbchanged)) {
204     // the first time to access this SBlock
205     // not start from the very beginning
206     orig->blockbase = sbstart;
207   } 
208
209   // setup information for this sblock
210   orig->blockbound = orig->blockbase+(unsigned int)*((int*)(orig->blockbase));
211   orig->offset = BAMBOO_CACHE_LINE_SIZE;
212   orig->ptr = orig->blockbase + orig->offset;
213   if(orig->ptr >= orig->bound) {
214     // met a lobj, move to next block
215     goto innernextSBlock;
216   }
217
218   return true;
219
220
221 // return false if there are no available data to compact
222 INLINE bool initOrig_Dst(struct moveHelper * orig,
223                          struct moveHelper * to) {
224   // init the dst ptr
225   to->numblocks = 0;
226   to->top = to->offset = BAMBOO_CACHE_LINE_SIZE;
227   to->bound = BAMBOO_SMEM_SIZE_L;
228   BASEPTR(BAMBOO_NUM_OF_CORE, to->numblocks, &(to->base));
229
230   unsigned int tobase = to->base;
231   to->ptr = tobase + to->offset;
232
233   // init the orig ptr
234   orig->numblocks = 0;
235   orig->base = tobase;
236   unsigned int blocknum = 0;
237   BLOCKINDEX(orig->base, &blocknum);
238   unsigned int origbase = orig->base;
239   // check the bamboo_smemtbl to decide the real bound
240   orig->bound = origbase + (unsigned int)bamboo_smemtbl[blocknum];
241   orig->blockbase = origbase;
242   orig->sblockindex = (unsigned int)(origbase - gcbaseva) / BAMBOO_SMEM_SIZE;
243
244   int sbstart = gcsbstarttbl[orig->sblockindex];
245   if(sbstart == -1) {
246     // goto next sblock
247     orig->blockbound=gcbaseva+BAMBOO_SMEM_SIZE*(orig->sblockindex+1);
248     return nextSBlock(orig);
249   } else if(sbstart != 0) {
250     orig->blockbase = sbstart;
251   }
252   orig->blockbound = orig->blockbase + *((int*)(orig->blockbase));
253   orig->offset = BAMBOO_CACHE_LINE_SIZE;
254   orig->ptr = orig->blockbase + orig->offset;
255
256   return true;
257 }
258
259 INLINE void nextBlock(struct moveHelper * to) {
260   to->top = to->bound + BAMBOO_CACHE_LINE_SIZE; // header!
261   to->bound += BAMBOO_SMEM_SIZE;
262   to->numblocks++;
263   BASEPTR(BAMBOO_NUM_OF_CORE, to->numblocks, &(to->base));
264   to->offset = BAMBOO_CACHE_LINE_SIZE;
265   to->ptr = to->base + to->offset;
266 }
267
268 INLINE unsigned int findValidObj(struct moveHelper * orig,
269                                  struct moveHelper * to,
270                                  int * type) {
271   unsigned int size = 0;
272   while(true) {
273     CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, to->ptr, false);
274     unsigned int origptr = (unsigned int)(orig->ptr);
275     unsigned int origbound = (unsigned int)orig->bound;
276     unsigned int origblockbound = (unsigned int)orig->blockbound;
277     if((origptr >= origbound) || (origptr == origblockbound)) {
278       if(!nextSBlock(orig)) {
279         // finished, no more data
280         return -1;
281       }
282       continue;
283     }
284     // check the obj's type, size and mark flag
285     *type = ((int *)(origptr))[0];
286     size = 0;
287     if(*type == 0) {
288       // end of this block, go to next one
289       if(!nextSBlock(orig)) {
290         // finished, no more data
291         return -1;
292       }
293       continue;
294     } else if(*type < NUMCLASSES) {
295       // a normal object
296       size = classsize[*type];
297     } else {
298       // an array
299       struct ArrayObject *ao=(struct ArrayObject *)(origptr);
300       unsigned int elementsize=classsize[*type];
301       unsigned int length=ao->___length___;
302       size=(unsigned int)sizeof(struct ArrayObject)
303         +(unsigned int)(length*elementsize);
304     }
305     return size;
306   }
307 }
308
309 // endaddr does not contain spaces for headers
310 INLINE bool moveobj(struct moveHelper * orig,
311                     struct moveHelper * to,
312                     unsigned int stopblock) {
313   if(stopblock == 0) {
314     return true;
315   }
316
317   int type = 0;
318   unsigned int size = 0;
319   unsigned int isize = 0;
320   size = findValidObj(orig, to, &type);
321   if(size == -1) {
322     // finished, no more data
323     return true;
324   }
325   ALIGNSIZE(size, &isize);       // no matter is the obj marked or not
326                                  // should be able to across
327   unsigned int origptr = (unsigned int)(orig->ptr);
328   if(((struct ___Object___ *)origptr)->marked == MARKED) {
329     unsigned int totop = (unsigned int)to->top;
330     unsigned int tobound = (unsigned int)to->bound;
331     GCPROFILE_RECORD_LIVE_OBJ();
332     // marked obj, copy it to current heap top
333     // check to see if remaining space is enough
334     if((unsigned int)(totop + isize) > tobound) {
335       // fill 0 indicating the end of this block
336       BAMBOO_MEMSET_WH(to->ptr,  '\0', tobound - totop);
337       // fill the header of this block and then go to next block
338       to->offset += tobound - totop;
339       CLOSEBLOCK(to->base, to->offset);
340 #ifdef GC_CACHE_ADAPT
341       unsigned int tmp_ptr = to->ptr;
342 #endif 
343       nextBlock(to);
344 #ifdef GC_CACHE_ADAPT
345       CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, tmp_ptr, true);
346 #endif 
347       if(stopblock == to->numblocks) {
348         // already fulfilled the block
349         return true;
350       }  
351     } 
352     // set the mark field to 2, indicating that this obj has been moved
353     // and need to be flushed
354     ((struct ___Object___ *)origptr)->marked = COMPACTED;
355     unsigned int toptr = (unsigned int)to->ptr;
356     if(toptr != origptr) {
357       if((unsigned int)(origptr) < (unsigned int)(toptr+size)) {
358         memmove(toptr, origptr, size);
359       } else {
360         memcpy(toptr, origptr, size);
361       }
362       // fill the remaining space with -2
363       BAMBOO_MEMSET_WH((unsigned int)(toptr+size), -2, isize-size);
364     }
365     // store mapping info
366     gcmappingtbl[OBJMAPPINGINDEX((unsigned int)origptr)]=(unsigned int)toptr;
367     gccurr_heaptop -= isize;
368     to->ptr += isize;
369     to->offset += isize;
370     to->top += isize;
371 #ifdef GC_CACHE_ADAPT
372     unsigned int tmp_ptr = to->ptr;
373 #endif // GC_CACHE_ADAPT
374     if(to->top == to->bound) {
375       CLOSEBLOCK(to->base, to->offset);
376       nextBlock(to);
377     }
378 #ifdef GC_CACHE_ADAPT
379     CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, tmp_ptr, true);
380 #endif
381   } 
382   
383   // move to next obj
384   orig->ptr += isize; 
385
386   if(((unsigned int)(orig->ptr) > (unsigned int)(orig->bound))
387     || ((unsigned int)(orig->ptr) == (unsigned int)(orig->blockbound))) {
388     if(!nextSBlock(orig)) {
389       // finished, no more data
390       return true;
391     }
392   }
393   return false;
394
395
396 // should be invoked with interrupt closed
397 INLINE int assignSpareMem_I(unsigned int sourcecore,
398                             unsigned int * requiredmem,
399                             unsigned int * tomove,
400                             unsigned int * startaddr) {
401   unsigned int b = 0;
402   BLOCKINDEX(gcloads[sourcecore], &b);
403   unsigned int boundptr = (b<NUMCORES4GC) ? ((b+1)*BAMBOO_SMEM_SIZE_L)
404      : (BAMBOO_LARGE_SMEM_BOUND+(b-NUMCORES4GC+1)*BAMBOO_SMEM_SIZE);
405   unsigned int remain = boundptr - gcloads[sourcecore];
406   unsigned int memneed = requiredmem + BAMBOO_CACHE_LINE_SIZE;
407   *startaddr = gcloads[sourcecore];
408   *tomove = gcfilledblocks[sourcecore] + 1;
409   if(memneed < remain) {
410     gcloads[sourcecore] += memneed;
411     return 0;
412   } else {
413     // next available block
414     gcfilledblocks[sourcecore] += 1;
415     unsigned int newbase = 0;
416     BASEPTR(sourcecore, gcfilledblocks[sourcecore], &newbase);
417     gcloads[sourcecore] = newbase;
418     return requiredmem-remain;
419   }
420
421
422 // should be invoked with interrupt closed
423 INLINE bool gcfindSpareMem_I(unsigned int * startaddr,
424                              unsigned int * tomove,
425                              unsigned int * dstcore,
426                              unsigned int requiredmem,
427                              unsigned int requiredcore) {
428   for(int k = 0; k < NUMCORES4GC; k++) {
429     if((gccorestatus[k] == 0) && (gcfilledblocks[k] < gcstopblock[k])) {
430       // check if this stopped core has enough mem
431       assignSpareMem_I(k, requiredmem, tomove, startaddr);
432       *dstcore = k;
433       return true;
434     }
435   }
436   // if can not find spare mem right now, hold the request
437   gcrequiredmems[requiredcore] = requiredmem;
438   gcmovepending++;
439   return false;
440
441
442 INLINE bool compacthelper(struct moveHelper * orig,
443                           struct moveHelper * to,
444                           int * filledblocks,
445                           unsigned int * heaptopptr,
446                           bool * localcompact) {
447   // scan over all objs in this block, compact the marked objs
448   // loop stop when finishing either scanning all active objs or
449   // fulfilled the gcstopblock
450 innercompact:
451   while((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
452     if(moveobj(orig, to, gcblock2fill)) {
453       break;
454     }
455   }
456   CACHEADAPT_SAMPLING_DATA_CONVERT(to->ptr);
457   // if no objs have been compact, do nothing,
458   // otherwise, fill the header of this block
459   if(to->offset > (unsigned int)BAMBOO_CACHE_LINE_SIZE) {
460     CLOSEBLOCK(to->base, to->offset);
461   } else {
462     to->offset = 0;
463     to->ptr = to->base;
464     to->top -= BAMBOO_CACHE_LINE_SIZE;
465   }  
466   if(*localcompact) {
467     *heaptopptr = to->ptr;
468     *filledblocks = to->numblocks;
469   }
470
471   // send msgs to core coordinator indicating that the compact is finishing
472   // send compact finish message to core coordinator
473   if(STARTUPCORE == BAMBOO_NUM_OF_CORE) {
474     gcfilledblocks[BAMBOO_NUM_OF_CORE] = *filledblocks;
475     gcloads[BAMBOO_NUM_OF_CORE] = *heaptopptr;
476     if((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
477       // ask for more mem
478       gctomove = false;
479       BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
480       if(gcfindSpareMem_I(&gcmovestartaddr, &gcblock2fill, &gcdstcore,
481             gccurr_heaptop, BAMBOO_NUM_OF_CORE)) {
482         gctomove = true;
483       } else {
484         BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
485         return false;
486       }
487       BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
488     } else {
489       gccorestatus[BAMBOO_NUM_OF_CORE] = 0;
490       gctomove = false;
491       return true;
492     }
493   } else {
494     if((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
495       // ask for more mem
496       gctomove = false;
497       send_msg_5(STARTUPCORE, GCFINISHCOMPACT, BAMBOO_NUM_OF_CORE,
498                  *filledblocks, *heaptopptr, gccurr_heaptop, false);
499     } else {
500       // finish compacting
501       send_msg_5(STARTUPCORE, GCFINISHCOMPACT, BAMBOO_NUM_OF_CORE,
502                  *filledblocks, *heaptopptr, 0, false);
503     }
504   } 
505
506   if(orig->ptr < gcmarkedptrbound) {
507     // still have unpacked obj
508     while(true) {
509       if(gctomove) {
510         break;
511       }
512     }
513     ;
514     gctomove = false;
515
516     to->ptr = gcmovestartaddr;
517     to->numblocks = gcblock2fill - 1;
518     to->bound = ((to->numblocks==0)?BAMBOO_SMEM_SIZE_L:BAMBOO_SMEM_SIZE_L)
519       +BAMBOO_SMEM_SIZE*to->numblocks;
520     BASEPTR(gcdstcore, to->numblocks, &(to->base));
521     to->offset = to->ptr - to->base;
522     to->top = (to->numblocks==0)?(to->offset)
523       :(to->bound-BAMBOO_SMEM_SIZE+to->offset);
524     to->base = to->ptr;
525     to->offset = BAMBOO_CACHE_LINE_SIZE;
526     to->ptr += to->offset;   // for header
527     to->top += to->offset;
528     if(gcdstcore == BAMBOO_NUM_OF_CORE) {
529       *localcompact = true;
530     } else {
531       *localcompact = false;
532     }
533     CACHEADAPT_SAMPLING_DATA_REVISE_INIT();
534     goto innercompact;
535   }
536   return true;
537 }
538
539 INLINE void compact() {
540   if(COMPACTPHASE != gcphase) {
541     BAMBOO_EXIT(0xb025);
542   }
543
544   // initialize pointers for comapcting
545   struct moveHelper * orig = 
546     (struct moveHelper *)RUNMALLOC(sizeof(struct moveHelper));
547   struct moveHelper * to =
548     (struct moveHelper *)RUNMALLOC(sizeof(struct moveHelper));
549   if(!initOrig_Dst(orig, to)) {
550     // no available data to compact
551     // send compact finish msg to STARTUP core
552     send_msg_5(STARTUPCORE, GCFINISHCOMPACT, BAMBOO_NUM_OF_CORE,
553                0, to->base, 0, false);
554     RUNFREE(orig);
555     RUNFREE(to);
556     return;
557   }
558   CACHEADAPT_SAMPLING_DATA_REVISE_INIT();
559
560   unsigned int filledblocks = 0;
561   unsigned int heaptopptr = 0;
562   bool localcompact = true;
563   compacthelper(orig, to, &filledblocks, &heaptopptr, &localcompact);
564   RUNFREE(orig);
565   RUNFREE(to);
566
567
568 INLINE void compact_master(struct moveHelper * orig,
569                            struct moveHelper * to) {
570   bool finalcompact = false;
571   // initialize pointers for comapcting
572   initOrig_Dst(orig, to);
573   CACHEADAPT_SAMPLING_DATA_REVISE_INIT();
574   int filledblocks = 0;
575   unsigned int heaptopptr = 0;
576   bool finishcompact = false;
577   bool iscontinue = true;
578   bool localcompact = true;
579   while((COMPACTPHASE == gcphase) || (SUBTLECOMPACTPHASE == gcphase)) {
580     if((!finishcompact) && iscontinue) {
581       finishcompact =
582         compacthelper(orig,to,&filledblocks,&heaptopptr,&localcompact);
583     }
584
585     BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
586     if(gc_checkCoreStatus_I()) {
587       // all cores have finished compacting
588       // restore the gcstatus of all cores
589       for(int i = 0; i < NUMCORES4GC; ++i) {
590         gccorestatus[i] = 1;
591       }
592       BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
593       break;
594     } else {
595       BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
596       // check if there are spare mem for pending move requires
597       if(COMPACTPHASE == gcphase) {
598         resolvePendingMoveRequest();
599       } else {
600         compact2Heaptop();
601       }
602     } 
603
604     if(gctomove) {
605       to->ptr = gcmovestartaddr;
606       to->numblocks = gcblock2fill - 1;
607       to->bound = (to->numblocks==0) ? BAMBOO_SMEM_SIZE_L :
608         BAMBOO_SMEM_SIZE_L+BAMBOO_SMEM_SIZE*to->numblocks;
609       BASEPTR(gcdstcore, to->numblocks, &(to->base));
610       to->offset = to->ptr - to->base;
611       to->top = (to->numblocks==0)?(to->offset):
612         (to->bound-BAMBOO_SMEM_SIZE+to->offset);
613       to->base = to->ptr;
614       to->offset = BAMBOO_CACHE_LINE_SIZE;
615       to->ptr += to->offset;  // for header
616       to->top += to->offset;
617       if(gcdstcore == BAMBOO_NUM_OF_CORE) {
618         localcompact = true;
619       } else {
620         localcompact = false;
621       }
622       gctomove = false;
623       iscontinue = true;
624     } else if(!finishcompact) {
625       // still pending
626       iscontinue = false;
627     }
628   }
629 }
630
631 #endif // MULTICORE_GC