예제 #1
0
static void trace_object(Heap_Verifier* heap_verifier, Partial_Reveal_Object* p_obj)
{ 
  scan_object(heap_verifier, p_obj);
  GC_Verifier* gc_verifier = heap_verifier->gc_verifier;
  Vector_Block* trace_stack = (Vector_Block*)gc_verifier->trace_stack;
  while( !vector_stack_is_empty(trace_stack)){
    p_obj = (Partial_Reveal_Object *)vector_stack_pop(trace_stack); 
    scan_object(heap_verifier, p_obj);
    trace_stack = (Vector_Block*)gc_verifier->trace_stack;
  }
  return; 
}
static void trace_object(Collector* collector, Partial_Reveal_Object *p_obj)
{ 
  scan_object(collector, p_obj);
  
  Vector_Block* trace_stack = collector->trace_stack;
  while( !vector_stack_is_empty(trace_stack)){
    p_obj = (Partial_Reveal_Object *)vector_stack_pop(trace_stack); 
    scan_object(collector, p_obj);
    trace_stack = collector->trace_stack;
  }
    
  return; 
}
예제 #3
0
static void trace_object(Conclctor* marker, Partial_Reveal_Object *p_obj)
{
  scan_object(marker, p_obj);
  obj_mark_black_in_table(p_obj, marker);
  
  Vector_Block *trace_stack = marker->trace_stack;
  while(!vector_stack_is_empty(trace_stack)){
    p_obj = (Partial_Reveal_Object*)vector_stack_pop(trace_stack);
    scan_object(marker, p_obj);
    obj_mark_black_in_table(p_obj, marker);    
    trace_stack = marker->trace_stack;
  }
}
예제 #4
0
  void MarkSweepGC::collect(Roots &roots, CallFrameLocationList& call_frames) {
    Object* tmp;

    Root* root = static_cast<Root*>(roots.head());
    while(root) {
      tmp = root->get();
      if(tmp->reference_p()) {
        saw_object(tmp);
      }

      root = static_cast<Root*>(root->next());
    }

    // Walk all the call frames
    for(CallFrameLocationList::const_iterator i = call_frames.begin();
        i != call_frames.end();
        ++i) {
      CallFrame** loc = *i;
      walk_call_frame(*loc);
    }

    while(!mark_stack_.empty()) {
      tmp = mark_stack_.back();
      mark_stack_.pop_back();
      scan_object(tmp);
    }

    after_marked();
  }
예제 #5
0
파일: baker.cpp 프로젝트: Emily/rubinius
  /**
   * Scans the remaining unscanned portion of the Next heap.
   */
  void BakerGC::copy_unscanned() {
    Object* iobj = next->next_unscanned(object_memory_->state());

    while(iobj) {
      if(!iobj->forwarded_p()) scan_object(iobj);
      iobj = next->next_unscanned(object_memory_->state());
    }
  }
예제 #6
0
  void BakerGC::copy_unscanned() {
    Object* iobj = next->next_unscanned(object_memory->state);

    while(iobj) {
      assert(iobj->zone == YoungObjectZone);
      if(!iobj->forwarded_p()) scan_object(iobj);
      iobj = next->next_unscanned(object_memory->state);
    }
  }
예제 #7
0
파일: baker.cpp 프로젝트: Emily/rubinius
 void BakerGC::scan_mature_mark_stack() {
   immix::MarkStack& stack = object_memory_->mature_mark_stack();
   for(immix::MarkStack::iterator i = stack.begin(); i != stack.end(); ++i) {
     Object* obj = (*i).as<Object>();
     if(obj && obj->mature_object_p()) {
       scan_object(obj);
     }
   }
 }
예제 #8
0
  void ImmixGC::collect_finish(GCData* data) {
    collect_scan(data);

    ObjectArray* marked_set = object_memory_->swap_marked_set();
    for(ObjectArray::iterator oi = marked_set->begin();
        oi != marked_set->end();
        ++oi) {
      Object* obj = *oi;
      if(obj) saw_object(obj);
    }
    delete marked_set;

    // Users manipulate values accessible from the data* within an
    // RData without running a write barrier. Thusly if we see any rdata
    // we must always scan it again here because it could contain new pointers.
    //
    // We do this in a loop because the scanning might generate new entries
    // on the mark stack.
    do {
      for(Allocator<capi::Handle>::Iterator i(data->handles()->allocator()); i.more(); i.advance()) {
        capi::Handle* hdl = i.current();
        if(!hdl->in_use_p()) continue;
        if(hdl->is_rdata()) {
          Object* obj = hdl->object();
          if(obj->marked_p(object_memory_->mark())) {
            scan_object(obj);
          }
        }
      }
    } while(process_mark_stack());

    // We've now finished marking the entire object graph.
    // Clean weakrefs before keeping additional objects alive
    // for finalization, so people don't get a hold of finalized
    // objects through weakrefs.
    clean_weakrefs();

    // Marking objects to be Finalized can cause more things to continue to
    // live, so we must check the mark_stack again.
    do {
      walk_finalizers();
      scan_fibers(data, true);
    } while(process_mark_stack());

    // Remove unreachable locked objects still in the list
    if(data->threads()) {
      for(std::list<ManagedThread*>::iterator i = data->threads()->begin();
          i != data->threads()->end();
          ++i) {
        clean_locked_objects(*i, false);
      }
    }

    // Clear unreachable objects from the various remember sets
    unsigned int mark = object_memory_->mark();
    object_memory_->unremember_objects(mark);
  }
예제 #9
0
void flx_collector_t::scan_object(void *p, int reclimit)
{
  Word_t reachable = (parity & 1UL) ^ 1UL;
again:
  if(debug)
    fprintf(stderr,"Scan object %p, reachable bit value = %d\n",p,(int)reachable);
  Word_t cand = (Word_t)p;
  Word_t head=cand;
  Word_t *ppshape = (Word_t*)JudyLLast(j_shape,&head,&je);
  if(ppshape==(Word_t*)PPJERR)judyerror("scan_object");
  if(ppshape == NULL) return; // no lower object
  /*
  if(debug)
  {
    fprintf(stderr,"Found candidate object %p, &shape=%p, shape(1) %p\n",(void*)fp,(void*)w,(void*)(*w));
    fprintf(stderr," .. type=%s!\n",((gc_shape_t*)(*w & ~1UL))->cname);
  }
  */
  if( (*ppshape & 1UL) == reachable) return;   // already handled

  gc_shape_t *pshape = (gc_shape_t*)(*ppshape & ~1UL);
  unsigned long n = get_count((void*)head) * pshape->count * pshape->amt;
  if(cand >= (Word_t)(void*)((unsigned char*)(void*)head+n)) return; // not interior
  if(debug)
    fprintf(stderr,"MARKING object %p, shape %p, type=%s\n",(void*)head,pshape,pshape->cname);

  *ppshape = (*ppshape & ~1uL) | reachable;


  if(pshape->flags & gc_flags_conservative)
  {
    unsigned long n_used = get_used((void*)head) * pshape->count;
    // end of object, rounded down to size of a void*
    void **end = (void**)(
      (unsigned char*)(void*)head +
      n_used * n / sizeof(void*) * sizeof(void*)
    );
    for ( void **i = (void**)head; i != end; i = i+1)
    {
      //if(debug)
      //  fprintf(stderr, "Check if *%p=%p is a pointer\n",i,*(void**)i);
      if(reclimit==0)
        Judy1Set(&j_tmp,(Word_t)*i,&je);
      else
        scan_object(*i,reclimit -1);
    }
  }
  else
  {
    unsigned long dyncount = get_used((void*)head);
    if(pshape->scanner) {
      void *r = pshape->scanner(this, pshape, (void*)head,dyncount,reclimit);
      if (r) { p = r; goto again; }
    }
  }
}
예제 #10
0
  Object* ObjectWalker::next() {
    if(stack_.empty()) return 0;

    Object* obj = stack_.back();
    stack_.pop_back();

    scan_object(obj);

    return obj;
  }
예제 #11
0
파일: baker.cpp 프로젝트: Emily/rubinius
  void BakerGC::scan_mark_set() {
    // Update the marked set and remove young not forwarded objects
    ObjectArray* marked_set = object_memory_->marked_set();

    for(ObjectArray::iterator oi = marked_set->begin();
        oi != marked_set->end(); ++oi) {
      Object* obj = *oi;
      if(obj && obj->mature_object_p()) {
        scan_object(obj);
      }
    }
  }
예제 #12
0
파일: baker.cpp 프로젝트: jockee/rubinius
  void BakerGC::walk_finalizers() {
    FinalizerHandler* fh = object_memory_->finalizer_handler();
    if(!fh) return;

    for(FinalizerHandler::iterator i = fh->begin();
        !i.end();
        /* advance is handled in the loop */)
    {
      FinalizeObject& fi = i.current();
      bool live = true;

      if(fi.object->young_object_p()) {
        live = fi.object->forwarded_p();
        if(Object* fwd = saw_object(fi.object)) {
          fi.object = fwd;
        }
      } else {
        // If this object is mature, scan it. This
        // means that any young objects it refers to are properly
        // GC'ed and kept alive if necessary
        scan_object(fi.object);
      }

      Object* fin = fi.ruby_finalizer;
      if(fin && fin->reference_p()) {
        if(fin->young_object_p()) {
          if(Object* fwd = saw_object(fin)) {
            fi.ruby_finalizer = fwd;
          }
        } else {
          // If this object is mature, scan it. This
          // means that any young objects it refers to are properly
          // GC'ed and kept alive if necessary
          scan_object(fin);
        }
      }

      i.next(live);
    }
  }
예제 #13
0
void ObjectTree::introspect(const char *service, EdbusConnection *c) {
	clear();

#if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 3)
	/* fix scrollbar position, since Fl_Tree doesn't do this */
	_vscroll->value(0);
#endif

	/* first we start with '/', as root object, since all services implement this one */
	EdbusMessage  m;
	scan_object(c, m, service, "/", this);
	redraw();
}
예제 #14
0
  bool BakerGC::handle_promotions() {
    if(promoted_stack_.empty() && fully_scanned_p()) return false;

    while(!promoted_stack_.empty() || !fully_scanned_p()) {
      while(!promoted_stack_.empty()) {
        Object* obj = promoted_stack_.back();
        promoted_stack_.pop_back();

        scan_object(obj);
      }

      copy_unscanned();
    }

    return true;
  }
예제 #15
0
  Object* MarkSweepGC::saw_object(Object* obj) {
    if(obj->young_object_p()) {
      if(obj->marked_p()) return NULL;

      obj->mark();
    } else {
      Entry *entry = find_entry(obj);
      if(entry->marked_p()) return NULL;

      entry->mark();
    }

    /* Recurse down, scanning each object as we see it. */
    scan_object(obj);
    return NULL;
  }
예제 #16
0
파일: baker.cpp 프로젝트: jockee/rubinius
  void BakerGC::scan_mark_set() {
    // Scan any mature objects in the mark set
    // since they might refer to young objects.
    ObjectArray* marked_set = object_memory_->marked_set();

    // This explicitly does not use an iterator. This is because
    // there might be elements appended to this list by scanning
    // which in turn can trigger a vector resize. This would invalidate
    // the iterator and result in invalid memory being read.
    for(ObjectArray::size_type i = 0; i < marked_set->size(); ++i) {
      Object* obj = marked_set->at(i);
      if(obj && obj->mature_object_p()) {
        scan_object(obj);
      }
    }
  }
예제 #17
0
  Object* HeapDebug::saw_object(Object* obj) {
    if(!obj->reference_p()) return NULL;

    if(seen[obj]) return NULL;
    
    seen_objects++;

    seen[obj] = 1;

    if(obj->young_object_p()) {
      if(!object_memory->young.current->contains_p(obj)) {
        throw std::runtime_error("Invalid young object detected.");
      }
    }

    scan_object(obj);

    return NULL;
  }
예제 #18
0
  /**
   * Perform garbage collection on the young objects.
   */
  void BakerGC::collect(GCData& data, YoungCollectStats* stats) {

#ifdef HAVE_VALGRIND_H
    VALGRIND_MAKE_MEM_DEFINED(next->start().as_int(), next->size());
    VALGRIND_MAKE_MEM_DEFINED(current->start().as_int(), current->size());
#endif

    Object* tmp;
    ObjectArray *current_rs = object_memory_->swap_remember_set();

    total_objects = 0;

    copy_spills_ = 0;
    reset_promoted();

    // Start by copying objects in the remember set
    for(ObjectArray::iterator oi = current_rs->begin();
        oi != current_rs->end();
        ++oi) {
      tmp = *oi;
      // unremember_object throws a NULL in to remove an object
      // so we don't have to compact the set in unremember
      if(tmp) {
        // assert(tmp->mature_object_p());
        // assert(!tmp->forwarded_p());

        // Remove the Remember bit, since we're clearing the set.
        tmp->clear_remember();
        scan_object(tmp);
      }
    }

    delete current_rs;

    for(std::list<gc::WriteBarrier*>::iterator wbi = object_memory_->aux_barriers().begin();
        wbi != object_memory_->aux_barriers().end();
        ++wbi) {
      gc::WriteBarrier* wb = *wbi;
      ObjectArray* rs = wb->swap_remember_set();
      for(ObjectArray::iterator oi = rs->begin();
          oi != rs->end();
          ++oi) {
        tmp = *oi;

        if(tmp) {
          tmp->clear_remember();
          scan_object(tmp);
        }
      }

      delete rs;
    }

    for(Roots::Iterator i(data.roots()); i.more(); i.advance()) {
      i->set(saw_object(i->get()));
    }

    if(data.threads()) {
      for(std::list<ManagedThread*>::iterator i = data.threads()->begin();
          i != data.threads()->end();
          ++i) {
        scan(*i, true);
      }
    }

    for(Allocator<capi::Handle>::Iterator i(data.handles()->allocator()); i.more(); i.advance()) {
      if(!i->in_use_p()) continue;

      if(!i->weak_p() && i->object()->young_object_p()) {
        i->set_object(saw_object(i->object()));

      // Users manipulate values accessible from the data* within an
      // RData without running a write barrier. Thusly if we see a mature
      // rdata, we must always scan it because it could contain
      // young pointers.
      } else if(!i->object()->young_object_p() && i->is_rdata()) {
        scan_object(i->object());
      }

      assert(i->object()->type_id() > InvalidType && i->object()->type_id() < LastObjectType);
    }

    std::list<capi::GlobalHandle*>* gh = data.global_handle_locations();

    if(gh) {
      for(std::list<capi::GlobalHandle*>::iterator i = gh->begin();
          i != gh->end();
          ++i) {
        capi::GlobalHandle* global_handle = *i;
        capi::Handle** loc = global_handle->handle();
        if(capi::Handle* hdl = *loc) {
          if(!REFERENCE_P(hdl)) continue;
          if(hdl->valid_p()) {
            Object* obj = hdl->object();
            if(obj && obj->reference_p() && obj->young_object_p()) {
              hdl->set_object(saw_object(obj));
            }
          } else {
            std::cerr << "Detected bad handle checking global capi handles\n";
          }
        }
      }
    }

#ifdef ENABLE_LLVM
    if(LLVMState* ls = data.llvm_state()) ls->gc_scan(this);
#endif

    // Handle all promotions to non-young space that occurred.
    handle_promotions();

    assert(fully_scanned_p());
    // We're now done seeing the entire object graph of normal, live references.
    // Now we get to handle the unusual references, like finalizers and such.

    // Objects with finalizers must be kept alive until the finalizers have
    // run.
    walk_finalizers();

    // Process possible promotions from processing objects with finalizers.
    handle_promotions();

    if(!promoted_stack_.empty()) rubinius::bug("promote stack has elements!");
    if(!fully_scanned_p()) rubinius::bug("more young refs");

    // Check any weakrefs and replace dead objects with nil
    clean_weakrefs(true);

    // Swap the 2 halves
    Heap *x = next;
    next = current;
    current = x;

    if(stats) {
      stats->lifetime = lifetime_;
      stats->percentage_used = current->percentage_used();
      stats->promoted_objects = promoted_objects_;
      stats->excess_objects = copy_spills_;
    }

    // Tune the age at which promotion occurs
    if(autotune_) {
      double used = current->percentage_used();
      if(used > cOverFullThreshold) {
        if(tune_threshold_ >= cOverFullTimes) {
          if(lifetime_ > cMinimumLifetime) lifetime_--;
        } else {
          tune_threshold_++;
        }
      } else if(used < cUnderFullThreshold) {
        if(tune_threshold_ <= cUnderFullTimes) {
          if(lifetime_ < cMaximumLifetime) lifetime_++;
        } else {
          tune_threshold_--;
        }
      } else if(tune_threshold_ > 0) {
        tune_threshold_--;
      } else if(tune_threshold_ < 0) {
        tune_threshold_++;
      } else if(tune_threshold_ == 0) {
        if(lifetime_ < original_lifetime_) {
          lifetime_++;
        } else if(lifetime_ > original_lifetime_) {
          lifetime_--;
        }
      }
    }

  }
예제 #19
0
static FORCE_INLINE void forward_object(Collector *collector, REF *p_ref) 
{
  Space* space = collector->collect_space; 
  GC* gc = collector->gc;
  Partial_Reveal_Object *p_obj = read_slot(p_ref);

  /* p_obj can also be in tospace because this p_ref is a redundant one in mutator remset. 
     We don't rem p_ref because it was remembered in first time it's met. 
     FIXME:: the situation obj_belongs_to_tospace() should never be true if we
     remember object rather than slot. Currently, mutator remembers objects, and
     collector remembers slots. Although collectors remember slots, we are sure 
     there are no chances to have repetitive p_ref because an object is scanned only
     when it is marked or forwarded atomically, hence only one collector has chance
     to do the scanning. */   
  if(!obj_belongs_to_nos(p_obj) || obj_belongs_to_tospace(p_obj)) return; 

  Partial_Reveal_Object* p_target_obj = NULL;
  Boolean to_rem_slot = FALSE;

  /* Fastpath: object has already been forwarded, update the ref slot */
  if(obj_is_fw_in_oi(p_obj)){
    p_target_obj = obj_get_fw_in_oi(p_obj);
    write_slot(p_ref, p_target_obj);

    /* check if the target obj stays in NOS, and p_ref from MOS. If yes, rem p_ref. */
    if(obj_belongs_to_tospace(p_target_obj))
      if( !addr_belongs_to_nos(p_ref) && address_belongs_to_gc_heap(p_ref, gc))
        collector_remset_add_entry(collector, ( Partial_Reveal_Object**) p_ref); 

    return; 
  }  
    
  /* following is the logic for forwarding */  
  p_target_obj = collector_forward_object(collector, p_obj);
  
  /* if p_target_obj is NULL, it is forwarded by other thread. 
      Note: a race condition here, it might be forwarded by other, but not set the 
      forwarding pointer yet. We need spin here to get the forwarding pointer. 
      We can implement the collector_forward_object() so that the forwarding pointer 
      is set in the atomic instruction, which requires to roll back the mos_alloced
      space. That is easy for thread local block allocation cancellation. */
  if( p_target_obj == NULL ){
    if(collector->result == FALSE ){
      /* failed to forward, let's get back to controller. */
      vector_stack_clear(collector->trace_stack);
      return;
    }
    /* forwarded already*/
    p_target_obj = obj_get_fw_in_oi(p_obj);
  
  }else{  /* otherwise, we successfully forwarded */

#ifdef GC_GEN_STATS
  if(gc_profile){
    GC_Gen_Collector_Stats* stats = (GC_Gen_Collector_Stats*)collector->stats;
    gc_gen_collector_update_marked_nos_obj_stats_minor(stats);
    gc_gen_collector_update_moved_nos_obj_stats_minor(stats, vm_object_size(p_obj));
  }
#endif

    scan_object(collector, p_target_obj);
  }
  
  assert(p_target_obj);
  write_slot(p_ref, p_target_obj);
  
  /* check if the target obj stays in NOS, and p_ref from MOS. If yes, rem p_ref. */
  if(obj_belongs_to_tospace(p_target_obj)){
    if( !addr_belongs_to_nos(p_ref) && address_belongs_to_gc_heap(p_ref, gc))
      collector_remset_add_entry(collector, ( Partial_Reveal_Object**) p_ref); 
  }
   
  return;
}
예제 #20
0
static void scan_object(EdbusConnection *conn, EdbusMessage &msg, const char *service, const char *path, ObjectTree *self) {
	EdbusMessage reply;
	msg.create_method_call(service, path, INTROSPECTABLE_INTERFACE, INTROSPECTABLE_METHOD);

	if(!conn->send_with_reply_and_block(msg, 1000, reply)) {
		E_WARNING(E_STRLOC ": Did not get reply from service bus. Skipping introspection of '%s' service (object path: '%s')\n", service, path);
		return;
	}

	/* reply must be single element and string, which is xml */
	if(reply.size() != 1) {
		E_WARNING(E_STRLOC ": Expected only one element, but got '%i'\n", reply.size());
		return;
	}

	EdbusMessage::const_iterator it = reply.begin();
	if(!it->is_string()) {
		E_WARNING(E_STRLOC ": Expected string in reply, but got some junk\n");
		return;
	}

	TiXmlDocument doc;
	char buf[128];
	Fl_Tree_Item *titem;

	doc.Parse(it->to_string());
	TiXmlNode *el = doc.FirstChild("node");
	if(!el) return;

	for(el = el->FirstChildElement(); el; el = el->NextSibling()) {
		/* we have subobjects */
		if(STR_CMP_VALUE(el, "node")) {
			const char *name = el->ToElement()->Attribute("name");
			if(!name) {
				E_DEBUG(E_STRLOC ": <node> is expected to have 'name' attribute\n");
				continue;
			}

			/* TODO: maybe use EdbusObjectPath? */
			if(strcmp(path, "/") == 0)
				snprintf(buf, sizeof(buf), "/%s", name);
			else
				snprintf(buf, sizeof(buf), "%s/%s", path, name);

			titem = self->add(buf);
			self->close(titem);
			titem->usericon(&image_package);

			/* recurse */
			scan_object(conn, msg, service, buf, self);
		} else if(STR_CMP_VALUE(el, "interface")) {
			/* full interface: get methods and properties */
			const char *interface_name, *name = el->ToElement()->Attribute("name");
			/* remember it for Entity */
			interface_name = name;
			if(!name) {
				E_DEBUG(E_STRLOC ": <interface> is expected to have 'name' attribute\n");
				continue;
			}

			/* append interface to tree */
			snprintf(buf, sizeof(buf), "%s/%s", path, name);
			titem = self->add(buf);
			self->close(titem);
			titem->usericon(&image_interface);

			/* append methods, signals and properties */
			TiXmlNode *sel;
			char buf2[256];
			Fl_Pixmap *icon;
			EntityType et;

			for(sel = el->FirstChildElement(); sel; sel = sel->NextSibling()) {
				if(STR_CMP_VALUE(sel, "method")) {
					icon = &image_method;
					et = ENTITY_METHOD;
				} else if(STR_CMP_VALUE(sel, "signal")) {
					icon = &image_signal;
					et = ENTITY_SIGNAL;
				} else if(STR_CMP_VALUE(sel, "property")) {
					icon = &image_property;
					et = ENTITY_PROPERTY;
				} else {
					E_WARNING(E_STRLOC ": Got unknown node '%s'. Skipping...\n", sel->Value());
					continue;
				}

				/* everything else are common elements between different types */
				name = sel->ToElement()->Attribute("name");
				snprintf(buf2, sizeof(buf2), "%s/%s", buf, name);
				titem = self->add(buf2);
				titem->usericon(icon);
				self->close(titem);

				/* fill our metadata */
				Entity *en = new Entity();
				en->set_type(et);
				en->set_name(name);
				en->set_interface(interface_name);
				en->set_path(path);

				/* TODO: this doesn't have to be copied */
				en->set_service(service);

				if(et == ENTITY_PROPERTY) {
					const char *argstype, *argsname, *argsaccess;
					argstype = sel->ToElement()->Attribute("type");
					argsname = sel->ToElement()->Attribute("name");
					argsaccess = sel->ToElement()->Attribute("access");

					en->append_arg(argsname, argstype, DIRECTION_NONE, argsaccess);
				} else {
					TiXmlNode *argsnode;
					for(argsnode = sel->FirstChildElement(); argsnode; argsnode = argsnode->NextSibling()) {
						if(STR_CMP_VALUE(argsnode, "arg")) {
							/* arguments */
							const char *argstype, *argsname, *argsdirection;
							ArgDirection dir = DIRECTION_NONE;

							argstype = argsnode->ToElement()->Attribute("type");
							if(!argstype) continue;

							argsname = argsnode->ToElement()->Attribute("name");
							if(!argsname) continue;

							/* it is fine to not have direction, which means it is only a method */
							argsdirection = argsnode->ToElement()->Attribute("direction");
							if(argsdirection) {
								if(STR_CMP(argsdirection, "in"))
									dir = DIRECTION_IN;
								else if(STR_CMP(argsdirection, "out"))
									dir = DIRECTION_OUT;
							}

							en->append_arg(argsname, argstype, dir);
						} else if(STR_CMP_VALUE(argsnode, "annotation")) {
							const char *annoname, *argsval;

							annoname = argsnode->ToElement()->Attribute("name");
							/* allow whatever annotation name ending with '.DocString' to be supported (e.g. org.gtk.GDBus.DocString or org.equinoxproject.DBus.DocString) */
							if(!str_ends(annoname, ".DocString")) {
								E_WARNING(E_STRLOC ": We are supporting now only DocString annotations. Skipping '%s'...\n", annoname);
								continue;
							}

							argsval = argsnode->ToElement()->Attribute("value");
							if(argsval) en->set_doc(argsval);
						}
					}
				}

				/* put it inside our tree so we can manage it */
				self->append_entity(en);
				/* add also inside Fl_Tree_Item */
				titem->user_data(en);
			}
		}
	}
}
예제 #21
0
static FORCE_INLINE void forward_object(Collector* collector, REF *p_ref) 
{
  GC* gc = collector->gc;
  Partial_Reveal_Object *p_obj = read_slot(p_ref);

  if(obj_belongs_to_tospace(p_obj)) return;
    
  if(!obj_belongs_to_nos(p_obj)){
    if(obj_mark_in_oi(p_obj)){
#ifdef GC_GEN_STATS
      if(gc_profile){
        GC_Gen_Collector_Stats* stats = (GC_Gen_Collector_Stats*)collector->stats;
        gc_gen_collector_update_marked_nonnos_obj_stats_minor(stats);
      }
#endif
      scan_object(collector, p_obj);
    }
    return;
  }

  Partial_Reveal_Object* p_target_obj = NULL;
  /* Fastpath: object has already been forwarded, update the ref slot */
  if(obj_is_fw_in_oi(p_obj)) {
    p_target_obj = obj_get_fw_in_oi(p_obj);
    assert(p_target_obj);
    write_slot(p_ref, p_target_obj);
    return;
  }

  /* following is the logic for forwarding */  
  p_target_obj = collector_forward_object(collector, p_obj);
  
  /* if p_target_obj is NULL, it is forwarded by other thread. 
      We can implement the collector_forward_object() so that the forwarding pointer 
      is set in the atomic instruction, which requires to roll back the mos_alloced
      space. That is easy for thread local block allocation cancellation. */
  if( p_target_obj == NULL ){
    if(collector->result == FALSE ){
      /* failed to forward, let's get back to controller. */
      vector_stack_clear(collector->trace_stack);
      return;
    }

    p_target_obj = obj_get_fw_in_oi(p_obj);
    assert(p_target_obj);
    write_slot(p_ref, p_target_obj);
    return;
  }
  /* otherwise, we successfully forwarded */

#ifdef GC_GEN_STATS
  if(gc_profile){
    GC_Gen_Collector_Stats* stats = (GC_Gen_Collector_Stats*)collector->stats;
    gc_gen_collector_update_marked_nos_obj_stats_minor(stats);
    gc_gen_collector_update_moved_nos_obj_stats_minor(stats, vm_object_size(p_obj));
  }
#endif
  write_slot(p_ref, p_target_obj);

  scan_object(collector, p_target_obj); 
  return;
}
예제 #22
0
파일: baker.cpp 프로젝트: Emily/rubinius
  /**
   * Perform garbage collection on the young objects.
   */
  void BakerGC::collect(GCData* data, YoungCollectStats* stats) {

#ifdef HAVE_VALGRIND_H
    (void)VALGRIND_MAKE_MEM_DEFINED(next->start().as_int(), next->size());
    (void)VALGRIND_MAKE_MEM_DEFINED(current->start().as_int(), current->size());
#endif
    mprotect(next->start(), next->size(), PROT_READ | PROT_WRITE);
    mprotect(current->start(), current->size(), PROT_READ | PROT_WRITE);

    check_growth_start();

    ObjectArray *current_rs = object_memory_->swap_remember_set();

    total_objects = 0;

    copy_spills_ = 0;
    reset_promoted();

    // Start by copying objects in the remember set
    for(ObjectArray::iterator oi = current_rs->begin();
        oi != current_rs->end();
        ++oi) {
      Object* tmp = *oi;
      // unremember_object throws a NULL in to remove an object
      // so we don't have to compact the set in unremember
      if(tmp) {
        // Remove the Remember bit, since we're clearing the set.
        tmp->clear_remember();
        scan_object(tmp);
      }
    }

    delete current_rs;

    scan_mark_set();
    scan_mature_mark_stack();

    for(Roots::Iterator i(data->roots()); i.more(); i.advance()) {
      i->set(saw_object(i->get()));
    }

    if(data->threads()) {
      for(std::list<ManagedThread*>::iterator i = data->threads()->begin();
          i != data->threads()->end();
          ++i) {
        scan(*i, true);
      }
    }

    for(Allocator<capi::Handle>::Iterator i(data->handles()->allocator()); i.more(); i.advance()) {
      if(!i->in_use_p()) continue;

      if(!i->weak_p() && i->object()->young_object_p()) {
        i->set_object(saw_object(i->object()));

      // Users manipulate values accessible from the data* within an
      // RData without running a write barrier. Thusly if we see a mature
      // rdata, we must always scan it because it could contain
      // young pointers.
      } else if(!i->object()->young_object_p() && i->is_rdata()) {
        scan_object(i->object());
      }
    }

    std::list<capi::GlobalHandle*>* gh = data->global_handle_locations();

    if(gh) {
      for(std::list<capi::GlobalHandle*>::iterator i = gh->begin();
          i != gh->end();
          ++i) {
        capi::GlobalHandle* global_handle = *i;
        capi::Handle** loc = global_handle->handle();
        if(capi::Handle* hdl = *loc) {
          if(!REFERENCE_P(hdl)) continue;
          if(hdl->valid_p()) {
            Object* obj = hdl->object();
            if(obj && obj->reference_p() && obj->young_object_p()) {
              hdl->set_object(saw_object(obj));
            }
          } else {
            std::cerr << "Detected bad handle checking global capi handles\n";
          }
        }
      }
    }

#ifdef ENABLE_LLVM
    if(LLVMState* ls = data->llvm_state()) ls->gc_scan(this);
#endif

    // Handle all promotions to non-young space that occurred.
    handle_promotions();

    assert(fully_scanned_p());
    // We're now done seeing the entire object graph of normal, live references.
    // Now we get to handle the unusual references, like finalizers and such.

    // Check any weakrefs and replace dead objects with nil
    // We need to do this before checking finalizers so people can't access
    // objects kept alive for finalization through weakrefs.
    clean_weakrefs(true);

    do {
      // Objects with finalizers must be kept alive until the finalizers have
      // run.
      walk_finalizers();
      // Scan any fibers that aren't running but still active
      scan_fibers(data, false);
      handle_promotions();
    } while(!promoted_stack_.empty() && !fully_scanned_p());

    // Remove unreachable locked objects still in the list
    if(data->threads()) {
      for(std::list<ManagedThread*>::iterator i = data->threads()->begin();
          i != data->threads()->end();
          ++i) {
        clean_locked_objects(*i, true);
      }
    }

    // Update the pending mark set to remove unreachable objects.
    update_mark_set();

    // Update the existing mark stack of the mature gen because young
    // objects might have moved.
    update_mature_mark_stack();

    // Update the weak ref set to remove unreachable weak refs.
    update_weak_refs_set();

    // Swap the 2 halves
    Heap* x = next;
    next = current;
    current = x;

    if(stats) {
      stats->lifetime = lifetime_;
      stats->percentage_used = current->percentage_used();
      stats->promoted_objects = promoted_objects_;
      stats->excess_objects = copy_spills_;
    }

    // Tune the age at which promotion occurs
    if(autotune_lifetime_) {
      double used = current->percentage_used();
      if(used > cOverFullThreshold) {
        if(tune_threshold_ >= cOverFullTimes) {
          if(lifetime_ > cMinimumLifetime) lifetime_--;
        } else {
          tune_threshold_++;
        }
      } else if(used < cUnderFullThreshold) {
        if(tune_threshold_ <= cUnderFullTimes) {
          if(lifetime_ < cMaximumLifetime) lifetime_++;
        } else {
          tune_threshold_--;
        }
      } else if(tune_threshold_ > 0) {
        tune_threshold_--;
      } else if(tune_threshold_ < 0) {
        tune_threshold_++;
      } else if(tune_threshold_ == 0) {
        if(lifetime_ < original_lifetime_) {
          lifetime_++;
        } else if(lifetime_ > original_lifetime_) {
          lifetime_--;
        }
      }
    }

  }
예제 #23
0
  /* Perform garbage collection on the young objects. */
  void BakerGC::collect(GCData& data) {
#ifdef RBX_GC_STATS
    stats::GCStats::get()->bytes_copied.start();
    stats::GCStats::get()->objects_copied.start();
    stats::GCStats::get()->objects_promoted.start();
    stats::GCStats::get()->collect_young.start();
#endif

    Object* tmp;
    ObjectArray *current_rs = object_memory->remember_set;

    object_memory->remember_set = new ObjectArray(0);
    total_objects = 0;

    // Tracks all objects that we promoted during this run, so
    // we can scan them at the end.
    promoted_ = new ObjectArray(0);

    promoted_current = promoted_insert = promoted_->begin();

    for(ObjectArray::iterator oi = current_rs->begin();
        oi != current_rs->end();
        ++oi) {
      tmp = *oi;
      // unremember_object throws a NULL in to remove an object
      // so we don't have to compact the set in unremember
      if(tmp) {
        assert(tmp->zone == MatureObjectZone);
        assert(!tmp->forwarded_p());

        // Remove the Remember bit, since we're clearing the set.
        tmp->clear_remember();
        scan_object(tmp);
      }
    }

    delete current_rs;

    for(Roots::Iterator i(data.roots()); i.more(); i.advance()) {
      tmp = i->get();
      if(tmp->reference_p() && tmp->young_object_p()) {
        i->set(saw_object(tmp));
      }
    }

    for(VariableRootBuffers::Iterator i(data.variable_buffers());
        i.more(); i.advance()) {
      Object*** buffer = i->buffer();
      for(int idx = 0; idx < i->size(); idx++) {
        Object** var = buffer[idx];
        Object* tmp = *var;

        if(tmp->reference_p() && tmp->young_object_p()) {
          *var = saw_object(tmp);
        }
      }
    }

    // Walk all the call frames
    for(CallFrameLocationList::iterator i = data.call_frames().begin();
        i != data.call_frames().end();
        i++) {
      CallFrame** loc = *i;
      walk_call_frame(*loc);
    }

    /* Ok, now handle all promoted objects. This is setup a little weird
     * so I should explain.
     *
     * We want to scan each promoted object. But this scanning will likely
     * cause more objects to be promoted. Adding to an ObjectArray that your
     * iterating over blows up the iterators, so instead we rotate the
     * current promoted set out as we iterator over it, and stick an
     * empty ObjectArray in.
     *
     * This way, when there are no more objects that are promoted, the last
     * ObjectArray will be empty.
     * */

    promoted_current = promoted_insert = promoted_->begin();

    while(promoted_->size() > 0 || !fully_scanned_p()) {
      if(promoted_->size() > 0) {
        for(;promoted_current != promoted_->end();
            ++promoted_current) {
          tmp = *promoted_current;
          assert(tmp->zone == MatureObjectZone);
          scan_object(tmp);
          if(watched_p(tmp)) {
            std::cout << "detected " << tmp << " during scan of promoted objects.\n";
          }
        }

        promoted_->resize(promoted_insert - promoted_->begin());
        promoted_current = promoted_insert = promoted_->begin();

      }

      /* As we're handling promoted objects, also handle unscanned objects.
       * Scanning these unscanned objects (via the scan pointer) will
       * cause more promotions. */
      copy_unscanned();
    }

    assert(promoted_->size() == 0);

    delete promoted_;
    promoted_ = NULL;

    assert(fully_scanned_p());

    /* Another than is going to be found is found now, so we go back and
     * look at everything in current and call delete_object() on anything
     * thats not been forwarded. */
    find_lost_souls();

    /* Check any weakrefs and replace dead objects with nil*/
    clean_weakrefs(true);

    /* Swap the 2 halves */
    Heap *x = next;
    next = current;
    current = x;
    next->reset();

#ifdef RBX_GC_STATS
    stats::GCStats::get()->collect_young.stop();
    stats::GCStats::get()->objects_copied.stop();
    stats::GCStats::get()->objects_promoted.stop();
    stats::GCStats::get()->bytes_copied.stop();
#endif
  }
