// Allocates memory void quotation_jit::emit_mega_cache_lookup(cell methods_, fixnum index, cell cache_) { data_root<array> methods(methods_, parent); data_root<array> cache(cache_, parent); // Load the object from the datastack. emit_with_literal(parent->special_objects[PIC_LOAD], tag_fixnum(-index * sizeof(cell))); // Do a cache lookup. emit_with_literal(parent->special_objects[MEGA_LOOKUP], cache.value()); // If we end up here, the cache missed. emit(parent->special_objects[JIT_PROLOG]); // Push index, method table and cache on the stack. push(methods.value()); push(tag_fixnum(index)); push(cache.value()); word_call(parent->special_objects[MEGA_MISS_WORD]); // Now the new method has been stored into the cache, and its on // the stack. emit(parent->special_objects[JIT_EPILOG]); emit(parent->special_objects[JIT_EXECUTE]); }
void inline_cache_jit::emit_check_and_jump(cell ic_type, cell i, cell klass, cell method) { // Class equal? cell check_type = PIC_CHECK_TAG; if (TAG(klass) != FIXNUM_TYPE) check_type = PIC_CHECK_TUPLE; // The tag check can be skipped if it is the first one and we are // checking for the fixnum type which is 0. That is because the // AND instruction in the PIC_TAG template already sets the zero // flag. if (!(i == 0 && ic_type == PIC_TAG && klass == 0)) { emit_with_literal(parent->special_objects[check_type], klass); } // Yes? Jump to method emit_with_literal(parent->special_objects[PIC_HIT], method); }
// index: 0 = top of stack, 1 = item underneath, etc // cache_entries: array of class/method pairs // Allocates memory void inline_cache_jit::emit_inline_cache(fixnum index, cell generic_word_, cell methods_, cell cache_entries_, bool tail_call_p) { data_root<word> generic_word(generic_word_, parent); data_root<array> methods(methods_, parent); data_root<array> cache_entries(cache_entries_, parent); cell ic_type = determine_inline_cache_type(cache_entries.untagged()); parent->update_pic_count(ic_type); // Generate machine code to determine the object's class. emit_with_literal(parent->special_objects[PIC_LOAD], tag_fixnum(-index * sizeof(cell))); // Put the tag of the object, or class of the tuple in a register. emit(parent->special_objects[ic_type]); // Generate machine code to check, in turn, if the class is one of the cached // entries. for (cell i = 0; i < array_capacity(cache_entries.untagged()); i += 2) { cell klass = array_nth(cache_entries.untagged(), i); cell method = array_nth(cache_entries.untagged(), i + 1); emit_check_and_jump(ic_type, i, klass, method); } // If none of the above conditionals tested true, then execution "falls // through" to here. // A stack frame is set up, since the inline-cache-miss sub-primitive // makes a subroutine call to the VM. emit(parent->special_objects[JIT_PROLOG]); // The inline-cache-miss sub-primitive call receives enough information to // reconstruct the PIC with the new entry. push(generic_word.value()); push(methods.value()); push(tag_fixnum(index)); push(cache_entries.value()); emit_subprimitive( parent->special_objects[tail_call_p ? PIC_MISS_TAIL_WORD : PIC_MISS_WORD], true, // tail_call_p true); // stack_frame_p }
/* Allocates memory */ void word_call(cell word) { emit_with_literal(parent->special_objects[JIT_WORD_CALL], word); }
/* Allocates memory */ void push(cell literal) { emit_with_literal(parent->special_objects[JIT_PUSH_IMMEDIATE], literal); }
/* Allocates memory (parameter(), literal(), emit_epilog, emit_with_literal)*/ void quotation_jit::iterate_quotation() { bool no_non_safepoint_words = no_non_safepoint_words_p(); set_position(0); if (no_non_safepoint_words) { emit(parent->special_objects[JIT_SAFEPOINT]); emit(parent->special_objects[JIT_PROLOG]); } cell length = array_capacity(elements.untagged()); bool tail_call = false; for (cell i = 0; i < length; i++) { set_position(i); data_root<object> obj(array_nth(elements.untagged(), i), parent); switch (obj.type()) { case WORD_TYPE: /* Sub-primitives */ if (to_boolean(obj.as<word>()->subprimitive)) { tail_call = emit_subprimitive(obj.value(), /* word */ i == length - 1, /* tail_call_p */ no_non_safepoint_words); /* stack_frame_p */ } /* Everything else */ else if (i == length - 1) { emit_epilog(no_non_safepoint_words); tail_call = true; word_jump(obj.value()); } else word_call(obj.value()); break; case WRAPPER_TYPE: push(obj.as<wrapper>()->object); break; case BYTE_ARRAY_TYPE: /* Primitive calls */ if (primitive_call_p(i, length)) { /* On x86-64 and PowerPC, the VM pointer is stored in a register; on other platforms, the RT_VM relocation is used and it needs an offset parameter */ #ifdef FACTOR_X86 parameter(tag_fixnum(0)); #endif parameter(obj.value()); parameter(false_object); #ifdef FACTOR_PPC_TOC parameter(obj.value()); parameter(false_object); #endif emit(parent->special_objects[JIT_PRIMITIVE]); i++; } else push(obj.value()); break; case QUOTATION_TYPE: /* 'if' preceded by two literal quotations (this is why if and ? are mutually recursive in the library, but both still work) */ if (fast_if_p(i, length)) { emit_epilog(no_non_safepoint_words); tail_call = true; emit_quotation(array_nth(elements.untagged(), i)); emit_quotation(array_nth(elements.untagged(), i + 1)); emit(parent->special_objects[JIT_IF]); i += 2; } /* dip */ else if (fast_dip_p(i, length)) { emit_quotation(obj.value()); emit(parent->special_objects[JIT_DIP]); i++; } /* 2dip */ else if (fast_2dip_p(i, length)) { emit_quotation(obj.value()); emit(parent->special_objects[JIT_2DIP]); i++; } /* 3dip */ else if (fast_3dip_p(i, length)) { emit_quotation(obj.value()); emit(parent->special_objects[JIT_3DIP]); i++; } else push(obj.value()); break; case ARRAY_TYPE: /* Method dispatch */ if (mega_lookup_p(i, length)) { fixnum index = untag_fixnum(array_nth(elements.untagged(), i + 1)); /* Load the object from the datastack, then remove our stack frame. */ emit_with_literal(parent->special_objects[PIC_LOAD], tag_fixnum(-index * sizeof(cell))); emit_epilog(no_non_safepoint_words); tail_call = true; emit_mega_cache_lookup(array_nth(elements.untagged(), i), index, array_nth(elements.untagged(), i + 2)); i += 3; } /* Non-optimizing compiler ignores declarations */ else if (declare_p(i, length)) i++; else push(obj.value()); break; default: push(obj.value()); break; } } if (!tail_call) { set_position(length); emit_epilog(no_non_safepoint_words); emit(parent->special_objects[JIT_RETURN]); } }