| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | #include "master.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | namespace factor { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | cell code_block::owner_quot() const { | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   if (!optimized_p() && TAG(owner) == WORD_TYPE) | 
					
						
							|  |  |  |     return untag<word>(owner)->def; | 
					
						
							|  |  |  |   return owner; | 
					
						
							| 
									
										
										
										
											2011-12-06 17:51:41 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-04 09:30:04 -05:00
										 |  |  | /* If the code block is an unoptimized quotation, we can calculate the
 | 
					
						
							|  |  |  |    scan offset. In all other cases -1 is returned. */ | 
					
						
							| 
									
										
										
										
											2015-01-05 08:04:12 -05:00
										 |  |  | cell code_block::scan(factor_vm* vm, cell addr) const { | 
					
						
							| 
									
										
										
										
											2015-01-04 09:30:04 -05:00
										 |  |  |   if (type() != code_block_unoptimized) { | 
					
						
							|  |  |  |     return tag_fixnum(-1); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-04 09:30:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   cell ptr = owner; | 
					
						
							|  |  |  |   if (TAG(ptr) == WORD_TYPE) | 
					
						
							|  |  |  |     ptr = untag<word>(ptr)->def; | 
					
						
							|  |  |  |   if (TAG(ptr) != QUOTATION_TYPE) | 
					
						
							| 
									
										
										
										
											2015-01-04 09:30:04 -05:00
										 |  |  |     return tag_fixnum(-1); | 
					
						
							| 
									
										
										
										
											2015-01-06 11:35:44 -05:00
										 |  |  |   cell ofs = offset(addr); | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   return tag_fixnum(vm->quot_code_offset_to_scan(ptr, ofs)); | 
					
						
							| 
									
										
										
										
											2011-12-02 12:11:34 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | cell factor_vm::compute_entry_point_address(cell obj) { | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   switch (TAG(obj)) { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case WORD_TYPE: | 
					
						
							| 
									
										
										
										
											2015-01-07 05:51:19 -05:00
										 |  |  |       return untag<word>(obj)->entry_point; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case QUOTATION_TYPE: | 
					
						
							| 
									
										
										
										
											2015-01-07 05:51:19 -05:00
										 |  |  |       return untag<quotation>(obj)->entry_point; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     default: | 
					
						
							|  |  |  |       critical_error("Expected word or quotation", obj); | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-05-07 15:26:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | cell factor_vm::compute_entry_point_pic_address(word* w, cell tagged_quot) { | 
					
						
							|  |  |  |   if (!to_boolean(tagged_quot) || max_pic_size == 0) | 
					
						
							| 
									
										
										
										
											2015-01-07 05:51:19 -05:00
										 |  |  |     return w->entry_point; | 
					
						
							| 
									
										
										
										
											2015-08-14 16:31:04 -04:00
										 |  |  |   quotation* q = untag<quotation>(tagged_quot); | 
					
						
							|  |  |  |   if (quotation_compiled_p(q)) | 
					
						
							|  |  |  |     return q->entry_point; | 
					
						
							|  |  |  |   return w->entry_point; | 
					
						
							| 
									
										
										
										
											2009-05-07 15:26:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | cell factor_vm::compute_entry_point_pic_address(cell w_) { | 
					
						
							|  |  |  |   tagged<word> w(w_); | 
					
						
							|  |  |  |   return compute_entry_point_pic_address(w.untagged(), w->pic_def); | 
					
						
							| 
									
										
										
										
											2009-11-27 18:05:08 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | cell factor_vm::compute_entry_point_pic_tail_address(cell w_) { | 
					
						
							|  |  |  |   tagged<word> w(w_); | 
					
						
							|  |  |  |   return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def); | 
					
						
							| 
									
										
										
										
											2009-05-07 15:26:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | cell factor_vm::code_block_owner(code_block* compiled) { | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   cell owner = compiled->owner; | 
					
						
							| 
									
										
										
										
											2009-11-25 18:20:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   /* Cold generic word call sites point to quotations that call the
 | 
					
						
							|  |  |  |      inline-cache-miss and inline-cache-miss-tail primitives. */ | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   if (TAG(owner) != QUOTATION_TYPE) | 
					
						
							|  |  |  |     return owner; | 
					
						
							| 
									
										
										
										
											2013-05-12 23:44:32 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   quotation* quot = untag<quotation>(owner); | 
					
						
							|  |  |  |   array* elements = untag<array>(quot->array); | 
					
						
							| 
									
										
										
										
											2013-05-12 23:44:32 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 20:27:22 -05:00
										 |  |  |   FACTOR_ASSERT(array_capacity(elements) == 5); | 
					
						
							|  |  |  |   FACTOR_ASSERT(array_nth(elements, 4) == special_objects[PIC_MISS_WORD] || | 
					
						
							|  |  |  |                 array_nth(elements, 4) == special_objects[PIC_MISS_TAIL_WORD]); | 
					
						
							|  |  |  |   wrapper* wrap = untag<wrapper>(array_nth(elements, 0)); | 
					
						
							|  |  |  |   return wrap->object; | 
					
						
							| 
									
										
										
										
											2009-11-25 18:20:48 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-28 20:48:26 -05:00
										 |  |  | struct update_word_references_relocation_visitor { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   factor_vm* parent; | 
					
						
							|  |  |  |   bool reset_inline_caches; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 23:20:43 -04:00
										 |  |  |   update_word_references_relocation_visitor(factor_vm* parent, | 
					
						
							|  |  |  |                                             bool reset_inline_caches) | 
					
						
							|  |  |  |       : parent(parent), reset_inline_caches(reset_inline_caches) {} | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void operator()(instruction_operand op) { | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  |     code_block* compiled = op.load_code_block(); | 
					
						
							| 
									
										
										
										
											2015-12-11 22:02:53 -05:00
										 |  |  |     switch (op.rel.type()) { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_ENTRY_POINT: { | 
					
						
							|  |  |  |         cell owner = compiled->owner; | 
					
						
							|  |  |  |         if (to_boolean(owner)) | 
					
						
							|  |  |  |           op.store_value(parent->compute_entry_point_address(owner)); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case RT_ENTRY_POINT_PIC: { | 
					
						
							|  |  |  |         if (reset_inline_caches || !compiled->pic_p()) { | 
					
						
							|  |  |  |           cell owner = parent->code_block_owner(compiled); | 
					
						
							|  |  |  |           if (to_boolean(owner)) | 
					
						
							|  |  |  |             op.store_value(parent->compute_entry_point_pic_address(owner)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case RT_ENTRY_POINT_PIC_TAIL: { | 
					
						
							|  |  |  |         if (reset_inline_caches || !compiled->pic_p()) { | 
					
						
							|  |  |  |           cell owner = parent->code_block_owner(compiled); | 
					
						
							|  |  |  |           if (to_boolean(owner)) | 
					
						
							|  |  |  |             op.store_value(parent->compute_entry_point_pic_tail_address(owner)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-11-25 18:20:48 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Relocate new code blocks completely; updating references to literals,
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |    dlsyms, and words. For all other words in the code heap, we only need | 
					
						
							|  |  |  |    to update references to other words, without worrying about literals | 
					
						
							|  |  |  |    or dlsyms. */ | 
					
						
							|  |  |  | void factor_vm::update_word_references(code_block* compiled, | 
					
						
							|  |  |  |                                        bool reset_inline_caches) { | 
					
						
							|  |  |  |   if (code->uninitialized_p(compiled)) | 
					
						
							|  |  |  |     initialize_code_block(compiled); | 
					
						
							|  |  |  |   /* update_word_references() is always applied to every block in
 | 
					
						
							|  |  |  |      the code heap. Since it resets all call sites to point to | 
					
						
							|  |  |  |      their canonical entry point (cold entry point for non-tail calls, | 
					
						
							|  |  |  |      standard entry point for tail calls), it means that no PICs | 
					
						
							|  |  |  |      are referenced after this is done. So instead of polluting | 
					
						
							|  |  |  |      the code heap with dead PICs that will be freed on the next | 
					
						
							|  |  |  |      GC, we add them to the free list immediately. */ | 
					
						
							|  |  |  |   else if (reset_inline_caches && compiled->pic_p()) | 
					
						
							|  |  |  |     code->free(compiled); | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     update_word_references_relocation_visitor visitor(this, | 
					
						
							|  |  |  |                                                       reset_inline_caches); | 
					
						
							|  |  |  |     compiled->each_instruction_operand(visitor); | 
					
						
							|  |  |  |     compiled->flush_icache(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-11-25 18:20:48 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-18 03:47:11 -04:00
										 |  |  | /* Look up an external library symbol referenced by a compiled code
 | 
					
						
							|  |  |  |    block */ | 
					
						
							|  |  |  | cell factor_vm::compute_dlsym_address(array* parameters, | 
					
						
							|  |  |  |                                       cell index, | 
					
						
							|  |  |  |                                       bool toc) { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   cell symbol = array_nth(parameters, index); | 
					
						
							|  |  |  |   cell library = array_nth(parameters, index + 1); | 
					
						
							| 
									
										
										
										
											2015-08-18 03:47:11 -04:00
										 |  |  |   dll* d = to_boolean(library) ? untag<dll>(library) : NULL; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-18 03:47:11 -04:00
										 |  |  |   cell undef = (cell)factor::undefined_symbol; | 
					
						
							|  |  |  |   undef = toc ? FUNCTION_TOC_POINTER(undef) : FUNCTION_CODE_POINTER(undef); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   if (d != NULL && !d->handle) | 
					
						
							| 
									
										
										
										
											2015-08-18 03:47:11 -04:00
										 |  |  |     return undef; | 
					
						
							| 
									
										
										
										
											2009-12-02 02:09:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 08:40:32 -04:00
										 |  |  |   FACTOR_ASSERT(TAG(symbol) == BYTE_ARRAY_TYPE); | 
					
						
							|  |  |  |   symbol_char* name = alien_offset(symbol); | 
					
						
							|  |  |  |   cell sym = ffi_dlsym_raw(d, name); | 
					
						
							|  |  |  |   sym = toc ? FUNCTION_TOC_POINTER(sym) : FUNCTION_CODE_POINTER(sym); | 
					
						
							|  |  |  |   return sym ? sym : undef; | 
					
						
							| 
									
										
										
										
											2011-05-20 18:11:50 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  | cell factor_vm::lookup_external_address(relocation_type rel_type, | 
					
						
							|  |  |  |                                         code_block *compiled, | 
					
						
							|  |  |  |                                         array* parameters, | 
					
						
							|  |  |  |                                         cell index) { | 
					
						
							|  |  |  |   switch (rel_type) { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_DLSYM: | 
					
						
							| 
									
										
										
										
											2015-08-18 03:47:11 -04:00
										 |  |  |       return compute_dlsym_address(parameters, index, false); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_THIS: | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       return compiled->entry_point(); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_MEGAMORPHIC_CACHE_HITS: | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       return (cell)&dispatch_stats.megamorphic_cache_hits; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_VM: | 
					
						
							| 
									
										
										
										
											2015-12-13 02:20:20 -05:00
										 |  |  |       return (cell)this + untag_fixnum(array_nth(parameters, index)); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_CARDS_OFFSET: | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       return cards_offset; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_DECKS_OFFSET: | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       return decks_offset; | 
					
						
							| 
									
										
										
										
											2011-05-20 18:11:50 -04:00
										 |  |  | #ifdef FACTOR_PPC
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_DLSYM_TOC: | 
					
						
							| 
									
										
										
										
											2015-08-18 03:47:11 -04:00
										 |  |  |       return compute_dlsym_address(parameters, index, true); | 
					
						
							| 
									
										
										
										
											2010-04-03 20:24:33 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_INLINE_CACHE_MISS: | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       return (cell)&factor::inline_cache_miss; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     case RT_SAFEPOINT: | 
					
						
							| 
									
										
										
										
											2015-08-24 02:47:36 -04:00
										 |  |  |       return code->safepoint_page; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     default: | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       return -1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 19:14:38 -04:00
										 |  |  | cell factor_vm::compute_external_address(instruction_operand op) { | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |   code_block* compiled = op.compiled; | 
					
						
							|  |  |  |   array* parameters = to_boolean(compiled->parameters) | 
					
						
							|  |  |  |       ? untag<array>(compiled->parameters) | 
					
						
							|  |  |  |       : NULL; | 
					
						
							| 
									
										
										
										
											2015-07-30 19:14:38 -04:00
										 |  |  |   cell idx = op.index; | 
					
						
							| 
									
										
										
										
											2015-12-11 22:02:53 -05:00
										 |  |  |   relocation_type rel_type = op.rel.type(); | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 19:14:38 -04:00
										 |  |  |   cell ext_addr = lookup_external_address(rel_type, compiled, parameters, idx); | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |   if (ext_addr == (cell)-1) { | 
					
						
							|  |  |  |     ostringstream ss; | 
					
						
							|  |  |  |     print_obj(ss, compiled->owner); | 
					
						
							|  |  |  |     ss << ": "; | 
					
						
							|  |  |  |     cell arg; | 
					
						
							|  |  |  |     if (rel_type == RT_DLSYM || rel_type == RT_DLSYM_TOC) { | 
					
						
							| 
									
										
										
										
											2015-07-30 19:14:38 -04:00
										 |  |  |       ss << "Bad symbol specifier in compute_external_address"; | 
					
						
							|  |  |  |       arg = array_nth(parameters, idx); | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2015-07-30 19:14:38 -04:00
										 |  |  |       ss << "Bad rel type in compute_external_address"; | 
					
						
							| 
									
										
										
										
											2015-01-28 09:40:12 -05:00
										 |  |  |       arg = rel_type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     critical_error(ss.str().c_str(), arg); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-07-30 19:14:38 -04:00
										 |  |  |   return ext_addr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | cell factor_vm::compute_here_address(cell arg, cell offset, | 
					
						
							|  |  |  |                                      code_block* compiled) { | 
					
						
							|  |  |  |   fixnum n = untag_fixnum(arg); | 
					
						
							|  |  |  |   if (n >= 0) | 
					
						
							| 
									
										
										
										
											2015-01-07 05:51:19 -05:00
										 |  |  |     return compiled->entry_point() + offset + n; | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |   return compiled->entry_point() - n; | 
					
						
							| 
									
										
										
										
											2009-12-02 05:55:48 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 02:09:08 -05:00
										 |  |  | struct initial_code_block_visitor { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   factor_vm* parent; | 
					
						
							|  |  |  |   cell literals; | 
					
						
							|  |  |  |   cell literal_index; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 23:20:43 -04:00
										 |  |  |   initial_code_block_visitor(factor_vm* parent, cell literals) | 
					
						
							|  |  |  |       : parent(parent), literals(literals), literal_index(0) {} | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   cell next_literal() { | 
					
						
							|  |  |  |     return array_nth(untag<array>(literals), literal_index++); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |   fixnum compute_operand_value(instruction_operand op) { | 
					
						
							| 
									
										
										
										
											2015-12-11 22:02:53 -05:00
										 |  |  |     switch (op.rel.type()) { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_LITERAL: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return next_literal(); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_ENTRY_POINT: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return parent->compute_entry_point_address(next_literal()); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_ENTRY_POINT_PIC: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return parent->compute_entry_point_pic_address(next_literal()); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_ENTRY_POINT_PIC_TAIL: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return parent->compute_entry_point_pic_tail_address(next_literal()); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_HERE: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return parent->compute_here_address( | 
					
						
							| 
									
										
										
										
											2015-12-11 22:02:53 -05:00
										 |  |  |             next_literal(), op.rel.offset(), op.compiled); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       case RT_UNTAGGED: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return untag_fixnum(next_literal()); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       default: | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  |         return parent->compute_external_address(op); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-07-30 19:34:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void operator()(instruction_operand op) { | 
					
						
							|  |  |  |     op.store_value(compute_operand_value(op)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-10-03 09:47:05 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | /* Perform all fixups on a code block */ | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | void factor_vm::initialize_code_block(code_block* compiled, cell literals) { | 
					
						
							|  |  |  |   initial_code_block_visitor visitor(this, literals); | 
					
						
							|  |  |  |   compiled->each_instruction_operand(visitor); | 
					
						
							|  |  |  |   compiled->flush_icache(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* next time we do a minor GC, we have to trace this code block, since
 | 
					
						
							|  |  |  |      the newly-installed instruction operands might point to literals in | 
					
						
							|  |  |  |      nursery or aging */ | 
					
						
							|  |  |  |   code->write_barrier(compiled); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | void factor_vm::initialize_code_block(code_block* compiled) { | 
					
						
							|  |  |  |   std::map<code_block*, cell>::iterator iter = | 
					
						
							|  |  |  |       code->uninitialized_blocks.find(compiled); | 
					
						
							|  |  |  |   initialize_code_block(compiled, iter->second); | 
					
						
							|  |  |  |   code->uninitialized_blocks.erase(iter); | 
					
						
							| 
									
										
										
										
											2010-02-01 08:49:05 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | /* Fixup labels. This is done at compile time, not image load time */ | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | void factor_vm::fixup_labels(array* labels, code_block* compiled) { | 
					
						
							|  |  |  |   cell size = array_capacity(labels); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   for (cell i = 0; i < size; i += 3) { | 
					
						
							|  |  |  |     relocation_class rel_class = | 
					
						
							|  |  |  |         (relocation_class) untag_fixnum(array_nth(labels, i)); | 
					
						
							|  |  |  |     cell offset = untag_fixnum(array_nth(labels, i + 1)); | 
					
						
							|  |  |  |     cell target = untag_fixnum(array_nth(labels, i + 2)); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     relocation_entry new_entry(RT_HERE, rel_class, offset); | 
					
						
							| 
									
										
										
										
											2009-12-02 01:48:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |     instruction_operand op(new_entry, compiled, 0); | 
					
						
							| 
									
										
										
										
											2015-01-07 05:51:19 -05:00
										 |  |  |     op.store_value(target + compiled->entry_point()); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Might GC */ | 
					
						
							| 
									
										
										
										
											2013-03-25 17:41:18 -04:00
										 |  |  | /* Allocates memory */ | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | code_block* factor_vm::allot_code_block(cell size, code_block_type type) { | 
					
						
							|  |  |  |   code_block* block = code->allocator->allot(size + sizeof(code_block)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If allocation failed, do a full GC and compact the code heap.
 | 
					
						
							|  |  |  |      A full GC that occurs as a result of the data heap filling up does not | 
					
						
							|  |  |  |      trigger a compaction. This setup ensures that most GCs do not compact | 
					
						
							|  |  |  |      the code heap, but if the code fills up, it probably means it will be | 
					
						
							|  |  |  |      fragmented after GC anyway, so its best to compact. */ | 
					
						
							|  |  |  |   if (block == NULL) { | 
					
						
							|  |  |  |     primitive_compact_gc(); | 
					
						
							|  |  |  |     block = code->allocator->allot(size + sizeof(code_block)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Insufficient room even after code GC, give up */ | 
					
						
							|  |  |  |     if (block == NULL) { | 
					
						
							|  |  |  |       std::cout << "Code heap used: " << code->allocator->occupied_space() | 
					
						
							|  |  |  |                 << "\n"; | 
					
						
							|  |  |  |       std::cout << "Code heap free: " << code->allocator->free_space() << "\n"; | 
					
						
							|  |  |  |       fatal_error("Out of memory in add-compiled-block", 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   block->set_type(type); | 
					
						
							|  |  |  |   return block; | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Might GC */ | 
					
						
							| 
									
										
										
										
											2013-03-25 17:41:18 -04:00
										 |  |  | /* Allocates memory */ | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | code_block* factor_vm::add_code_block(code_block_type type, cell code_, | 
					
						
							|  |  |  |                                       cell labels_, cell owner_, | 
					
						
							|  |  |  |                                       cell relocation_, cell parameters_, | 
					
						
							|  |  |  |                                       cell literals_, | 
					
						
							|  |  |  |                                       cell frame_size_untagged) { | 
					
						
							|  |  |  |   data_root<byte_array> code(code_, this); | 
					
						
							|  |  |  |   data_root<object> labels(labels_, this); | 
					
						
							|  |  |  |   data_root<object> owner(owner_, this); | 
					
						
							|  |  |  |   data_root<byte_array> relocation(relocation_, this); | 
					
						
							|  |  |  |   data_root<array> parameters(parameters_, this); | 
					
						
							|  |  |  |   data_root<array> literals(literals_, this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cell code_length = array_capacity(code.untagged()); | 
					
						
							|  |  |  |   code_block* compiled = allot_code_block(code_length, type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   compiled->owner = owner.value(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* slight space optimization */ | 
					
						
							|  |  |  |   if (relocation.type() == BYTE_ARRAY_TYPE && | 
					
						
							|  |  |  |       array_capacity(relocation.untagged()) == 0) | 
					
						
							|  |  |  |     compiled->relocation = false_object; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     compiled->relocation = relocation.value(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (parameters.type() == ARRAY_TYPE && | 
					
						
							|  |  |  |       array_capacity(parameters.untagged()) == 0) | 
					
						
							|  |  |  |     compiled->parameters = false_object; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     compiled->parameters = parameters.value(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* code */ | 
					
						
							|  |  |  |   memcpy(compiled + 1, code.untagged() + 1, code_length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* fixup labels */ | 
					
						
							|  |  |  |   if (to_boolean(labels.value())) | 
					
						
							|  |  |  |     fixup_labels(labels.as<array>().untagged(), compiled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   compiled->set_stack_frame_size(frame_size_untagged); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Once we are ready, fill in literal and word references in this code
 | 
					
						
							|  |  |  |      block's instruction operands. In most cases this is done right after this | 
					
						
							|  |  |  |      method returns, except when compiling words with the non-optimizing | 
					
						
							|  |  |  |      compiler at the beginning of bootstrap */ | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   this->code->uninitialized_blocks.insert( | 
					
						
							|  |  |  |       std::make_pair(compiled, literals.value())); | 
					
						
							|  |  |  |   this->code->all_blocks.insert((cell)compiled); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* next time we do a minor GC, we have to trace this code block, since
 | 
					
						
							|  |  |  |      the fields of the code_block struct might point into nursery or aging */ | 
					
						
							|  |  |  |   this->code->write_barrier(compiled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return compiled; | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  | /* References to undefined symbols are patched up to call this function on
 | 
					
						
							|  |  |  |    image load. It finds the symbol and library, and throws an error. */ | 
					
						
							|  |  |  | void factor_vm::undefined_symbol() { | 
					
						
							|  |  |  |   cell frame = ctx->callstack_top; | 
					
						
							|  |  |  |   cell return_address = *(cell*)frame; | 
					
						
							|  |  |  |   code_block* compiled = code->code_block_for_address(return_address); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  |   /* Find the RT_DLSYM relocation nearest to the given return
 | 
					
						
							|  |  |  |      address. */ | 
					
						
							|  |  |  |   cell symbol = false_object; | 
					
						
							|  |  |  |   cell library = false_object; | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  |   auto find_symbol_at_address_visitor = [&](instruction_operand op) { | 
					
						
							| 
									
										
										
										
											2015-12-11 22:02:53 -05:00
										 |  |  |     if (op.rel.type() == RT_DLSYM && op.pointer <= return_address) { | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |       array* parameters = untag<array>(compiled->parameters); | 
					
						
							|  |  |  |       cell index = op.index; | 
					
						
							|  |  |  |       symbol = array_nth(parameters, index); | 
					
						
							|  |  |  |       library = array_nth(parameters, index + 1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  |   }; | 
					
						
							|  |  |  |   compiled->each_instruction_operand(find_symbol_at_address_visitor); | 
					
						
							| 
									
										
										
										
											2011-09-12 03:56:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  |   if (!to_boolean(symbol)) | 
					
						
							| 
									
										
										
										
											2015-01-05 06:59:54 -05:00
										 |  |  |     critical_error("Can't find RT_DLSYM at return address", return_address); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:50:21 -04:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2015-07-06 13:12:21 -04:00
										 |  |  |     general_error(ERROR_UNDEFINED_SYMBOL, symbol, library); | 
					
						
							| 
									
										
										
										
											2011-09-12 03:56:24 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 14:13:52 -04:00
										 |  |  | void undefined_symbol() { | 
					
						
							|  |  |  |   return current_vm()->undefined_symbol(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | } |