| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | namespace factor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-02 14:10:55 -04:00
										 |  |  | struct must_start_gc_again {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | template<typename TargetGeneration, typename Policy> struct gc_workhorse : no_fixup { | 
					
						
							| 
									
										
										
										
											2009-10-18 21:31:59 -04:00
										 |  |  | 	factor_vm *parent; | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 	TargetGeneration *target; | 
					
						
							|  |  |  | 	Policy policy; | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 	code_heap *code; | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 	explicit gc_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) : | 
					
						
							| 
									
										
										
										
											2009-10-18 21:31:59 -04:00
										 |  |  | 		parent(parent_), | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 		target(target_), | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 		policy(policy_), | 
					
						
							|  |  |  | 		code(parent->code) {} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	object *resolve_forwarding(object *untagged) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-10-18 21:31:59 -04:00
										 |  |  | 		parent->check_data_pointer(untagged); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* is there another forwarding pointer? */ | 
					
						
							| 
									
										
										
										
											2009-11-10 22:06:36 -05:00
										 |  |  | 		while(untagged->forwarding_pointer_p()) | 
					
						
							|  |  |  | 			untagged = untagged->forwarding_pointer(); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* we've found the destination */ | 
					
						
							|  |  |  | 		return untagged; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	object *promote_object(object *untagged) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-10-20 14:13:39 -04:00
										 |  |  | 		cell size = untagged->size(); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 		object *newpointer = target->allot(size); | 
					
						
							| 
									
										
										
										
											2010-04-02 14:10:55 -04:00
										 |  |  | 		if(!newpointer) throw must_start_gc_again(); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		memcpy(newpointer,untagged,size); | 
					
						
							| 
									
										
										
										
											2009-11-10 22:06:36 -05:00
										 |  |  | 		untagged->forward_to(newpointer); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 		policy.promoted_object(newpointer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 		return newpointer; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 	object *fixup_data(object *obj) | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-06-13 17:36:08 -04:00
										 |  |  | 		parent->check_data_pointer(obj); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		if(!policy.should_copy_p(obj)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			policy.visited_object(obj); | 
					
						
							|  |  |  | 			return obj; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		object *forwarding = resolve_forwarding(obj); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-30 04:15:50 -04:00
										 |  |  | 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 { | 
					
						
							|  |  |  | 	explicit full_unmarker() {} | 
					
						
							|  |  |  | 	void operator()(card *ptr) { *ptr = 0; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-23 19:51:08 -05:00
										 |  |  | template<typename TargetGeneration, typename Policy> | 
					
						
							|  |  |  | struct collector { | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	factor_vm *parent; | 
					
						
							|  |  |  | 	data_heap *data; | 
					
						
							|  |  |  | 	code_heap *code; | 
					
						
							|  |  |  | 	TargetGeneration *target; | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 	gc_workhorse<TargetGeneration,Policy> workhorse; | 
					
						
							|  |  |  | 	slot_visitor<gc_workhorse<TargetGeneration,Policy> > data_visitor; | 
					
						
							| 
									
										
										
										
											2009-10-26 23:08:35 -04:00
										 |  |  | 	cell cards_scanned; | 
					
						
							|  |  |  | 	cell decks_scanned; | 
					
						
							|  |  |  | 	cell code_blocks_scanned; | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-26 23:08:35 -04:00
										 |  |  | 	explicit collector(factor_vm *parent_, TargetGeneration *target_, Policy policy_) : | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		parent(parent_), | 
					
						
							|  |  |  | 		data(parent_->data), | 
					
						
							|  |  |  | 		code(parent_->code), | 
					
						
							|  |  |  | 		target(target_), | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | 		workhorse(parent,target,policy_), | 
					
						
							|  |  |  | 		data_visitor(parent,workhorse), | 
					
						
							| 
									
										
										
										
											2009-10-26 23:08:35 -04:00
										 |  |  | 		cards_scanned(0), | 
					
						
							|  |  |  | 		decks_scanned(0), | 
					
						
							|  |  |  | 		code_blocks_scanned(0) {} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	void trace_handle(cell *handle) | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-11-23 19:51:08 -05:00
										 |  |  | 		data_visitor.visit_handle(handle); | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 04:25:39 -05:00
										 |  |  | 	void trace_object(object *ptr) | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-11-23 19:51:08 -05:00
										 |  |  | 		data_visitor.visit_slots(ptr); | 
					
						
							| 
									
										
										
										
											2009-11-10 22:06:36 -05:00
										 |  |  | 		if(ptr->type() == ALIEN_TYPE) | 
					
						
							| 
									
										
										
										
											2009-11-02 04:25:39 -05:00
										 |  |  | 			((alien *)ptr)->update_address(); | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	void trace_roots() | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-11-23 19:51:08 -05:00
										 |  |  | 		data_visitor.visit_roots(); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void trace_contexts() | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-11-23 19:51:08 -05:00
										 |  |  | 		data_visitor.visit_contexts(); | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 20:29:59 -05:00
										 |  |  | 	void trace_code_block_objects(code_block *compiled) | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-11-24 20:29:59 -05:00
										 |  |  | 		data_visitor.visit_code_block_objects(compiled); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void trace_embedded_literals(code_block *compiled) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		data_visitor.visit_embedded_literals(compiled); | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 	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(); | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		for(; iter != end; iter++) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2009-11-24 22:36:35 -05:00
										 |  |  | 			code_block *compiled = *iter; | 
					
						
							|  |  |  | 			trace_code_block_objects(compiled); | 
					
						
							|  |  |  | 			trace_embedded_literals(compiled); | 
					
						
							|  |  |  | 			compiled->flush_icache(); | 
					
						
							| 
									
										
										
										
											2009-10-26 23:08:35 -04:00
										 |  |  | 			code_blocks_scanned++; | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		return addr_to_deck(a - data->start); | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inline cell card_start_address(cell card) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		return (card << card_bits) + data->start; | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inline cell card_end_address(cell card) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		return ((card + 1) << card_bits) + data->start; | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-06 02:22:53 -05:00
										 |  |  | 			for(; slot_ptr < end_ptr; slot_ptr++) | 
					
						
							| 
									
										
										
										
											2009-11-23 19:51:08 -05:00
										 |  |  | 				data_visitor.visit_handle(slot_ptr); | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	template<typename SourceGeneration, typename Unmarker> | 
					
						
							|  |  |  | 	void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		card_deck *decks = data->decks; | 
					
						
							|  |  |  | 		card_deck *cards = data->cards; | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-24 04:54:53 -04:00
										 |  |  | 		cell gen_start_card = addr_to_card(gen->start - data->start); | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cell first_deck = card_deck_for_address(gen->start); | 
					
						
							|  |  |  | 		cell last_deck = card_deck_for_address(gen->end); | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 		cell start = 0, binary_start = 0, end = 0; | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 		for(cell deck_index = first_deck; deck_index < last_deck; deck_index++) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if(decks[deck_index] & mask) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2009-10-26 23:08:35 -04:00
										 |  |  | 				decks_scanned++; | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				cell first_card = first_card_in_deck(deck_index); | 
					
						
							|  |  |  | 				cell last_card = last_card_in_deck(deck_index); | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 				for(cell card_index = first_card; card_index < last_card; card_index++) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					if(cards[card_index] & mask) | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2009-10-26 23:08:35 -04:00
										 |  |  | 						cards_scanned++; | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						if(end < card_start_address(card_index)) | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							start = gen->starts.find_object_containing_card(card_index - gen_start_card); | 
					
						
							| 
									
										
										
										
											2009-10-24 05:27:45 -04:00
										 |  |  | 							binary_start = start + ((object *)start)->binary_payload_start(); | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 							end = start + ((object *)start)->size(); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | scan_next_object:				if(start < card_end_address(card_index)) | 
					
						
							|  |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 							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) | 
					
						
							|  |  |  | 								{ | 
					
						
							| 
									
										
										
										
											2009-10-24 05:43:11 -04:00
										 |  |  | 									binary_start = start + ((object *)start)->binary_payload_start(); | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 									end = start + ((object *)start)->size(); | 
					
						
							|  |  |  | 									goto scan_next_object; | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 						unmarker(&cards[card_index]); | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-27 00:57:26 -04:00
										 |  |  | 						if(!start) return; | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2009-11-06 00:53:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 23:20:49 -04:00
										 |  |  | 				unmarker(&decks[deck_index]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-10-07 16:48:09 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |