⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mark.c

📁 Boost provides free peer-reviewed portable C++ source libraries. We emphasize libraries that work
💻 C
📖 第 1 页 / 共 4 页
字号:
  /* unexpected thread start?					*/#endif# ifdef WRAP_MARK_SOME  GC_bool GC_mark_some(ptr_t cold_gc_frame)  {      GC_bool ret_val;#   ifdef MSWIN32#    ifndef __GNUC__      /* Windows 98 appears to asynchronously create and remove  */      /* writable memory mappings, for reasons we haven't yet    */      /* understood.  Since we look for writable regions to      */      /* determine the root set, we may try to mark from an      */      /* address range that disappeared since we started the     */      /* collection.  Thus we have to recover from faults here.  */      /* This code does not appear to be necessary for Windows   */      /* 95/NT/2000. Note that this code should never generate   */      /* an incremental GC write fault.                          */      /* It's conceivable that this is the same issue with	 */      /* terminating threads that we see with Linux and		 */      /* USE_PROC_FOR_LIBRARIES.				 */      __try {          ret_val = GC_mark_some_inner(cold_gc_frame);      } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {	  goto handle_ex;      }#     ifdef GC_WIN32_THREADS	/* With DllMain-based thread tracking, a thread may have	*/	/* started while we were marking.  This is logically equivalent	*/	/* to the exception case; our results are invalid and we have	*/	/* to start over.  This cannot be prevented since we can't	*/	/* block in DllMain.						*/	if (GC_started_thread_while_stopped()) goto handle_ex;#     endif     rm_handler:      return ret_val;#    else /* __GNUC__ */      /* Manually install an exception handler since GCC does    */      /* not yet support Structured Exception Handling (SEH) on  */      /* Win32.                                                  */      ext_ex_regn er;      er.alt_path = &&handle_ex;      er.ex_reg.handler = mark_ex_handler;      asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));      asm volatile ("movl %0, %%fs:0" : : "r" (&er));      ret_val = GC_mark_some_inner(cold_gc_frame);      /* Prevent GCC from considering the following code unreachable */      /* and thus eliminating it.                                    */        if (er.alt_path == 0)          goto handle_ex;    rm_handler:      /* Uninstall the exception handler */      asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));      return ret_val;#    endif /* __GNUC__ */#   else /* !MSWIN32 */      /* Here we are handling the case in which /proc is used for root	*/      /* finding, and we have threads.  We may find a stack for a	*/      /* thread that is in the process of exiting, and disappears	*/      /* while we are marking it.  This seems extremely difficult to	*/      /* avoid otherwise.						*/      if (GC_incremental)	      WARN("Incremental GC incompatible with /proc roots\n", 0);      	/* I'm not sure if this could still work ...	*/      GC_setup_temporary_fault_handler();      if(SETJMP(GC_jmp_buf) != 0) goto handle_ex;      ret_val = GC_mark_some_inner(cold_gc_frame);    rm_handler:      GC_reset_fault_handler();      return ret_val;      #   endif /* !MSWIN32 */handle_ex:    /* Exception handler starts here for all cases. */      if (GC_print_stats) {        GC_log_printf("Caught ACCESS_VIOLATION in marker. "		      "Memory mapping disappeared.\n");      }      /* We have bad roots on the stack.  Discard mark stack.	*/      /* Rescan from marked objects.  Redetermine roots.	*/      GC_invalidate_mark_state();	      scan_ptr = 0;      ret_val = FALSE;      goto rm_handler;  // Back to platform-specific code.  }#endif /* WRAP_MARK_SOME */GC_bool GC_mark_stack_empty(void){    return(GC_mark_stack_top < GC_mark_stack);}	void GC_invalidate_mark_state(void){    GC_mark_state = MS_INVALID;    GC_mark_stack_top = GC_mark_stack-1;}mse * GC_signal_mark_stack_overflow(mse *msp){    GC_mark_state = MS_INVALID;    GC_mark_stack_too_small = TRUE;    if (GC_print_stats) {	GC_log_printf("Mark stack overflow; current size = %lu entries\n",	    	      GC_mark_stack_size);    }    return(msp - GC_MARK_STACK_DISCARDS);}/* * Mark objects pointed to by the regions described by * mark stack entries between mark_stack and mark_stack_top, * inclusive.  Assumes the upper limit of a mark stack entry * is never 0.  A mark stack entry never has size 0. * We try to traverse on the order of a hblk of memory before we return. * Caller is responsible for calling this until the mark stack is empty. * Note that this is the most performance critical routine in the * collector.  Hence it contains all sorts of ugly hacks to speed * things up.  In particular, we avoid procedure calls on the common * path, we take advantage of peculiarities of the mark descriptor * encoding, we optionally maintain a cache for the block address to * header mapping, we prefetch when an object is "grayed", etc.  */mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack, mse *mark_stack_limit){  signed_word credit = HBLKSIZE;  /* Remaining credit for marking work	*/  ptr_t current_p;	/* Pointer to current candidate ptr.	*/  word current;	/* Candidate pointer.			*/  ptr_t limit;	/* (Incl) limit of current candidate 	*/  				/* range				*/  word descr;  ptr_t greatest_ha = GC_greatest_plausible_heap_addr;  ptr_t least_ha = GC_least_plausible_heap_addr;  DECLARE_HDR_CACHE;# define SPLIT_RANGE_WORDS 128  /* Must be power of 2.		*/  GC_objects_are_marked = TRUE;  INIT_HDR_CACHE;# ifdef OS2 /* Use untweaked version to circumvent compiler problem */  while (mark_stack_top >= mark_stack && credit >= 0) {# else  while ((((ptr_t)mark_stack_top - (ptr_t)mark_stack) | credit)  	>= 0) {# endif    current_p = mark_stack_top -> mse_start;    descr = mark_stack_top -> mse_descr;  retry:    /* current_p and descr describe the current object.		*/    /* *mark_stack_top is vacant.				*/    /* The following is 0 only for small objects described by a simple	*/    /* length descriptor.  For many applications this is the common	*/    /* case, so we try to detect it quickly.				*/    if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | GC_DS_TAGS)) {      word tag = descr & GC_DS_TAGS;            switch(tag) {        case GC_DS_LENGTH:          /* Large length.					        */          /* Process part of the range to avoid pushing too much on the	*/          /* stack.							*/	  GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr			    - (word)GC_least_plausible_heap_addr);#	  ifdef ENABLE_TRACE	    if (GC_trace_addr >= current_p		&& GC_trace_addr < current_p + descr) {		GC_log_printf("GC:%d Large section; start %p len %lu\n",			      GC_gc_no, current_p, (unsigned long) descr);	    }#	  endif /* ENABLE_TRACE */#	  ifdef PARALLEL_MARK#	    define SHARE_BYTES 2048	    if (descr > SHARE_BYTES && GC_parallel		&& mark_stack_top < mark_stack_limit - 1) {	      int new_size = (descr/2) & ~(sizeof(word)-1);	      mark_stack_top -> mse_start = current_p;	      mark_stack_top -> mse_descr = new_size + sizeof(word);					/* makes sure we handle 	*/					/* misaligned pointers.		*/	      mark_stack_top++;#	      ifdef ENABLE_TRACE	        if (GC_trace_addr >= current_p		    && GC_trace_addr < current_p + descr) {		    GC_log_printf("GC:%d splitting (parallel) %p at %p\n",				  GC_gc_no, current_p, current_p + new_size);	        }#	      endif /* ENABLE_TRACE */	      current_p += new_size;	      descr -= new_size;	      goto retry;	    }#	  endif /* PARALLEL_MARK */          mark_stack_top -> mse_start =         	limit = current_p + WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);          mark_stack_top -> mse_descr =          		descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);#	  ifdef ENABLE_TRACE	    if (GC_trace_addr >= current_p		&& GC_trace_addr < current_p + descr) {		GC_log_printf("GC:%d splitting %p at %p\n",			      GC_gc_no, current_p, limit);	    }#	  endif /* ENABLE_TRACE */          /* Make sure that pointers overlapping the two ranges are	*/          /* considered. 						*/          limit += sizeof(word) - ALIGNMENT;          break;        case GC_DS_BITMAP:          mark_stack_top--;#	  ifdef ENABLE_TRACE	    if (GC_trace_addr >= current_p		&& GC_trace_addr < current_p + WORDS_TO_BYTES(WORDSZ-2)) {		GC_log_printf("GC:%d Tracing from %p bitmap descr %lu\n",			      GC_gc_no, current_p, (unsigned long) descr);	    }#	  endif /* ENABLE_TRACE */          descr &= ~GC_DS_TAGS;          credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */          while (descr != 0) {            if ((signed_word)descr < 0) {              current = *(word *)current_p;	      FIXUP_POINTER(current);	      if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {		PREFETCH((ptr_t)current);#               ifdef ENABLE_TRACE	          if (GC_trace_addr == current_p) {	            GC_log_printf("GC:%d Considering(3) %p -> %p\n",			          GC_gc_no, current_p, (ptr_t) current);	          }#               endif /* ENABLE_TRACE */                PUSH_CONTENTS((ptr_t)current, mark_stack_top,			      mark_stack_limit, current_p, exit1);	      }            }	    descr <<= 1;	    current_p += sizeof(word);          }          continue;        case GC_DS_PROC:          mark_stack_top--;#	  ifdef ENABLE_TRACE	    if (GC_trace_addr >= current_p		&& GC_base(current_p) != 0		&& GC_base(current_p) == GC_base(GC_trace_addr)) {		GC_log_printf("GC:%d Tracing from %p proc descr %lu\n",			      GC_gc_no, current_p, (unsigned long) descr);	    }#	  endif /* ENABLE_TRACE */          credit -= GC_PROC_BYTES;          mark_stack_top =              (*PROC(descr))              	    ((word *)current_p, mark_stack_top,              	    mark_stack_limit, ENV(descr));          continue;        case GC_DS_PER_OBJECT:	  if ((signed_word)descr >= 0) {	    /* Descriptor is in the object.	*/            descr = *(word *)(current_p + descr - GC_DS_PER_OBJECT);	  } else {	    /* Descriptor is in type descriptor pointed to by first	*/	    /* word in object.						*/	    ptr_t type_descr = *(ptr_t *)current_p;	    /* type_descr is either a valid pointer to the descriptor	*/	    /* structure, or this object was on a free list.  If it 	*/	    /* it was anything but the last object on the free list,	*/	    /* we will misinterpret the next object on the free list as */	    /* the type descriptor, and get a 0 GC descriptor, which	*/	    /* is ideal.  Unfortunately, we need to check for the last	*/	    /* object case explicitly.					*/	    if (0 == type_descr) {		/* Rarely executed.	*/		mark_stack_top--;		continue;	    }            descr = *(word *)(type_descr			      - (descr - (GC_DS_PER_OBJECT					  - GC_INDIR_PER_OBJ_BIAS)));	  }	  if (0 == descr) {	      /* Can happen either because we generated a 0 descriptor	*/	      /* or we saw a pointer to a free object.		*/	      mark_stack_top--;	      continue;	  }          goto retry;      }    } else /* Small object with length descriptor */ {      mark_stack_top--;      limit = current_p + (word)descr;    }#   ifdef ENABLE_TRACE	if (GC_trace_addr >= current_p	    && GC_trace_addr < limit) {	    GC_log_printf("GC:%d Tracing from %p len %lu\n",			  GC_gc_no, current_p, (unsigned long) descr);	}#   endif /* ENABLE_TRACE */    /* The simple case in which we're scanning a range.	*/    GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));    credit -= limit - current_p;    limit -= sizeof(word);    {#     define PREF_DIST 4#     ifndef SMALL_CONFIG        word deferred;	/* Try to prefetch the next pointer to be examined asap.	*/	/* Empirically, this also seems to help slightly without	*/	/* prefetches, at least on linux/X86.  Presumably this loop 	*/	/* ends up with less register pressure, and gcc thus ends up 	*/	/* generating slightly better code.  Overall gcc code quality	*/	/* for this loop is still not great.				*/	for(;;) {	  PREFETCH(limit - PREF_DIST*CACHE_LINE_SIZE);	  GC_ASSERT(limit >= current_p);	  deferred = *(word *)limit;	  FIXUP_POINTER(deferred);	  limit -= ALIGNMENT;	  if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {	    PREFETCH((ptr_t)deferred);	    break;	  }	  if (current_p > limit) goto next_object;	  /* Unroll once, so we don't do too many of the prefetches 	*/	  /* based on limit.						*/	  deferred = *(word *)limit;	  FIXUP_POINTER(deferred);	  limit -= ALIGNMENT;	  if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {	    PREFETCH((ptr_t)deferred);	    break;	  }	  if (current_p > limit) goto next_object;	}#     endif      while (current_p <= limit) {	/* Empirically, unrolling this loop doesn't help a lot.	*/	/* Since PUSH_CONTENTS expands to a lot of code,	*/	/* we don't.						*/        current = *(word *)current_p;	FIXUP_POINTER(current);        PREFETCH(current_p + PREF_DIST*CACHE_LINE_SIZE);        if ((ptr_t)current >= least_ha && (ptr_t)current <  greatest_ha) {  	  /* Prefetch the contents of the object we just pushed.  It's	*/  	  /* likely we will need them soon.				*/  	  PREFETCH((ptr_t)current);#         ifdef ENABLE_TRACE	    if (GC_trace_addr == current_p) {	        GC_log_printf("GC:%d Considering(1) %p -> %p\n",			      GC_gc_no, current_p, (ptr_t) current);	    }#         endif /* ENABLE_TRACE */          PUSH_CONTENTS((ptr_t)current, mark_stack_top,  		           mark_stack_limit, current_p, exit2);        }        current_p += ALIGNMENT;      }#     ifndef SMALL_CONFIG	/* We still need to mark the entry we previously prefetched.	*/	/* We already know that it passes the preliminary pointer	*/	/* validity test.						*/#       ifdef ENABLE_TRACE	    if (GC_trace_addr == current_p) {	        GC_log_printf("GC:%d Considering(2) %p -> %p\n",			      GC_gc_no, current_p, (ptr_t) deferred);	    }#       endif /* ENABLE_TRACE */        PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,  		         mark_stack_limit, current_p, exit4);	next_object:;#     endif    }  }  return mark_stack_top;}#ifdef PARALLEL_MARK/* We assume we have an ANSI C Compiler.	*/GC_bool GC_help_wanted = FALSE;unsigned GC_helper_count = 0;unsigned GC_active_count = 0;word GC_mark_no = 0;#define LOCAL_MARK_STACK_SIZE HBLKSIZE	/* Under normal circumstances, this is big enough to guarantee	*/	/* We don't overflow half of it in a single call to 		*/	/* GC_mark_from.						*//* Steal mark stack entries starting at mse low into mark stack local	*//* until we either steal mse high, or we have max entries.		*//* Return a pointer to the top of the local mark stack.		        *//* *next is replaced by a pointer to the next unscanned mark stack	*//* entry.								*/mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,			  unsigned max, mse **next){    mse *p;    mse *top = local - 1;    unsigned i = 0;    GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);    for (p = low; p <= high && i <= max; ++p) {	word descr = AO_load((volatile AO_t *) &(p -> mse_descr));	if (descr != 0) {	    /* Must be ordered after read of descr: */	    AO_store_release_write((volatile AO_t *) &(p -> mse_descr), 0);	    /* More than one thread may get this entry, but that's only */	    /* a minor performance problem.				*/	    ++top;	    top -> mse_descr = descr;	    top -> mse_start = p -> mse_start;	    GC_ASSERT((top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH || 		      top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr			                 - (ptr_t)GC_least_plausible_heap_addr);	    /* If this is a big object, count it as			*/	    /* size/256 + 1 objects.					*/	    ++i;	    if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (descr >> 8);	}    }    *next = p;    return top;}/* Copy back a local mark stack.	*//* low and high are inclusive bounds.	*/void GC_return_mark_stack(mse * low, mse * high){    mse * my_top;    mse * my_start;    size_t stack_size;    if (high < low) return;    stack_size = high - low + 1;    GC_acquire_mark_lock();    my_top = GC_mark_stack_top;	/* Concurrent modification impossible. */    my_start = my_top + 1;    if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) {      if (GC_print_stats) {	  GC_log_printf("No room to copy back mark stack.");      }      GC_mark_state = MS_INVALID;      GC_mark_stack_too_small = TRUE;      /* We drop the local mark stack.  We'll fix things later.	*/    } else {      BCOPY(low, my_start, stack_size * sizeof(mse));      GC_ASSERT((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))		== my_top);      AO_store_release_write((volatile AO_t *)(&GC_mark_stack_top),		             (AO_t)(my_top + stack_size));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -