VM: Refactor code_heap to Factor style
							parent
							
								
									d2fe86eb7e
								
							
						
					
					
						commit
						7f56458820
					
				
							
								
								
									
										224
									
								
								vm/code_heap.cpp
								
								
								
								
							
							
						
						
									
										224
									
								
								vm/code_heap.cpp
								
								
								
								
							|  | @ -1,95 +1,80 @@ | |||
| #include "master.hpp" | ||||
| 
 | ||||
| namespace factor | ||||
| { | ||||
| namespace factor { | ||||
| 
 | ||||
| code_heap::code_heap(cell size) | ||||
| { | ||||
| 	if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size); | ||||
| 	seg = new segment(align_page(size),true); | ||||
| 	if(!seg) fatal_error("Out of memory in code_heap constructor",size); | ||||
| code_heap::code_heap(cell size) { | ||||
|   if (size > ((u64) 1 << (sizeof(cell) * 8 - 6))) | ||||
|     fatal_error("Heap too large", size); | ||||
|   seg = new segment(align_page(size), true); | ||||
|   if (!seg) | ||||
|     fatal_error("Out of memory in code_heap constructor", size); | ||||
| 
 | ||||
|   cell start = seg->start + getpagesize() + seh_area_size; | ||||
| 
 | ||||
| 	allocator = new free_list_allocator<code_block>(seg->end - start,start); | ||||
|   allocator = new free_list_allocator<code_block>(seg->end - start, start); | ||||
| 
 | ||||
|   /* See os-windows-x86.64.cpp for seh_area usage */ | ||||
| 	safepoint_page = (void *)seg->start; | ||||
| 	seh_area = (char *)seg->start + getpagesize(); | ||||
|   safepoint_page = (void*)seg->start; | ||||
|   seh_area = (char*)seg->start + getpagesize(); | ||||
| } | ||||
| 
 | ||||
| code_heap::~code_heap() | ||||
| { | ||||
| code_heap::~code_heap() { | ||||
|   delete allocator; | ||||
|   allocator = NULL; | ||||
|   delete seg; | ||||
|   seg = NULL; | ||||
| } | ||||
| 
 | ||||
| void code_heap::write_barrier(code_block *compiled) | ||||
| { | ||||
| void code_heap::write_barrier(code_block* compiled) { | ||||
|   points_to_nursery.insert(compiled); | ||||
|   points_to_aging.insert(compiled); | ||||
| } | ||||
| 
 | ||||
| void code_heap::clear_remembered_set() | ||||
| { | ||||
| void code_heap::clear_remembered_set() { | ||||
|   points_to_nursery.clear(); | ||||
|   points_to_aging.clear(); | ||||
| } | ||||
| 
 | ||||
| bool code_heap::uninitialized_p(code_block *compiled) | ||||
| { | ||||
| bool code_heap::uninitialized_p(code_block* compiled) { | ||||
|   return uninitialized_blocks.count(compiled) > 0; | ||||
| } | ||||
| 
 | ||||
| bool code_heap::marked_p(code_block *compiled) | ||||
| { | ||||
| bool code_heap::marked_p(code_block* compiled) { | ||||
|   return allocator->state.marked_p(compiled); | ||||
| } | ||||
| 
 | ||||
| void code_heap::set_marked_p(code_block *compiled) | ||||
| { | ||||
| void code_heap::set_marked_p(code_block* compiled) { | ||||
|   allocator->state.set_marked_p(compiled); | ||||
| } | ||||
| 
 | ||||
| void code_heap::clear_mark_bits() | ||||
| { | ||||
| 	allocator->state.clear_mark_bits(); | ||||
| } | ||||
| void code_heap::clear_mark_bits() { allocator->state.clear_mark_bits(); } | ||||
| 
 | ||||
| void code_heap::free(code_block *compiled) | ||||
| { | ||||
| void code_heap::free(code_block* compiled) { | ||||
|   FACTOR_ASSERT(!uninitialized_p(compiled)); | ||||
|   points_to_nursery.erase(compiled); | ||||
|   points_to_aging.erase(compiled); | ||||
| 	all_blocks.erase((cell)compiled); | ||||
|   all_blocks.erase((cell) compiled); | ||||
|   allocator->free(compiled); | ||||
| } | ||||
| 
 | ||||
| void code_heap::flush_icache() | ||||
| { | ||||
| 	factor::flush_icache(seg->start,seg->size); | ||||
| } | ||||
| void code_heap::flush_icache() { factor::flush_icache(seg->start, seg->size); } | ||||
| 
 | ||||
| struct clear_free_blocks_from_all_blocks_iterator | ||||
| { | ||||
| 	code_heap *code; | ||||
| struct clear_free_blocks_from_all_blocks_iterator { | ||||
|   code_heap* code; | ||||
| 
 | ||||
| 	clear_free_blocks_from_all_blocks_iterator(code_heap *code) : code(code) {} | ||||
|   clear_free_blocks_from_all_blocks_iterator(code_heap* code) : code(code) {} | ||||
| 
 | ||||
| 	void operator()(code_block *free_block, cell size) { | ||||
|   void operator()(code_block* free_block, cell size) { | ||||
|     std::set<cell>::iterator erase_from = | ||||
| 			code->all_blocks.lower_bound((cell)free_block); | ||||
|         code->all_blocks.lower_bound((cell) free_block); | ||||
|     std::set<cell>::iterator erase_to = | ||||
| 			code->all_blocks.lower_bound((cell)free_block + size); | ||||
|         code->all_blocks.lower_bound((cell) free_block + size); | ||||
| 
 | ||||
|     code->all_blocks.erase(erase_from, erase_to); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| void code_heap::sweep() | ||||
| { | ||||
| void code_heap::sweep() { | ||||
|   clear_free_blocks_from_all_blocks_iterator clearer(this); | ||||
|   allocator->sweep(clearer); | ||||
| #ifdef FACTOR_DEBUG | ||||
|  | @ -98,48 +83,45 @@ void code_heap::sweep() | |||
| } | ||||
| 
 | ||||
| struct all_blocks_set_verifier { | ||||
| 	std::set<cell> *all_blocks; | ||||
|   std::set<cell>* all_blocks; | ||||
| 
 | ||||
| 	all_blocks_set_verifier(std::set<cell> *all_blocks) : all_blocks(all_blocks) {} | ||||
|   all_blocks_set_verifier(std::set<cell>* all_blocks) | ||||
|       : all_blocks(all_blocks) {} | ||||
| 
 | ||||
| 	void operator()(code_block *block, cell size) | ||||
| 	{ | ||||
| 		FACTOR_ASSERT(all_blocks->find((cell)block) != all_blocks->end()); | ||||
|   void operator()(code_block* block, cell size) { | ||||
|     FACTOR_ASSERT(all_blocks->find((cell) block) != all_blocks->end()); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| void code_heap::verify_all_blocks_set() | ||||
| { | ||||
| void code_heap::verify_all_blocks_set() { | ||||
|   all_blocks_set_verifier verifier(&all_blocks); | ||||
|   allocator->iterate(verifier); | ||||
| } | ||||
| 
 | ||||
| code_block *code_heap::code_block_for_address(cell address) | ||||
| { | ||||
| 	std::set<cell>::const_iterator blocki = | ||||
| 		all_blocks.upper_bound(address); | ||||
| code_block* code_heap::code_block_for_address(cell address) { | ||||
|   std::set<cell>::const_iterator blocki = all_blocks.upper_bound(address); | ||||
|   FACTOR_ASSERT(blocki != all_blocks.begin()); | ||||
|   --blocki; | ||||
|   code_block* found_block = (code_block*)*blocki; | ||||
| 	FACTOR_ASSERT((cell)found_block->entry_point() <= address | ||||
| 		/* XXX this isn't valid during fixup. should store the size in the map
 | ||||
| 		&& address - (cell)found_block->entry_point() < found_block->size()*/); | ||||
|   FACTOR_ASSERT((cell) found_block->entry_point() <= | ||||
|                 address /* XXX this isn't valid during fixup. should store the
 | ||||
|                                size in the map | ||||
|                               && address - (cell)found_block->entry_point() < | ||||
|                                  found_block->size()*/); | ||||
|   return found_block; | ||||
| } | ||||
| 
 | ||||
| struct all_blocks_set_inserter { | ||||
| 	code_heap *code; | ||||
|   code_heap* code; | ||||
| 
 | ||||
| 	all_blocks_set_inserter(code_heap *code) : code(code) {} | ||||
|   all_blocks_set_inserter(code_heap* code) : code(code) {} | ||||
| 
 | ||||
| 	void operator()(code_block *block, cell size) | ||||
| 	{ | ||||
| 		code->all_blocks.insert((cell)block); | ||||
|   void operator()(code_block* block, cell size) { | ||||
|     code->all_blocks.insert((cell) block); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| void code_heap::initialize_all_blocks_set() | ||||
| { | ||||
| void code_heap::initialize_all_blocks_set() { | ||||
|   all_blocks.clear(); | ||||
|   all_blocks_set_inserter inserter(this); | ||||
|   allocator->iterate(inserter); | ||||
|  | @ -149,107 +131,91 @@ void code_heap::initialize_all_blocks_set() | |||
| } | ||||
| 
 | ||||
| /* Allocate a code heap during startup */ | ||||
| void factor_vm::init_code_heap(cell size) | ||||
| { | ||||
| 	code = new code_heap(size); | ||||
| } | ||||
| void factor_vm::init_code_heap(cell size) { code = new code_heap(size); } | ||||
| 
 | ||||
| struct word_updater { | ||||
| 	factor_vm *parent; | ||||
|   factor_vm* parent; | ||||
|   bool reset_inline_caches; | ||||
| 
 | ||||
| 	word_updater(factor_vm *parent_, bool reset_inline_caches_) : | ||||
| 		parent(parent_), reset_inline_caches(reset_inline_caches_) {} | ||||
|   word_updater(factor_vm* parent_, bool reset_inline_caches_) | ||||
|       : parent(parent_), reset_inline_caches(reset_inline_caches_) {} | ||||
| 
 | ||||
| 	void operator()(code_block *compiled, cell size) | ||||
| 	{ | ||||
| 		parent->update_word_references(compiled,reset_inline_caches); | ||||
|   void operator()(code_block* compiled, cell size) { | ||||
|     parent->update_word_references(compiled, reset_inline_caches); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /* Update pointers to words referenced from all code blocks.
 | ||||
| Only needed after redefining an existing word. | ||||
| If generic words were redefined, inline caches need to be reset. */ | ||||
| void factor_vm::update_code_heap_words(bool reset_inline_caches) | ||||
| { | ||||
| 	word_updater updater(this,reset_inline_caches); | ||||
| void factor_vm::update_code_heap_words(bool reset_inline_caches) { | ||||
|   word_updater updater(this, reset_inline_caches); | ||||
|   each_code_block(updater); | ||||
| } | ||||
| 
 | ||||
| /* Fix up new words only.
 | ||||
| Fast path for compilation units that only define new words. */ | ||||
| void factor_vm::initialize_code_blocks() | ||||
| { | ||||
| 	std::map<code_block *, cell>::const_iterator iter = code->uninitialized_blocks.begin(); | ||||
| 	std::map<code_block *, cell>::const_iterator end = code->uninitialized_blocks.end(); | ||||
| void factor_vm::initialize_code_blocks() { | ||||
|   std::map<code_block*, cell>::const_iterator iter = | ||||
|       code->uninitialized_blocks.begin(); | ||||
|   std::map<code_block*, cell>::const_iterator end = | ||||
|       code->uninitialized_blocks.end(); | ||||
| 
 | ||||
| 	for(; iter != end; iter++) | ||||
| 		initialize_code_block(iter->first,iter->second); | ||||
|   for (; iter != end; iter++) | ||||
|     initialize_code_block(iter->first, iter->second); | ||||
| 
 | ||||
|   code->uninitialized_blocks.clear(); | ||||
| } | ||||
| 
 | ||||
| /* Allocates memory */ | ||||
| void factor_vm::primitive_modify_code_heap() | ||||
| { | ||||
| void factor_vm::primitive_modify_code_heap() { | ||||
|   bool reset_inline_caches = to_boolean(ctx->pop()); | ||||
|   bool update_existing_words = to_boolean(ctx->pop()); | ||||
| 	data_root<array> alist(ctx->pop(),this); | ||||
|   data_root<array> alist(ctx->pop(), this); | ||||
| 
 | ||||
|   cell count = array_capacity(alist.untagged()); | ||||
| 
 | ||||
| 	if(count == 0) | ||||
|   if (count == 0) | ||||
|     return; | ||||
| 
 | ||||
| 	for(cell i = 0; i < count; i++) | ||||
| 	{ | ||||
| 		data_root<array> pair(array_nth(alist.untagged(),i),this); | ||||
|   for (cell i = 0; i < count; i++) { | ||||
|     data_root<array> pair(array_nth(alist.untagged(), i), this); | ||||
| 
 | ||||
| 		data_root<word> word(array_nth(pair.untagged(),0),this); | ||||
| 		data_root<object> data(array_nth(pair.untagged(),1),this); | ||||
|     data_root<word> word(array_nth(pair.untagged(), 0), this); | ||||
|     data_root<object> data(array_nth(pair.untagged(), 1), this); | ||||
| 
 | ||||
| 		switch(data.type()) | ||||
| 		{ | ||||
|     switch (data.type()) { | ||||
|       case QUOTATION_TYPE: | ||||
| 			jit_compile_word(word.value(),data.value(),false); | ||||
|         jit_compile_word(word.value(), data.value(), false); | ||||
|         break; | ||||
| 		case ARRAY_TYPE: | ||||
| 			{ | ||||
| 				array *compiled_data = data.as<array>().untagged(); | ||||
| 				cell parameters = array_nth(compiled_data,0); | ||||
| 				cell literals = array_nth(compiled_data,1); | ||||
| 				cell relocation = array_nth(compiled_data,2); | ||||
| 				cell labels = array_nth(compiled_data,3); | ||||
| 				cell code = array_nth(compiled_data,4); | ||||
| 				cell frame_size = untag_fixnum(array_nth(compiled_data,5)); | ||||
|       case ARRAY_TYPE: { | ||||
|         array* compiled_data = data.as<array>().untagged(); | ||||
|         cell parameters = array_nth(compiled_data, 0); | ||||
|         cell literals = array_nth(compiled_data, 1); | ||||
|         cell relocation = array_nth(compiled_data, 2); | ||||
|         cell labels = array_nth(compiled_data, 3); | ||||
|         cell code = array_nth(compiled_data, 4); | ||||
|         cell frame_size = untag_fixnum(array_nth(compiled_data, 5)); | ||||
| 
 | ||||
| 				code_block *compiled = add_code_block( | ||||
| 					code_block_optimized, | ||||
| 					code, | ||||
| 					labels, | ||||
| 					word.value(), | ||||
| 					relocation, | ||||
| 					parameters, | ||||
| 					literals, | ||||
| 					frame_size); | ||||
|         code_block* compiled = | ||||
|             add_code_block(code_block_optimized, code, labels, word.value(), | ||||
|                            relocation, parameters, literals, frame_size); | ||||
| 
 | ||||
|         word->entry_point = compiled->entry_point(); | ||||
| 			} | ||||
| 			break; | ||||
|       } break; | ||||
|       default: | ||||
| 			critical_error("Expected a quotation or an array",data.value()); | ||||
|         critical_error("Expected a quotation or an array", data.value()); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| 	if(update_existing_words) | ||||
|   if (update_existing_words) | ||||
|     update_code_heap_words(reset_inline_caches); | ||||
|   else | ||||
|     initialize_code_blocks(); | ||||
| } | ||||
| 
 | ||||
| code_heap_room factor_vm::code_room() | ||||
| { | ||||
| code_heap_room factor_vm::code_room() { | ||||
|   code_heap_room room; | ||||
| 
 | ||||
|   room.size = code->allocator->size; | ||||
|  | @ -262,8 +228,7 @@ code_heap_room factor_vm::code_room() | |||
| } | ||||
| 
 | ||||
| /* Allocates memory */ | ||||
| void factor_vm::primitive_code_room() | ||||
| { | ||||
| void factor_vm::primitive_code_room() { | ||||
|   code_heap_room room = code_room(); | ||||
|   ctx->push(tag<byte_array>(byte_array_from_value(&room))); | ||||
| } | ||||
|  | @ -271,14 +236,12 @@ void factor_vm::primitive_code_room() | |||
| struct stack_trace_stripper { | ||||
|   explicit stack_trace_stripper() {} | ||||
| 
 | ||||
| 	void operator()(code_block *compiled, cell size) | ||||
| 	{ | ||||
|   void operator()(code_block* compiled, cell size) { | ||||
|     compiled->owner = false_object; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| void factor_vm::primitive_strip_stack_traces() | ||||
| { | ||||
| void factor_vm::primitive_strip_stack_traces() { | ||||
|   stack_trace_stripper stripper; | ||||
|   each_code_block(stripper); | ||||
| } | ||||
|  | @ -286,8 +249,7 @@ void factor_vm::primitive_strip_stack_traces() | |||
| struct code_block_accumulator { | ||||
|   std::vector<cell> objects; | ||||
| 
 | ||||
| 	void operator()(code_block *compiled, cell size) | ||||
| 	{ | ||||
|   void operator()(code_block* compiled, cell size) { | ||||
|     objects.push_back(compiled->owner); | ||||
|     objects.push_back(compiled->parameters); | ||||
|     objects.push_back(compiled->relocation); | ||||
|  | @ -301,7 +263,7 @@ struct code_block_accumulator { | |||
|        from_unsigned_cell() here. It is OK, however, to add it as | ||||
|        if it were a fixnum, and have library code shift it to the | ||||
|        left by 4. */ | ||||
| 		cell entry_point = (cell)compiled->entry_point(); | ||||
|     cell entry_point = (cell) compiled->entry_point(); | ||||
|     FACTOR_ASSERT((entry_point & (data_alignment - 1)) == 0); | ||||
|     FACTOR_ASSERT((entry_point & TAG_MASK) == FIXNUM_TYPE); | ||||
|     objects.push_back(entry_point); | ||||
|  | @ -309,17 +271,13 @@ struct code_block_accumulator { | |||
| }; | ||||
| 
 | ||||
| /* Allocates memory */ | ||||
| cell factor_vm::code_blocks() | ||||
| { | ||||
| cell factor_vm::code_blocks() { | ||||
|   code_block_accumulator accum; | ||||
|   each_code_block(accum); | ||||
|   return std_vector_to_array(accum.objects); | ||||
| } | ||||
| 
 | ||||
| /* Allocates memory */ | ||||
| void factor_vm::primitive_code_blocks() | ||||
| { | ||||
| 	ctx->push(code_blocks()); | ||||
| } | ||||
| void factor_vm::primitive_code_blocks() { ctx->push(code_blocks()); } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -1,47 +1,46 @@ | |||
| namespace factor | ||||
| { | ||||
| namespace factor { | ||||
| 
 | ||||
| #if defined(WINDOWS) && defined(FACTOR_64) | ||||
| 	const cell seh_area_size = 1024; | ||||
| const cell seh_area_size = 1024; | ||||
| #else | ||||
| 	const cell seh_area_size = 0; | ||||
| const cell seh_area_size = 0; | ||||
| #endif | ||||
| 
 | ||||
| struct code_heap { | ||||
|   /* The actual memory area */ | ||||
| 	segment *seg; | ||||
|   segment* seg; | ||||
| 
 | ||||
|   /* Memory area reserved for safepoint guard page */ | ||||
| 	void *safepoint_page; | ||||
|   void* safepoint_page; | ||||
| 
 | ||||
|   /* Memory area reserved for SEH. Only used on Windows */ | ||||
| 	char *seh_area; | ||||
|   char* seh_area; | ||||
| 
 | ||||
|   /* Memory allocator */ | ||||
| 	free_list_allocator<code_block> *allocator; | ||||
|   free_list_allocator<code_block>* allocator; | ||||
| 
 | ||||
|   std::set<cell> all_blocks; | ||||
| 
 | ||||
|   /* Keys are blocks which need to be initialized by initialize_code_block().
 | ||||
|      Values are literal tables. Literal table arrays are GC roots until the | ||||
|      time the block is initialized, after which point they are discarded. */ | ||||
| 	std::map<code_block *, cell> uninitialized_blocks; | ||||
|   std::map<code_block*, cell> uninitialized_blocks; | ||||
| 
 | ||||
|   /* Code blocks which may reference objects in the nursery */ | ||||
| 	std::set<code_block *> points_to_nursery; | ||||
|   std::set<code_block*> points_to_nursery; | ||||
| 
 | ||||
|   /* Code blocks which may reference objects in aging space or the nursery */ | ||||
| 	std::set<code_block *> points_to_aging; | ||||
|   std::set<code_block*> points_to_aging; | ||||
| 
 | ||||
|   explicit code_heap(cell size); | ||||
|   ~code_heap(); | ||||
| 	void write_barrier(code_block *compiled); | ||||
|   void write_barrier(code_block* compiled); | ||||
|   void clear_remembered_set(); | ||||
| 	bool uninitialized_p(code_block *compiled); | ||||
| 	bool marked_p(code_block *compiled); | ||||
| 	void set_marked_p(code_block *compiled); | ||||
|   bool uninitialized_p(code_block* compiled); | ||||
|   bool marked_p(code_block* compiled); | ||||
|   void set_marked_p(code_block* compiled); | ||||
|   void clear_mark_bits(); | ||||
| 	void free(code_block *compiled); | ||||
|   void free(code_block* compiled); | ||||
|   void flush_icache(); | ||||
|   void guard_safepoint(); | ||||
|   void unguard_safepoint(); | ||||
|  | @ -50,12 +49,11 @@ struct code_heap { | |||
| 
 | ||||
|   void sweep(); | ||||
| 
 | ||||
| 	code_block *code_block_for_address(cell address); | ||||
|   code_block* code_block_for_address(cell address); | ||||
| 
 | ||||
| 	bool safepoint_p(cell addr) | ||||
| 	{ | ||||
|   bool safepoint_p(cell addr) { | ||||
|     cell page_mask = ~(getpagesize() - 1); | ||||
| 		return (addr & page_mask) == (cell)safepoint_page; | ||||
|     return (addr & page_mask) == (cell) safepoint_page; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue