242 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
namespace factor {
 | 
						|
 | 
						|
struct must_start_gc_again {
 | 
						|
};
 | 
						|
 | 
						|
template <typename TargetGeneration, typename Policy>
 | 
						|
struct gc_workhorse : no_fixup {
 | 
						|
  static const bool translated_code_block_map = false;
 | 
						|
 | 
						|
  factor_vm* parent;
 | 
						|
  TargetGeneration* target;
 | 
						|
  Policy policy;
 | 
						|
  code_heap* code;
 | 
						|
 | 
						|
  gc_workhorse(factor_vm* parent_, TargetGeneration* target_, Policy policy_)
 | 
						|
      : parent(parent_), target(target_), policy(policy_), code(parent->code) {}
 | 
						|
 | 
						|
  object* resolve_forwarding(object* untagged) {
 | 
						|
    parent->check_data_pointer(untagged);
 | 
						|
 | 
						|
    /* is there another forwarding pointer? */
 | 
						|
    while (untagged->forwarding_pointer_p())
 | 
						|
      untagged = untagged->forwarding_pointer();
 | 
						|
 | 
						|
    /* we've found the destination */
 | 
						|
    return untagged;
 | 
						|
  }
 | 
						|
 | 
						|
  object* promote_object(object* untagged) {
 | 
						|
    cell size = untagged->size();
 | 
						|
    object* newpointer = target->allot(size);
 | 
						|
    if (!newpointer)
 | 
						|
      throw must_start_gc_again();
 | 
						|
 | 
						|
    memcpy(newpointer, untagged, size);
 | 
						|
    untagged->forward_to(newpointer);
 | 
						|
 | 
						|
    policy.promoted_object(newpointer);
 | 
						|
 | 
						|
    return newpointer;
 | 
						|
  }
 | 
						|
 | 
						|
  object* fixup_data(object* obj) {
 | 
						|
    parent->check_data_pointer(obj);
 | 
						|
 | 
						|
    if (!policy.should_copy_p(obj)) {
 | 
						|
      policy.visited_object(obj);
 | 
						|
      return obj;
 | 
						|
    }
 | 
						|
 | 
						|
    object* forwarding = resolve_forwarding(obj);
 | 
						|
 | 
						|
    if (forwarding == obj)
 | 
						|
      return promote_object(obj);
 | 
						|
    else if (policy.should_copy_p(forwarding))
 | 
						|
      return promote_object(forwarding);
 | 
						|
    else {
 | 
						|
      policy.visited_object(forwarding);
 | 
						|
      return forwarding;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  code_block* fixup_code(code_block* compiled) {
 | 
						|
    if (!code->marked_p(compiled)) {
 | 
						|
      code->set_marked_p(compiled);
 | 
						|
      parent->mark_stack.push_back((cell) compiled + 1);
 | 
						|
    }
 | 
						|
 | 
						|
    return compiled;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
struct dummy_unmarker {
 | 
						|
  void operator()(card* ptr) {}
 | 
						|
};
 | 
						|
 | 
						|
struct simple_unmarker {
 | 
						|
  card unmask;
 | 
						|
  explicit simple_unmarker(card unmask_) : unmask(unmask_) {}
 | 
						|
  void operator()(card* ptr) { *ptr &= ~unmask; }
 | 
						|
};
 | 
						|
 | 
						|
struct full_unmarker {
 | 
						|
  full_unmarker() {}
 | 
						|
  void operator()(card* ptr) { *ptr = 0; }
 | 
						|
};
 | 
						|
 | 
						|
template <typename TargetGeneration, typename Policy> struct collector {
 | 
						|
  factor_vm* parent;
 | 
						|
  data_heap* data;
 | 
						|
  code_heap* code;
 | 
						|
  TargetGeneration* target;
 | 
						|
  gc_workhorse<TargetGeneration, Policy> workhorse;
 | 
						|
  slot_visitor<gc_workhorse<TargetGeneration, Policy> > data_visitor;
 | 
						|
  cell cards_scanned;
 | 
						|
  cell decks_scanned;
 | 
						|
  cell code_blocks_scanned;
 | 
						|
 | 
						|
  collector(factor_vm* parent_, TargetGeneration* target_, Policy policy_)
 | 
						|
      : parent(parent_),
 | 
						|
        data(parent_->data),
 | 
						|
        code(parent_->code),
 | 
						|
        target(target_),
 | 
						|
        workhorse(parent, target, policy_),
 | 
						|
        data_visitor(parent, workhorse),
 | 
						|
        cards_scanned(0),
 | 
						|
        decks_scanned(0),
 | 
						|
        code_blocks_scanned(0) {}
 | 
						|
 | 
						|
  void trace_handle(cell* handle) { data_visitor.visit_handle(handle); }
 | 
						|
 | 
						|
  void trace_object(object* ptr) {
 | 
						|
    data_visitor.visit_slots(ptr);
 | 
						|
    if (ptr->type() == ALIEN_TYPE)
 | 
						|
      ((alien*)ptr)->update_address();
 | 
						|
  }
 | 
						|
 | 
						|
  void trace_roots() { data_visitor.visit_roots(); }
 | 
						|
 | 
						|
  void trace_contexts() { data_visitor.visit_contexts(); }
 | 
						|
 | 
						|
  void trace_code_block_objects(code_block* compiled) {
 | 
						|
    data_visitor.visit_code_block_objects(compiled);
 | 
						|
  }
 | 
						|
 | 
						|
  void trace_embedded_literals(code_block* compiled) {
 | 
						|
    data_visitor.visit_embedded_literals(compiled);
 | 
						|
  }
 | 
						|
 | 
						|
  void trace_code_heap_roots(std::set<code_block*>* remembered_set) {
 | 
						|
    std::set<code_block*>::const_iterator iter = remembered_set->begin();
 | 
						|
    std::set<code_block*>::const_iterator end = remembered_set->end();
 | 
						|
 | 
						|
    for (; iter != end; iter++) {
 | 
						|
      code_block* compiled = *iter;
 | 
						|
      trace_code_block_objects(compiled);
 | 
						|
      trace_embedded_literals(compiled);
 | 
						|
      compiled->flush_icache();
 | 
						|
      code_blocks_scanned++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  inline cell first_card_in_deck(cell deck) {
 | 
						|
    return deck << (deck_bits - card_bits);
 | 
						|
  }
 | 
						|
 | 
						|
  inline cell last_card_in_deck(cell deck) {
 | 
						|
    return first_card_in_deck(deck + 1);
 | 
						|
  }
 | 
						|
 | 
						|
  inline cell card_deck_for_address(cell a) {
 | 
						|
    return addr_to_deck(a - data->start);
 | 
						|
  }
 | 
						|
 | 
						|
  inline cell card_start_address(cell card) {
 | 
						|
    return (card << card_bits) + data->start;
 | 
						|
  }
 | 
						|
 | 
						|
  inline cell card_end_address(cell card) {
 | 
						|
    return ((card + 1) << card_bits) + data->start;
 | 
						|
  }
 | 
						|
 | 
						|
  void trace_partial_objects(cell start, cell end, cell card_start,
 | 
						|
                             cell card_end) {
 | 
						|
    if (card_start < end) {
 | 
						|
      start += sizeof(cell);
 | 
						|
 | 
						|
      if (start < card_start)
 | 
						|
        start = card_start;
 | 
						|
      if (end > card_end)
 | 
						|
        end = card_end;
 | 
						|
 | 
						|
      cell* slot_ptr = (cell*)start;
 | 
						|
      cell* end_ptr = (cell*)end;
 | 
						|
 | 
						|
      for (; slot_ptr < end_ptr; slot_ptr++)
 | 
						|
        data_visitor.visit_handle(slot_ptr);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  template <typename SourceGeneration, typename Unmarker>
 | 
						|
  void trace_cards(SourceGeneration* gen, card mask, Unmarker unmarker) {
 | 
						|
    card_deck* decks = data->decks;
 | 
						|
    card_deck* cards = data->cards;
 | 
						|
 | 
						|
    cell gen_start_card = addr_to_card(gen->start - data->start);
 | 
						|
 | 
						|
    cell first_deck = card_deck_for_address(gen->start);
 | 
						|
    cell last_deck = card_deck_for_address(gen->end);
 | 
						|
 | 
						|
    cell start = 0, binary_start = 0, end = 0;
 | 
						|
 | 
						|
    for (cell deck_index = first_deck; deck_index < last_deck; deck_index++) {
 | 
						|
      if (decks[deck_index] & mask) {
 | 
						|
        decks_scanned++;
 | 
						|
 | 
						|
        cell first_card = first_card_in_deck(deck_index);
 | 
						|
        cell last_card = last_card_in_deck(deck_index);
 | 
						|
 | 
						|
        for (cell card_index = first_card; card_index < last_card;
 | 
						|
             card_index++) {
 | 
						|
          if (cards[card_index] & mask) {
 | 
						|
            cards_scanned++;
 | 
						|
 | 
						|
            if (end < card_start_address(card_index)) {
 | 
						|
              start = gen->starts
 | 
						|
                  .find_object_containing_card(card_index - gen_start_card);
 | 
						|
              binary_start = start + ((object*)start)->binary_payload_start();
 | 
						|
              end = start + ((object*)start)->size();
 | 
						|
            }
 | 
						|
 | 
						|
          scan_next_object:
 | 
						|
            if (start < card_end_address(card_index)) {
 | 
						|
              trace_partial_objects(start, binary_start,
 | 
						|
                                    card_start_address(card_index),
 | 
						|
                                    card_end_address(card_index));
 | 
						|
              if (end < card_end_address(card_index)) {
 | 
						|
                start = gen->next_object_after(start);
 | 
						|
                if (start) {
 | 
						|
                  binary_start =
 | 
						|
                      start + ((object*)start)->binary_payload_start();
 | 
						|
                  end = start + ((object*)start)->size();
 | 
						|
                  goto scan_next_object;
 | 
						|
                }
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            unmarker(&cards[card_index]);
 | 
						|
 | 
						|
            if (!start)
 | 
						|
              return;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        unmarker(&decks[deck_index]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
}
 |