Top


定義場所(file name)

hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp

説明(description)

この関数は, deopt 時に interpreter が決め打ちで使っているレジスタ (L*) の値を作成するためのもの (& フレームサイズを計算するためのもの). 以下のようなレジスタ値を設定する.

名前(function name)

int AbstractInterpreter::layout_activation(methodOop method,
                                           int tempcount,
                                           int popframe_extra_args,
                                           int moncount,
                                           int caller_actual_parameters,
                                           int callee_param_count,
                                           int callee_local_count,
                                           frame* caller,
                                           frame* interpreter_frame,
                                           bool is_top_frame) {

本体部(body)

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      // Note: This calculation must exactly parallel the frame setup
      // in InterpreterGenerator::generate_fixed_frame.
      // If f!=NULL, set up the following variables:
      //   - Lmethod
      //   - Llocals
      //   - Lmonitors (to the indicated number of monitors)
      //   - Lesp (to the indicated number of temps)
      // The frame f (if not NULL) on entry is a description of the caller of the frame
      // we are about to layout. We are guaranteed that we will be able to fill in a
      // new interpreter frame as its callee (i.e. the stack space is allocated and
      // the amount was determined by an earlier call to this method with f == NULL).
      // On return f (if not NULL) while describe the interpreter frame we just layed out.

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      int monitor_size           = moncount * frame::interpreter_frame_monitor_size();
      int rounded_vm_local_words = round_to(frame::interpreter_frame_vm_local_words,WordsPerLong);

  {- -------------------------------------------
  (1) (assert)
      ---------------------------------------- -}

      assert(monitor_size == round_to(monitor_size, WordsPerLong), "must align");

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      //
      // Note: if you look closely this appears to be doing something much different
      // than generate_fixed_frame. What is happening is this. On sparc we have to do
      // this dance with interpreter_sp_adjustment because the window save area would
      // appear just below the bottom (tos) of the caller's java expression stack. Because
      // the interpreter want to have the locals completely contiguous generate_fixed_frame
      // will adjust the caller's sp for the "extra locals" (max_locals - parameter_size).
      // Now in generate_fixed_frame the extension of the caller's sp happens in the callee.
      // In this code the opposite occurs the caller adjusts it's own stack base on the callee.
      // This is mostly ok but it does cause a problem when we get to the initial frame (the oldest)
      // because the oldest frame would have adjust its callers frame and yet that frame
      // already exists and isn't part of this array of frames we are unpacking. So at first
      // glance this would seem to mess up that frame. However Deoptimization::fetch_unroll_info_helper()
      // will after it calculates all of the frame's on_stack_size()'s will then figure out the
      // amount to adjust the caller of the initial (oldest) frame and the calculation will all
      // add up. It does seem like it simpler to account for the adjustment here (and remove the
      // callee... parameters here). However this would mean that this routine would have to take
      // the caller frame as input so we could adjust its sp (and set it's interpreter_sp_adjustment)
      // and run the calling loop in the reverse order. This would also would appear to mean making
      // this code aware of what the interactions are when that initial caller fram was an osr or
      // other adapter frame. deoptimization is complicated enough and  hard enough to debug that
      // there is no sense in messing working code.
      //

  {- -------------------------------------------
  (1) size_activation_helper() を呼んで, フレームサイズを計算する.
      ---------------------------------------- -}

      int rounded_cls = round_to((callee_local_count - callee_param_count), WordsPerLong);
      assert(rounded_cls == round_to(rounded_cls, WordsPerLong), "must align");

      int raw_frame_size = size_activation_helper(rounded_cls, method->max_stack(),
                                                  monitor_size);

  {- -------------------------------------------
  (1) (interpreter_frame 引数が NULL でなければ, 以降の処理でレジスタ値の設定を行う)
      ---------------------------------------- -}

      if (interpreter_frame != NULL) {
        // The skeleton frame must already look like an interpreter frame
        // even if not fully filled out.
        assert(interpreter_frame->is_interpreted_frame(), "Must be interpreted frame");

    {- -------------------------------------------
  (1.1) レジスタ値として設定する値を計算する
        ---------------------------------------- -}

        intptr_t* fp = interpreter_frame->fp();

        JavaThread* thread = JavaThread::current();
        RegisterMap map(thread, false);
        // More verification that skeleton frame is properly walkable
        assert(fp == caller->sp(), "fp must match");

        intptr_t* montop     = fp - rounded_vm_local_words;

        // preallocate monitors (cf. __ add_monitor_to_stack)
        intptr_t* monitors = montop - monitor_size;

        // preallocate stack space
        intptr_t*  esp = monitors - 1 -
                         (tempcount * Interpreter::stackElementWords) -
                         popframe_extra_args;

        int local_words = method->max_locals() * Interpreter::stackElementWords;
        NEEDS_CLEANUP;
        intptr_t* locals;
        if (caller->is_interpreted_frame()) {
          // Can force the locals area to end up properly overlapping the top of the expression stack.
          intptr_t* Lesp_ptr = caller->interpreter_frame_tos_address() - 1;
          // Note that this computation means we replace size_of_parameters() values from the caller
          // interpreter frame's expression stack with our argument locals
          int parm_words  = caller_actual_parameters * Interpreter::stackElementWords;
          locals = Lesp_ptr + parm_words;
          int delta = local_words - parm_words;
          int computed_sp_adjustment = (delta > 0) ? round_to(delta, WordsPerLong) : 0;
          *interpreter_frame->register_addr(I5_savedSP)    = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS;
        } else {
          assert(caller->is_compiled_frame() || caller->is_entry_frame() || caller->is_ricochet_frame(), "only possible cases");
          // Don't have Lesp available; lay out locals block in the caller
          // adjacent to the register window save area.
          //
          // Compiled frames do not allocate a varargs area which is why this if
          // statement is needed.
          //
          if (caller->is_compiled_frame()) {
            locals = fp + frame::register_save_words + local_words - 1;
          } else {
            locals = fp + frame::memory_parameter_word_sp_offset + local_words - 1;
          }
          if (!caller->is_entry_frame()) {
            // Caller wants his own SP back
            int caller_frame_size = caller->cb()->frame_size();
            *interpreter_frame->register_addr(I5_savedSP) = (intptr_t)(caller->fp() - caller_frame_size) - STACK_BIAS;
          }
        }

    {- -------------------------------------------
  (1.1) (トレース出力)
        ---------------------------------------- -}

        if (TraceDeoptimization) {
          if (caller->is_entry_frame()) {
            // make sure I5_savedSP and the entry frames notion of saved SP
            // agree.  This assertion duplicate a check in entry frame code
            // but catches the failure earlier.
            assert(*caller->register_addr(Lscratch) == *interpreter_frame->register_addr(I5_savedSP),
                   "would change callers SP");
          }
          if (caller->is_entry_frame()) {
            tty->print("entry ");
          }
          if (caller->is_compiled_frame()) {
            tty->print("compiled ");
            if (caller->is_deoptimized_frame()) {
              tty->print("(deopt) ");
            }
          }
          if (caller->is_interpreted_frame()) {
            tty->print("interpreted ");
          }
          tty->print_cr("caller fp=0x%x sp=0x%x", caller->fp(), caller->sp());
          tty->print_cr("save area = 0x%x, 0x%x", caller->sp(), caller->sp() + 16);
          tty->print_cr("save area = 0x%x, 0x%x", caller->fp(), caller->fp() + 16);
          tty->print_cr("interpreter fp=0x%x sp=0x%x", interpreter_frame->fp(), interpreter_frame->sp());
          tty->print_cr("save area = 0x%x, 0x%x", interpreter_frame->sp(), interpreter_frame->sp() + 16);
          tty->print_cr("save area = 0x%x, 0x%x", interpreter_frame->fp(), interpreter_frame->fp() + 16);
          tty->print_cr("Llocals = 0x%x", locals);
          tty->print_cr("Lesp = 0x%x", esp);
          tty->print_cr("Lmonitors = 0x%x", monitors);
        }

    {- -------------------------------------------
  (1.1) (assert)
        ---------------------------------------- -}

        if (method->max_locals() > 0) {
          assert(locals < caller->sp() || locals >= (caller->sp() + 16), "locals in save area");
          assert(locals < caller->fp() || locals > (caller->fp() + 16), "locals in save area");
          assert(locals < interpreter_frame->sp() || locals > (interpreter_frame->sp() + 16), "locals in save area");
          assert(locals < interpreter_frame->fp() || locals >= (interpreter_frame->fp() + 16), "locals in save area");
        }
    #ifdef _LP64
        assert(*interpreter_frame->register_addr(I5_savedSP) & 1, "must be odd");
    #endif

    {- -------------------------------------------
  (1.1) 計算した結果をレジスタ値として設定する
        ---------------------------------------- -}

        *interpreter_frame->register_addr(Lmethod)     = (intptr_t) method;
        *interpreter_frame->register_addr(Llocals)     = (intptr_t) locals;
        *interpreter_frame->register_addr(Lmonitors)   = (intptr_t) monitors;
        *interpreter_frame->register_addr(Lesp)        = (intptr_t) esp;
        // Llast_SP will be same as SP as there is no adapter space
        *interpreter_frame->register_addr(Llast_SP)    = (intptr_t) interpreter_frame->sp() - STACK_BIAS;
        *interpreter_frame->register_addr(LcpoolCache) = (intptr_t) method->constants()->cache();
    #ifdef FAST_DISPATCH
        *interpreter_frame->register_addr(IdispatchTables) = (intptr_t) Interpreter::dispatch_table();
    #endif


    {- -------------------------------------------
  (1.1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
        ---------------------------------------- -}

    #ifdef ASSERT
        BasicObjectLock* mp = (BasicObjectLock*)monitors;

        assert(interpreter_frame->interpreter_frame_method() == method, "method matches");
        assert(interpreter_frame->interpreter_frame_local_at(9) == (intptr_t *)((intptr_t)locals - (9 * Interpreter::stackElementSize)), "locals match");
        assert(interpreter_frame->interpreter_frame_monitor_end()   == mp, "monitor_end matches");
        assert(((intptr_t *)interpreter_frame->interpreter_frame_monitor_begin()) == ((intptr_t *)mp)+monitor_size, "monitor_begin matches");
        assert(interpreter_frame->interpreter_frame_tos_address()-1 == esp, "esp matches");

        // check bounds
        intptr_t* lo = interpreter_frame->sp() + (frame::memory_parameter_word_sp_offset - 1);
        intptr_t* hi = interpreter_frame->fp() - rounded_vm_local_words;
        assert(lo < monitors && montop <= hi, "monitors in bounds");
        assert(lo <= esp && esp < monitors, "esp in bounds");
    #endif // ASSERT
      }

  {- -------------------------------------------
  (1) 計算したフレームサイズをリターン
      ---------------------------------------- -}

      return raw_frame_size;
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.