Example #1
0
// 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]);
}
Example #2
0
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);
}
Example #3
0
// 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
}
Example #4
0
 /* Allocates memory */
 void word_call(cell word) {
   emit_with_literal(parent->special_objects[JIT_WORD_CALL], word);
 }
Example #5
0
 /* Allocates memory */
 void push(cell literal) {
   emit_with_literal(parent->special_objects[JIT_PUSH_IMMEDIATE], literal);
 }
Example #6
0
/* 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]);
  }
}