5 cell code_block::owner_quot() const {
6 tagged<object> executing(owner);
7 if (!optimized_p() && executing->type() == WORD_TYPE)
8 executing = executing.as<word>()->def;
9 return executing.value();
12 /* If the code block is an unoptimized quotation, we can calculate the
13 scan offset. In all other cases -1 is returned. */
14 cell code_block::scan(factor_vm* vm, cell addr) const {
15 if (type() != code_block_unoptimized) {
16 return tag_fixnum(-1);
19 tagged<object> obj(owner);
20 if (obj.type_p(WORD_TYPE))
21 obj = obj.as<word>()->def;
22 if (!obj.type_p(QUOTATION_TYPE))
23 return tag_fixnum(-1);
25 cell ofs = offset(addr);
26 return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(), ofs));
29 cell factor_vm::compute_entry_point_address(cell obj) {
30 switch (tagged<object>(obj).type()) {
32 return untag<word>(obj)->entry_point;
34 return untag<quotation>(obj)->entry_point;
36 critical_error("Expected word or quotation", obj);
41 cell factor_vm::compute_entry_point_pic_address(word* w, cell tagged_quot) {
42 if (!to_boolean(tagged_quot) || max_pic_size == 0)
43 return w->entry_point;
45 quotation* quot = untag<quotation>(tagged_quot);
46 if (quot_compiled_p(quot))
47 return quot->entry_point;
49 return w->entry_point;
53 cell factor_vm::compute_entry_point_pic_address(cell w_) {
55 return compute_entry_point_pic_address(w.untagged(), w->pic_def);
58 cell factor_vm::compute_entry_point_pic_tail_address(cell w_) {
60 return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def);
63 cell factor_vm::code_block_owner(code_block* compiled) {
64 tagged<object> owner(compiled->owner);
66 /* Cold generic word call sites point to quotations that call the
67 inline-cache-miss and inline-cache-miss-tail primitives. */
68 if (owner.type_p(QUOTATION_TYPE)) {
69 tagged<quotation> quot(owner.as<quotation>());
70 tagged<array> elements(quot->array);
72 FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
73 FACTOR_ASSERT(array_nth(elements.untagged(), 4) ==
74 special_objects[PIC_MISS_WORD] ||
75 array_nth(elements.untagged(), 4) ==
76 special_objects[PIC_MISS_TAIL_WORD]);
78 tagged<wrapper> word_wrapper(array_nth(elements.untagged(), 0));
79 return word_wrapper->object;
81 return compiled->owner;
84 struct update_word_references_relocation_visitor {
86 bool reset_inline_caches;
88 update_word_references_relocation_visitor(factor_vm* parent,
89 bool reset_inline_caches)
90 : parent(parent), reset_inline_caches(reset_inline_caches) {}
92 void operator()(instruction_operand op) {
93 switch (op.rel_type()) {
94 case RT_ENTRY_POINT: {
95 code_block* compiled = op.load_code_block();
96 cell owner = compiled->owner;
97 if (to_boolean(owner))
98 op.store_value(parent->compute_entry_point_address(owner));
101 case RT_ENTRY_POINT_PIC: {
102 code_block* compiled = op.load_code_block();
103 if (reset_inline_caches || !compiled->pic_p()) {
104 cell owner = parent->code_block_owner(compiled);
105 if (to_boolean(owner))
106 op.store_value(parent->compute_entry_point_pic_address(owner));
110 case RT_ENTRY_POINT_PIC_TAIL: {
111 code_block* compiled = op.load_code_block();
112 if (reset_inline_caches || !compiled->pic_p()) {
113 cell owner = parent->code_block_owner(compiled);
114 if (to_boolean(owner))
115 op.store_value(parent->compute_entry_point_pic_tail_address(owner));
125 /* Relocate new code blocks completely; updating references to literals,
126 dlsyms, and words. For all other words in the code heap, we only need
127 to update references to other words, without worrying about literals
129 void factor_vm::update_word_references(code_block* compiled,
130 bool reset_inline_caches) {
131 if (code->uninitialized_p(compiled))
132 initialize_code_block(compiled);
133 /* update_word_references() is always applied to every block in
134 the code heap. Since it resets all call sites to point to
135 their canonical entry point (cold entry point for non-tail calls,
136 standard entry point for tail calls), it means that no PICs
137 are referenced after this is done. So instead of polluting
138 the code heap with dead PICs that will be freed on the next
139 GC, we add them to the free list immediately. */
140 else if (reset_inline_caches && compiled->pic_p())
141 code->free(compiled);
143 update_word_references_relocation_visitor visitor(this,
144 reset_inline_caches);
145 compiled->each_instruction_operand(visitor);
146 compiled->flush_icache();
150 /* Look up an external library symbol referenced by a compiled code block */
151 cell factor_vm::compute_dlsym_address(array* parameters, cell index) {
152 cell symbol = array_nth(parameters, index);
153 cell library = array_nth(parameters, index + 1);
155 dll* d = (to_boolean(library) ? untag<dll>(library) : NULL);
157 void* undefined_symbol = (void*)factor::undefined_symbol;
158 undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
159 if (d != NULL && !d->handle)
160 return (cell)undefined_symbol;
162 switch (tagged<object>(symbol).type()) {
163 case BYTE_ARRAY_TYPE: {
164 symbol_char* name = alien_offset(symbol);
165 void* sym = ffi_dlsym(d, name);
170 return (cell)undefined_symbol;
173 array* names = untag<array>(symbol);
174 for (cell i = 0; i < array_capacity(names); i++) {
175 symbol_char* name = alien_offset(array_nth(names, i));
176 void* sym = ffi_dlsym(d, name);
181 return (cell)undefined_symbol;
189 cell factor_vm::compute_dlsym_toc_address(array* parameters, cell index) {
190 cell symbol = array_nth(parameters, index);
191 cell library = array_nth(parameters, index + 1);
193 dll* d = (to_boolean(library) ? untag<dll>(library) : NULL);
195 void* undefined_toc = (void*)factor::undefined_symbol;
196 undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
197 if (d != NULL && !d->handle)
198 return (cell)undefined_toc;
200 switch (tagged<object>(symbol).type()) {
201 case BYTE_ARRAY_TYPE: {
202 symbol_char* name = alien_offset(symbol);
203 void* toc = ffi_dlsym_toc(d, name);
207 return (cell)undefined_toc;
210 array* names = untag<array>(symbol);
211 for (cell i = 0; i < array_capacity(names); i++) {
212 symbol_char* name = alien_offset(array_nth(names, i));
213 void* toc = ffi_dlsym_toc(d, name);
218 return (cell)undefined_toc;
226 cell factor_vm::compute_vm_address(cell arg) {
227 return (cell)this + untag_fixnum(arg);
230 cell factor_vm::lookup_external_address(relocation_type rel_type,
231 code_block *compiled,
236 return compute_dlsym_address(parameters, index);
238 return compiled->entry_point();
239 case RT_MEGAMORPHIC_CACHE_HITS:
240 return (cell)&dispatch_stats.megamorphic_cache_hits;
242 return compute_vm_address(array_nth(parameters, index));
243 case RT_CARDS_OFFSET:
245 case RT_DECKS_OFFSET:
248 case RT_EXCEPTION_HANDLER:
249 return (cell)&factor::exception_handler;
253 return compute_dlsym_toc_address(parameters, index);
255 case RT_INLINE_CACHE_MISS:
256 return (cell)&factor::inline_cache_miss;
258 return (cell)code->safepoint_page;
264 void factor_vm::store_external_address(instruction_operand op) {
266 code_block* compiled = op.compiled;
267 array* parameters = to_boolean(compiled->parameters)
268 ? untag<array>(compiled->parameters)
270 cell index = op.index;
271 relocation_type rel_type = op.rel_type();
273 cell ext_addr = lookup_external_address(rel_type,
277 if (ext_addr == (cell)-1) {
279 print_obj(ss, compiled->owner);
282 if (rel_type == RT_DLSYM || rel_type == RT_DLSYM_TOC) {
283 ss << "Bad symbol specifier in store_external_address";
284 arg = array_nth(parameters, index);
286 ss << "Bad rel type in store_external_address";
289 critical_error(ss.str().c_str(), arg);
291 op.store_value(ext_addr);
294 cell factor_vm::compute_here_address(cell arg, cell offset,
295 code_block* compiled) {
296 fixnum n = untag_fixnum(arg);
298 return compiled->entry_point() + offset + n;
300 return compiled->entry_point() - n;
303 struct initial_code_block_visitor {
308 initial_code_block_visitor(factor_vm* parent, cell literals)
309 : parent(parent), literals(literals), literal_index(0) {}
311 cell next_literal() {
312 return array_nth(untag<array>(literals), literal_index++);
315 void operator()(instruction_operand op) {
316 switch (op.rel_type()) {
318 op.store_value(next_literal());
321 op.store_value(parent->compute_entry_point_address(next_literal()));
323 case RT_ENTRY_POINT_PIC:
324 op.store_value(parent->compute_entry_point_pic_address(next_literal()));
326 case RT_ENTRY_POINT_PIC_TAIL:
328 parent->compute_entry_point_pic_tail_address(next_literal()));
331 op.store_value(parent->compute_here_address(
332 next_literal(), op.rel_offset(), op.compiled));
335 op.store_value(untag_fixnum(next_literal()));
338 parent->store_external_address(op);
344 /* Perform all fixups on a code block */
345 void factor_vm::initialize_code_block(code_block* compiled, cell literals) {
346 initial_code_block_visitor visitor(this, literals);
347 compiled->each_instruction_operand(visitor);
348 compiled->flush_icache();
350 /* next time we do a minor GC, we have to trace this code block, since
351 the newly-installed instruction operands might point to literals in
353 code->write_barrier(compiled);
356 void factor_vm::initialize_code_block(code_block* compiled) {
357 std::map<code_block*, cell>::iterator iter =
358 code->uninitialized_blocks.find(compiled);
359 initialize_code_block(compiled, iter->second);
360 code->uninitialized_blocks.erase(iter);
363 /* Fixup labels. This is done at compile time, not image load time */
364 void factor_vm::fixup_labels(array* labels, code_block* compiled) {
365 cell size = array_capacity(labels);
367 for (cell i = 0; i < size; i += 3) {
368 relocation_class rel_class =
369 (relocation_class) untag_fixnum(array_nth(labels, i));
370 cell offset = untag_fixnum(array_nth(labels, i + 1));
371 cell target = untag_fixnum(array_nth(labels, i + 2));
373 relocation_entry new_entry(RT_HERE, rel_class, offset);
375 instruction_operand op(new_entry, compiled, 0);
376 op.store_value(target + compiled->entry_point());
381 /* Allocates memory */
382 code_block* factor_vm::allot_code_block(cell size, code_block_type type) {
383 code_block* block = code->allocator->allot(size + sizeof(code_block));
385 /* If allocation failed, do a full GC and compact the code heap.
386 A full GC that occurs as a result of the data heap filling up does not
387 trigger a compaction. This setup ensures that most GCs do not compact
388 the code heap, but if the code fills up, it probably means it will be
389 fragmented after GC anyway, so its best to compact. */
391 primitive_compact_gc();
392 block = code->allocator->allot(size + sizeof(code_block));
394 /* Insufficient room even after code GC, give up */
396 std::cout << "Code heap used: " << code->allocator->occupied_space()
398 std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
399 fatal_error("Out of memory in add-compiled-block", 0);
403 block->set_type(type);
408 /* Allocates memory */
409 code_block* factor_vm::add_code_block(code_block_type type, cell code_,
410 cell labels_, cell owner_,
411 cell relocation_, cell parameters_,
413 cell frame_size_untagged) {
414 data_root<byte_array> code(code_, this);
415 data_root<object> labels(labels_, this);
416 data_root<object> owner(owner_, this);
417 data_root<byte_array> relocation(relocation_, this);
418 data_root<array> parameters(parameters_, this);
419 data_root<array> literals(literals_, this);
421 cell code_length = array_capacity(code.untagged());
422 code_block* compiled = allot_code_block(code_length, type);
424 compiled->owner = owner.value();
426 /* slight space optimization */
427 if (relocation.type() == BYTE_ARRAY_TYPE &&
428 array_capacity(relocation.untagged()) == 0)
429 compiled->relocation = false_object;
431 compiled->relocation = relocation.value();
433 if (parameters.type() == ARRAY_TYPE &&
434 array_capacity(parameters.untagged()) == 0)
435 compiled->parameters = false_object;
437 compiled->parameters = parameters.value();
440 memcpy(compiled + 1, code.untagged() + 1, code_length);
443 if (to_boolean(labels.value()))
444 fixup_labels(labels.as<array>().untagged(), compiled);
446 compiled->set_stack_frame_size(frame_size_untagged);
448 /* Once we are ready, fill in literal and word references in this code
449 block's instruction operands. In most cases this is done right after this
450 method returns, except when compiling words with the non-optimizing
451 compiler at the beginning of bootstrap */
452 this->code->uninitialized_blocks.insert(
453 std::make_pair(compiled, literals.value()));
454 this->code->all_blocks.insert((cell)compiled);
456 /* next time we do a minor GC, we have to trace this code block, since
457 the fields of the code_block struct might point into nursery or aging */
458 this->code->write_barrier(compiled);
463 /* Find the RT_DLSYM relocation nearest to the given return address. */
464 struct find_symbol_at_address_visitor {
470 find_symbol_at_address_visitor(factor_vm* parent, cell return_address)
472 return_address(return_address),
473 symbol(false_object),
474 library(false_object) {}
476 void operator()(instruction_operand op) {
477 if (op.rel_type() == RT_DLSYM && op.pointer <= return_address) {
478 code_block* compiled = op.compiled;
479 array* parameters = untag<array>(compiled->parameters);
480 cell index = op.index;
481 symbol = array_nth(parameters, index);
482 library = array_nth(parameters, index + 1);
487 /* References to undefined symbols are patched up to call this function on
488 image load. It finds the symbol and library, and throws an error. */
489 void factor_vm::undefined_symbol() {
490 cell frame = ctx->callstack_top;
491 cell return_address = *(cell*)frame;
492 code_block* compiled = code->code_block_for_address(return_address);
493 find_symbol_at_address_visitor visitor(this, return_address);
494 compiled->each_instruction_operand(visitor);
495 if (!to_boolean(visitor.symbol))
496 critical_error("Can't find RT_DLSYM at return address", return_address);
498 general_error(ERROR_UNDEFINED_SYMBOL, visitor.symbol, visitor.library);
501 void undefined_symbol() { return current_vm()->undefined_symbol(); }