예제 #24
0
void flx_collector_t::mark(pthread::memory_ranges_t *px)
{
  int reclimit = 64;
  if(debug)
    fprintf(stderr,"Collector: Running mark\n");
  assert (root_count == roots.size());
  assert(j_tmp == 0);

  if(px)
  {
    std::vector<pthread::memory_range_t>::iterator end = (*px).end();
    for(
      std::vector<pthread::memory_range_t>::iterator i = (*px).begin();
      i != end;
      ++i
    )
    {
      pthread::memory_range_t range = *i;
      if(debug)
      {
        unsigned long n = (char*)range.e - (char*)range.b;
        fprintf(stderr, "Conservate scan of memory %p->%p, %ld bytes\n",range.b, range.e, n);
      }
      //VALGRIND_MAKE_MEM_DEFINED(range.b, (char*)range.e-(char*)range.b);
      void *end = range.e;
      for ( void *i = range.b; i != end; i = (void*)((void**)i+1))
      {
        if(debug)
          fprintf(stderr, "Check if *%p=%p is a pointer\n",i,*(void**)i);
        scan_object(*(void**)i, reclimit);
      }
      if(debug)
        fprintf(stderr, "DONE: Conservate scan of memory %p->%p\n",range.b, range.e);
    }
  }

  if(debug)
    fprintf(stderr, "Scanning roots\n");
  rootmap_t::iterator const end = roots.end();
  for(
    rootmap_t::iterator i = roots.begin();
    i != end;
    ++i
  )
  {
    if (debug)
      fprintf(stderr, "Scanning root %p\n", (*i).first);
    scan_object((*i).first, reclimit);
  }
  // Now, scan the temporary list until it is empty
  Word_t toscan = 0ul;
  int res = Judy1First(j_tmp,&toscan,&je); // get one object scheduled for scanning
  while(res) {
    Judy1Unset(&j_tmp,toscan,&je);         // remove it immediately
    scan_object((void*)toscan, reclimit);            // scan it, it will either be marked or discarded
    toscan = 0ul;
    res = Judy1First(j_tmp,&toscan,&je); 
  }                                     
  assert(j_tmp == 0);                  

  if(debug)
    fprintf(stderr, "Done Scanning roots\n");
}
예제 #25
0
void flx_collector_t::register_pointer(void *q, int reclimit)
{
  if(reclimit==0)Judy1Set(&j_tmp,(Word_t)q,&je);
  else scan_object(q, reclimit-1);
}