view src/cpu/zero/vm/cppInterpreter_zero.cpp @ 5762:b30cced39597

generalized functionality for finding classes based on searching for patterns in source code and moved it from commands.py to mx.py used above functionality to find classes manually excluded from JaCoCo processing
author Doug Simon <doug.simon@oracle.com>
date Wed, 04 Jul 2012 21:56:48 +0200
parents 38fa55e5e792
children 7f410b6ea66c
line wrap: on
line source

/*
 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/cppInterpreter.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "oops/arrayOop.hpp"
#include "oops/methodDataOop.hpp"
#include "oops/methodOop.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/arguments.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/timer.hpp"
#include "runtime/vframeArray.hpp"
#include "stack_zero.inline.hpp"
#include "utilities/debug.hpp"
#ifdef SHARK
#include "shark/shark_globals.hpp"
#endif

#ifdef CC_INTERP

#define fixup_after_potential_safepoint()       \
  method = istate->method()

#define CALL_VM_NOCHECK_NOFIX(func)             \
  thread->set_last_Java_frame();                \
  func;                                         \
  thread->reset_last_Java_frame();

#define CALL_VM_NOCHECK(func)                   \
  CALL_VM_NOCHECK_NOFIX(func)                   \
  fixup_after_potential_safepoint()

int CppInterpreter::normal_entry(methodOop method, intptr_t UNUSED, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;

  // Allocate and initialize our frame.
  InterpreterFrame *frame = InterpreterFrame::build(method, CHECK_0);
  thread->push_zero_frame(frame);

  // Execute those bytecodes!
  main_loop(0, THREAD);

  // No deoptimized frames on the stack
  return 0;
}

void CppInterpreter::main_loop(int recurse, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();

  // If we are entering from a deopt we may need to call
  // ourself a few times in order to get to our frame.
  if (recurse)
    main_loop(recurse - 1, THREAD);

  InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame();
  interpreterState istate = frame->interpreter_state();
  methodOop method = istate->method();

  intptr_t *result = NULL;
  int result_slots = 0;

  while (true) {
    // We can set up the frame anchor with everything we want at
    // this point as we are thread_in_Java and no safepoints can
    // occur until we go to vm mode.  We do have to clear flags
    // on return from vm but that is it.
    thread->set_last_Java_frame();

    // Call the interpreter
    if (JvmtiExport::can_post_interpreter_events())
      BytecodeInterpreter::runWithChecks(istate);
    else
      BytecodeInterpreter::run(istate);
    fixup_after_potential_safepoint();

    // Clear the frame anchor
    thread->reset_last_Java_frame();

    // Examine the message from the interpreter to decide what to do
    if (istate->msg() == BytecodeInterpreter::call_method) {
      methodOop callee = istate->callee();

      // Trim back the stack to put the parameters at the top
      stack->set_sp(istate->stack() + 1);

      // Make the call
      Interpreter::invoke_method(callee, istate->callee_entry_point(), THREAD);
      fixup_after_potential_safepoint();

      // Convert the result
      istate->set_stack(stack->sp() - 1);

      // Restore the stack
      stack->set_sp(istate->stack_limit() + 1);

      // Resume the interpreter
      istate->set_msg(BytecodeInterpreter::method_resume);
    }
    else if (istate->msg() == BytecodeInterpreter::more_monitors) {
      int monitor_words = frame::interpreter_frame_monitor_size();

      // Allocate the space
      stack->overflow_check(monitor_words, THREAD);
      if (HAS_PENDING_EXCEPTION)
        break;
      stack->alloc(monitor_words * wordSize);

      // Move the expression stack contents
      for (intptr_t *p = istate->stack() + 1; p < istate->stack_base(); p++)
        *(p - monitor_words) = *p;

      // Move the expression stack pointers
      istate->set_stack_limit(istate->stack_limit() - monitor_words);
      istate->set_stack(istate->stack() - monitor_words);
      istate->set_stack_base(istate->stack_base() - monitor_words);

      // Zero the new monitor so the interpreter can find it.
      ((BasicObjectLock *) istate->stack_base())->set_obj(NULL);

      // Resume the interpreter
      istate->set_msg(BytecodeInterpreter::got_monitors);
    }
    else if (istate->msg() == BytecodeInterpreter::return_from_method) {
      // Copy the result into the caller's frame
      result_slots = type2size[result_type_of(method)];
      assert(result_slots >= 0 && result_slots <= 2, "what?");
      result = istate->stack() + result_slots;
      break;
    }
    else if (istate->msg() == BytecodeInterpreter::throwing_exception) {
      assert(HAS_PENDING_EXCEPTION, "should do");
      break;
    }
    else if (istate->msg() == BytecodeInterpreter::do_osr) {
      // Unwind the current frame
      thread->pop_zero_frame();

      // Remove any extension of the previous frame
      int extra_locals = method->max_locals() - method->size_of_parameters();
      stack->set_sp(stack->sp() + extra_locals);

      // Jump into the OSR method
      Interpreter::invoke_osr(
        method, istate->osr_entry(), istate->osr_buf(), THREAD);
      return;
    }
    else if (istate->msg() == BytecodeInterpreter::call_method_handle) {
      oop method_handle = istate->callee();

      // Trim back the stack to put the parameters at the top
      stack->set_sp(istate->stack() + 1);

      // Make the call
      process_method_handle(method_handle, THREAD);
      fixup_after_potential_safepoint();

      // Convert the result
      istate->set_stack(stack->sp() - 1);

      // Restore the stack
      stack->set_sp(istate->stack_limit() + 1);

      // Resume the interpreter
      istate->set_msg(BytecodeInterpreter::method_resume);
    }
    else {
      ShouldNotReachHere();
    }
  }

  // Unwind the current frame
  thread->pop_zero_frame();

  // Pop our local variables
  stack->set_sp(stack->sp() + method->max_locals());

  // Push our result
  for (int i = 0; i < result_slots; i++)
    stack->push(result[-i]);
}

int CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
  // Make sure method is native and not abstract
  assert(method->is_native() && !method->is_abstract(), "should be");

  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();

  // Allocate and initialize our frame
  InterpreterFrame *frame = InterpreterFrame::build(method, CHECK_0);
  thread->push_zero_frame(frame);
  interpreterState istate = frame->interpreter_state();
  intptr_t *locals = istate->locals();

  // Update the invocation counter
  if ((UseCompiler || CountCompiledCalls) && !method->is_synchronized()) {
    InvocationCounter *counter = method->invocation_counter();
    counter->increment();
    if (counter->reached_InvocationLimit()) {
      CALL_VM_NOCHECK(
        InterpreterRuntime::frequency_counter_overflow(thread, NULL));
      if (HAS_PENDING_EXCEPTION)
        goto unwind_and_return;
    }
  }

  // Lock if necessary
  BasicObjectLock *monitor;
  monitor = NULL;
  if (method->is_synchronized()) {
    monitor = (BasicObjectLock*) istate->stack_base();
    oop lockee = monitor->obj();
    markOop disp = lockee->mark()->set_unlocked();

    monitor->lock()->set_displaced_header(disp);
    if (Atomic::cmpxchg_ptr(monitor, lockee->mark_addr(), disp) != disp) {
      if (thread->is_lock_owned((address) disp->clear_lock_bits())) {
        monitor->lock()->set_displaced_header(NULL);
      }
      else {
        CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor));
        if (HAS_PENDING_EXCEPTION)
          goto unwind_and_return;
      }
    }
  }

  // Get the signature handler
  InterpreterRuntime::SignatureHandler *handler; {
    address handlerAddr = method->signature_handler();
    if (handlerAddr == NULL) {
      CALL_VM_NOCHECK(InterpreterRuntime::prepare_native_call(thread, method));
      if (HAS_PENDING_EXCEPTION)
        goto unlock_unwind_and_return;

      handlerAddr = method->signature_handler();
      assert(handlerAddr != NULL, "eh?");
    }
    if (handlerAddr == (address) InterpreterRuntime::slow_signature_handler) {
      CALL_VM_NOCHECK(handlerAddr =
        InterpreterRuntime::slow_signature_handler(thread, method, NULL,NULL));
      if (HAS_PENDING_EXCEPTION)
        goto unlock_unwind_and_return;
    }
    handler = \
      InterpreterRuntime::SignatureHandler::from_handlerAddr(handlerAddr);
  }

  // Get the native function entry point
  address function;
  function = method->native_function();
  assert(function != NULL, "should be set if signature handler is");

  // Build the argument list
  stack->overflow_check(handler->argument_count() * 2, THREAD);
  if (HAS_PENDING_EXCEPTION)
    goto unlock_unwind_and_return;

  void **arguments;
  void *mirror; {
    arguments =
      (void **) stack->alloc(handler->argument_count() * sizeof(void **));
    void **dst = arguments;

    void *env = thread->jni_environment();
    *(dst++) = &env;

    if (method->is_static()) {
      istate->set_oop_temp(
        method->constants()->pool_holder()->java_mirror());
      mirror = istate->oop_temp_addr();
      *(dst++) = &mirror;
    }

    intptr_t *src = locals;
    for (int i = dst - arguments; i < handler->argument_count(); i++) {
      ffi_type *type = handler->argument_type(i);
      if (type == &ffi_type_pointer) {
        if (*src) {
          stack->push((intptr_t) src);
          *(dst++) = stack->sp();
        }
        else {
          *(dst++) = src;
        }
        src--;
      }
      else if (type->size == 4) {
        *(dst++) = src--;
      }
      else if (type->size == 8) {
        src--;
        *(dst++) = src--;
      }
      else {
        ShouldNotReachHere();
      }
    }
  }

  // Set up the Java frame anchor
  thread->set_last_Java_frame();

  // Change the thread state to _thread_in_native
  ThreadStateTransition::transition_from_java(thread, _thread_in_native);

  // Make the call
  intptr_t result[4 - LogBytesPerWord];
  ffi_call(handler->cif(), (void (*)()) function, result, arguments);

  // Change the thread state back to _thread_in_Java.
  // ThreadStateTransition::transition_from_native() cannot be used
  // here because it does not check for asynchronous exceptions.
  // We have to manage the transition ourself.
  thread->set_thread_state(_thread_in_native_trans);

  // Make sure new state is visible in the GC thread
  if (os::is_MP()) {
    if (UseMembar) {
      OrderAccess::fence();
    }
    else {
      InterfaceSupport::serialize_memory(thread);
    }
  }

  // Handle safepoint operations, pending suspend requests,
  // and pending asynchronous exceptions.
  if (SafepointSynchronize::do_call_back() ||
      thread->has_special_condition_for_native_trans()) {
    JavaThread::check_special_condition_for_native_trans(thread);
    CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops());
  }

  // Finally we can change the thread state to _thread_in_Java.
  thread->set_thread_state(_thread_in_Java);
  fixup_after_potential_safepoint();

  // Clear the frame anchor
  thread->reset_last_Java_frame();

  // If the result was an oop then unbox it and store it in
  // oop_temp where the garbage collector can see it before
  // we release the handle it might be protected by.
  if (handler->result_type() == &ffi_type_pointer) {
    if (result[0])
      istate->set_oop_temp(*(oop *) result[0]);
    else
      istate->set_oop_temp(NULL);
  }

  // Reset handle block
  thread->active_handles()->clear();

 unlock_unwind_and_return:

  // Unlock if necessary
  if (monitor) {
    BasicLock *lock = monitor->lock();
    markOop header = lock->displaced_header();
    oop rcvr = monitor->obj();
    monitor->set_obj(NULL);

    if (header != NULL) {
      if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), lock) != lock) {
        monitor->set_obj(rcvr); {
          HandleMark hm(thread);
          CALL_VM_NOCHECK(InterpreterRuntime::monitorexit(thread, monitor));
        }
      }
    }
  }

 unwind_and_return:

  // Unwind the current activation
  thread->pop_zero_frame();

  // Pop our parameters
  stack->set_sp(stack->sp() + method->size_of_parameters());

  // Push our result
  if (!HAS_PENDING_EXCEPTION) {
    BasicType type = result_type_of(method);
    stack->set_sp(stack->sp() - type2size[type]);

    switch (type) {
    case T_VOID:
      break;

    case T_BOOLEAN:
#ifndef VM_LITTLE_ENDIAN
      result[0] <<= (BitsPerWord - BitsPerByte);
#endif
      SET_LOCALS_INT(*(jboolean *) result != 0, 0);
      break;

    case T_CHAR:
#ifndef VM_LITTLE_ENDIAN
      result[0] <<= (BitsPerWord - BitsPerShort);
#endif
      SET_LOCALS_INT(*(jchar *) result, 0);
      break;

    case T_BYTE:
#ifndef VM_LITTLE_ENDIAN
      result[0] <<= (BitsPerWord - BitsPerByte);
#endif
      SET_LOCALS_INT(*(jbyte *) result, 0);
      break;

    case T_SHORT:
#ifndef VM_LITTLE_ENDIAN
      result[0] <<= (BitsPerWord - BitsPerShort);
#endif
      SET_LOCALS_INT(*(jshort *) result, 0);
      break;

    case T_INT:
#ifndef VM_LITTLE_ENDIAN
      result[0] <<= (BitsPerWord - BitsPerInt);
#endif
      SET_LOCALS_INT(*(jint *) result, 0);
      break;

    case T_LONG:
      SET_LOCALS_LONG(*(jlong *) result, 0);
      break;

    case T_FLOAT:
      SET_LOCALS_FLOAT(*(jfloat *) result, 0);
      break;

    case T_DOUBLE:
      SET_LOCALS_DOUBLE(*(jdouble *) result, 0);
      break;

    case T_OBJECT:
    case T_ARRAY:
      SET_LOCALS_OBJECT(istate->oop_temp(), 0);
      break;

    default:
      ShouldNotReachHere();
    }
  }

  // No deoptimized frames on the stack
  return 0;
}

int CppInterpreter::accessor_entry(methodOop method, intptr_t UNUSED, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();
  intptr_t *locals = stack->sp();

  // Drop into the slow path if we need a safepoint check
  if (SafepointSynchronize::do_call_back()) {
    return normal_entry(method, 0, THREAD);
  }

  // Load the object pointer and drop into the slow path
  // if we have a NullPointerException
  oop object = LOCALS_OBJECT(0);
  if (object == NULL) {
    return normal_entry(method, 0, THREAD);
  }

  // Read the field index from the bytecode, which looks like this:
  //  0:  aload_0
  //  1:  getfield
  //  2:    index
  //  3:    index
  //  4:  ireturn/areturn
  // NB this is not raw bytecode: index is in machine order
  u1 *code = method->code_base();
  assert(code[0] == Bytecodes::_aload_0 &&
         code[1] == Bytecodes::_getfield &&
         (code[4] == Bytecodes::_ireturn ||
          code[4] == Bytecodes::_areturn), "should do");
  u2 index = Bytes::get_native_u2(&code[2]);

  // Get the entry from the constant pool cache, and drop into
  // the slow path if it has not been resolved
  constantPoolCacheOop cache = method->constants()->cache();
  ConstantPoolCacheEntry* entry = cache->entry_at(index);
  if (!entry->is_resolved(Bytecodes::_getfield)) {
    return normal_entry(method, 0, THREAD);
  }

  // Get the result and push it onto the stack
  switch (entry->flag_state()) {
  case ltos:
  case dtos:
    stack->overflow_check(1, CHECK_0);
    stack->alloc(wordSize);
    break;
  }
  if (entry->is_volatile()) {
    switch (entry->flag_state()) {
    case ctos:
      SET_LOCALS_INT(object->char_field_acquire(entry->f2()), 0);
      break;

    case btos:
      SET_LOCALS_INT(object->byte_field_acquire(entry->f2()), 0);
      break;

    case stos:
      SET_LOCALS_INT(object->short_field_acquire(entry->f2()), 0);
      break;

    case itos:
      SET_LOCALS_INT(object->int_field_acquire(entry->f2()), 0);
      break;

    case ltos:
      SET_LOCALS_LONG(object->long_field_acquire(entry->f2()), 0);
      break;

    case ftos:
      SET_LOCALS_FLOAT(object->float_field_acquire(entry->f2()), 0);
      break;

    case dtos:
      SET_LOCALS_DOUBLE(object->double_field_acquire(entry->f2()), 0);
      break;

    case atos:
      SET_LOCALS_OBJECT(object->obj_field_acquire(entry->f2()), 0);
      break;

    default:
      ShouldNotReachHere();
    }
  }
  else {
    switch (entry->flag_state()) {
    case ctos:
      SET_LOCALS_INT(object->char_field(entry->f2()), 0);
      break;

    case btos:
      SET_LOCALS_INT(object->byte_field(entry->f2()), 0);
      break;

    case stos:
      SET_LOCALS_INT(object->short_field(entry->f2()), 0);
      break;

    case itos:
      SET_LOCALS_INT(object->int_field(entry->f2()), 0);
      break;

    case ltos:
      SET_LOCALS_LONG(object->long_field(entry->f2()), 0);
      break;

    case ftos:
      SET_LOCALS_FLOAT(object->float_field(entry->f2()), 0);
      break;

    case dtos:
      SET_LOCALS_DOUBLE(object->double_field(entry->f2()), 0);
      break;

    case atos:
      SET_LOCALS_OBJECT(object->obj_field(entry->f2()), 0);
      break;

    default:
      ShouldNotReachHere();
    }
  }

  // No deoptimized frames on the stack
  return 0;
}

int CppInterpreter::empty_entry(methodOop method, intptr_t UNUSED, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();

  // Drop into the slow path if we need a safepoint check
  if (SafepointSynchronize::do_call_back()) {
    return normal_entry(method, 0, THREAD);
  }

  // Pop our parameters
  stack->set_sp(stack->sp() + method->size_of_parameters());

  // No deoptimized frames on the stack
  return 0;
}

int CppInterpreter::method_handle_entry(methodOop method,
                                        intptr_t UNUSED, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();
  int argument_slots = method->size_of_parameters();
  int result_slots = type2size[result_type_of(method)];
  intptr_t *vmslots = stack->sp();
  intptr_t *unwind_sp = vmslots + argument_slots;

  // Find the MethodType
  address p = (address) method;
  for (jint* pc = method->method_type_offsets_chain(); (*pc) != -1; pc++) {
    p = *(address*)(p + (*pc));
  }
  oop method_type = (oop) p;

  // The MethodHandle is in the slot after the arguments
  oop form = java_lang_invoke_MethodType::form(method_type);
  int num_vmslots = java_lang_invoke_MethodTypeForm::vmslots(form);
  assert(argument_slots == num_vmslots + 1, "should be");
  oop method_handle = VMSLOTS_OBJECT(num_vmslots);

  // InvokeGeneric requires some extra shuffling
  oop mhtype = java_lang_invoke_MethodHandle::type(method_handle);
  bool is_exact = mhtype == method_type;
  if (!is_exact) {
    if (method->intrinsic_id() == vmIntrinsics::_invokeExact) {
      CALL_VM_NOCHECK_NOFIX(
        SharedRuntime::throw_WrongMethodTypeException(
          thread, method_type, mhtype));
      // NB all oops trashed!
      assert(HAS_PENDING_EXCEPTION, "should do");
      stack->set_sp(unwind_sp);
      return 0;
    }
    assert(method->intrinsic_id() == vmIntrinsics::_invokeGeneric, "should be");

    // Load up an adapter from the calling type
    // NB the x86 code for this (in methodHandles_x86.cpp, search for
    // "genericInvoker") is really really odd.  I'm hoping it's trying
    // to accomodate odd VM/class library combinations I can ignore.
    oop adapter = java_lang_invoke_MethodTypeForm::genericInvoker(form);
    if (adapter == NULL) {
      CALL_VM_NOCHECK_NOFIX(
        SharedRuntime::throw_WrongMethodTypeException(
          thread, method_type, mhtype));
      // NB all oops trashed!
      assert(HAS_PENDING_EXCEPTION, "should do");
      stack->set_sp(unwind_sp);
      return 0;
    }

    // Adapters are shared among form-families of method-type.  The
    // type being called is passed as a trusted first argument so that
    // the adapter knows the actual types of its arguments and return
    // values.
    insert_vmslots(num_vmslots + 1, 1, THREAD);
    if (HAS_PENDING_EXCEPTION) {
      // NB all oops trashed!
      stack->set_sp(unwind_sp);
      return 0;
    }

    vmslots = stack->sp();
    num_vmslots++;
    SET_VMSLOTS_OBJECT(method_type, num_vmslots);

    method_handle = adapter;
  }

  // Start processing
  process_method_handle(method_handle, THREAD);
  if (HAS_PENDING_EXCEPTION)
    result_slots = 0;

  // If this is an invokeExact then the eventual callee will not
  // have unwound the method handle argument so we have to do it.
  // If a result is being returned the it will be above the method
  // handle argument we're unwinding.
  if (is_exact) {
    intptr_t result[2];
    for (int i = 0; i < result_slots; i++)
      result[i] = stack->pop();
    stack->pop();
    for (int i = result_slots - 1; i >= 0; i--)
      stack->push(result[i]);
  }

  // Check
  assert(stack->sp() == unwind_sp - result_slots, "should be");

  // No deoptimized frames on the stack
  return 0;
}

void CppInterpreter::process_method_handle(oop method_handle, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();
  intptr_t *vmslots = stack->sp();

  bool direct_to_method = false;
  BasicType src_rtype = T_ILLEGAL;
  BasicType dst_rtype = T_ILLEGAL;

  MethodHandleEntry *entry =
    java_lang_invoke_MethodHandle::vmentry(method_handle);
  MethodHandles::EntryKind entry_kind =
    (MethodHandles::EntryKind) (((intptr_t) entry) & 0xffffffff);

  methodOop method = NULL;
  switch (entry_kind) {
  case MethodHandles::_invokestatic_mh:
    direct_to_method = true;
    break;

  case MethodHandles::_invokespecial_mh:
  case MethodHandles::_invokevirtual_mh:
  case MethodHandles::_invokeinterface_mh:
    {
      oop receiver =
        VMSLOTS_OBJECT(
          java_lang_invoke_MethodHandle::vmslots(method_handle) - 1);
      if (receiver == NULL) {
          stack->set_sp(calculate_unwind_sp(stack, method_handle));
          CALL_VM_NOCHECK_NOFIX(
            throw_exception(
              thread, vmSymbols::java_lang_NullPointerException()));
          // NB all oops trashed!
          assert(HAS_PENDING_EXCEPTION, "should do");
          return;
      }
      if (entry_kind != MethodHandles::_invokespecial_mh) {
        int index = java_lang_invoke_DirectMethodHandle::vmindex(method_handle);
        instanceKlass* rcvrKlass =
          (instanceKlass *) receiver->klass()->klass_part();
        if (entry_kind == MethodHandles::_invokevirtual_mh) {
          method = (methodOop) rcvrKlass->start_of_vtable()[index];
        }
        else {
          oop iclass = java_lang_invoke_MethodHandle::vmtarget(method_handle);
          itableOffsetEntry* ki =
            (itableOffsetEntry *) rcvrKlass->start_of_itable();
          int i, length = rcvrKlass->itable_length();
          for (i = 0; i < length; i++, ki++ ) {
            if (ki->interface_klass() == iclass)
              break;
          }
          if (i == length) {
            stack->set_sp(calculate_unwind_sp(stack, method_handle));
            CALL_VM_NOCHECK_NOFIX(
              throw_exception(
                thread, vmSymbols::java_lang_IncompatibleClassChangeError()));
            // NB all oops trashed!
            assert(HAS_PENDING_EXCEPTION, "should do");
            return;
          }
          itableMethodEntry* im = ki->first_method_entry(receiver->klass());
          method = im[index].method();
          if (method == NULL) {
            stack->set_sp(calculate_unwind_sp(stack, method_handle));
            CALL_VM_NOCHECK_NOFIX(
              throw_exception(
                thread, vmSymbols::java_lang_AbstractMethodError()));
            // NB all oops trashed!
            assert(HAS_PENDING_EXCEPTION, "should do");
            return;
          }
        }
      }
    }
    direct_to_method = true;
    break;

  case MethodHandles::_bound_ref_direct_mh:
  case MethodHandles::_bound_int_direct_mh:
  case MethodHandles::_bound_long_direct_mh:
    direct_to_method = true;
    // fall through
  case MethodHandles::_bound_ref_mh:
  case MethodHandles::_bound_int_mh:
  case MethodHandles::_bound_long_mh:
    {
      BasicType arg_type  = T_ILLEGAL;
      int       arg_mask  = -1;
      int       arg_slots = -1;
      MethodHandles::get_ek_bound_mh_info(
        entry_kind, arg_type, arg_mask, arg_slots);
      int arg_slot =
        java_lang_invoke_BoundMethodHandle::vmargslot(method_handle);

      // Create the new slot(s)
      intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
      insert_vmslots(arg_slot, arg_slots, THREAD);
      if (HAS_PENDING_EXCEPTION) {
        // all oops trashed
        stack->set_sp(unwind_sp);
        return;
      }
      vmslots = stack->sp();

      // Store bound argument into new stack slot
      oop arg = java_lang_invoke_BoundMethodHandle::argument(method_handle);
      if (arg_type == T_OBJECT) {
        assert(arg_slots == 1, "should be");
        SET_VMSLOTS_OBJECT(arg, arg_slot);
      }
      else {
        jvalue arg_value;
        arg_type = java_lang_boxing_object::get_value(arg, &arg_value);
        switch (arg_type) {
        case T_BOOLEAN:
          SET_VMSLOTS_INT(arg_value.z, arg_slot);
          break;
        case T_CHAR:
          SET_VMSLOTS_INT(arg_value.c, arg_slot);
          break;
        case T_BYTE:
          SET_VMSLOTS_INT(arg_value.b, arg_slot);
          break;
        case T_SHORT:
          SET_VMSLOTS_INT(arg_value.s, arg_slot);
          break;
        case T_INT:
          SET_VMSLOTS_INT(arg_value.i, arg_slot);
          break;
        case T_FLOAT:
          SET_VMSLOTS_FLOAT(arg_value.f, arg_slot);
          break;
        case T_LONG:
          SET_VMSLOTS_LONG(arg_value.j, arg_slot + 1);
          break;
        case T_DOUBLE:
          SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot + 1);
          break;
        default:
          tty->print_cr("unhandled type %s", type2name(arg_type));
          ShouldNotReachHere();
        }
      }
    }
    break;

  case MethodHandles::_adapter_retype_only:
  case MethodHandles::_adapter_retype_raw:
    src_rtype = result_type_of_handle(
      java_lang_invoke_MethodHandle::vmtarget(method_handle));
    dst_rtype = result_type_of_handle(method_handle);
    break;

  case MethodHandles::_adapter_check_cast:
    {
      int arg_slot =
        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
      oop arg = VMSLOTS_OBJECT(arg_slot);
      if (arg != NULL) {
        klassOop objKlassOop = arg->klass();
        klassOop klassOf = java_lang_Class::as_klassOop(
          java_lang_invoke_AdapterMethodHandle::argument(method_handle));

        if (objKlassOop != klassOf &&
            !objKlassOop->klass_part()->is_subtype_of(klassOf)) {
          ResourceMark rm(THREAD);
          const char* objName = Klass::cast(objKlassOop)->external_name();
          const char* klassName = Klass::cast(klassOf)->external_name();
          char* message = SharedRuntime::generate_class_cast_message(
            objName, klassName);

          stack->set_sp(calculate_unwind_sp(stack, method_handle));
          CALL_VM_NOCHECK_NOFIX(
            throw_exception(
              thread, vmSymbols::java_lang_ClassCastException(), message));
          // NB all oops trashed!
          assert(HAS_PENDING_EXCEPTION, "should do");
          return;
        }
      }
    }
    break;

  case MethodHandles::_adapter_dup_args:
    {
      int arg_slot =
        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
      int conv =
        java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
      int num_slots = -MethodHandles::adapter_conversion_stack_move(conv);
      assert(num_slots > 0, "should be");

      // Create the new slot(s)
      intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
      stack->overflow_check(num_slots, THREAD);
      if (HAS_PENDING_EXCEPTION) {
        // all oops trashed
        stack->set_sp(unwind_sp);
        return;
      }

      // Duplicate the arguments
      for (int i = num_slots - 1; i >= 0; i--)
        stack->push(*VMSLOTS_SLOT(arg_slot + i));

      vmslots = stack->sp(); // unused, but let the compiler figure that out
    }
    break;

  case MethodHandles::_adapter_drop_args:
    {
      int arg_slot =
        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
      int conv =
        java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
      int num_slots = MethodHandles::adapter_conversion_stack_move(conv);
      assert(num_slots > 0, "should be");

      remove_vmslots(arg_slot, num_slots, THREAD); // doesn't trap
      vmslots = stack->sp(); // unused, but let the compiler figure that out
    }
    break;

  case MethodHandles::_adapter_opt_swap_1:
  case MethodHandles::_adapter_opt_swap_2:
  case MethodHandles::_adapter_opt_rot_1_up:
  case MethodHandles::_adapter_opt_rot_1_down:
  case MethodHandles::_adapter_opt_rot_2_up:
  case MethodHandles::_adapter_opt_rot_2_down:
    {
      int arg1 =
        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
      int conv =
        java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
      int arg2 = MethodHandles::adapter_conversion_vminfo(conv);

      int swap_bytes = 0, rotate = 0;
      MethodHandles::get_ek_adapter_opt_swap_rot_info(
        entry_kind, swap_bytes, rotate);
      int swap_slots = swap_bytes >> LogBytesPerWord;

      intptr_t tmp;
      switch (rotate) {
      case 0: // swap
        for (int i = 0; i < swap_slots; i++) {
          tmp = *VMSLOTS_SLOT(arg1 + i);
          SET_VMSLOTS_SLOT(VMSLOTS_SLOT(arg2 + i), arg1 + i);
          SET_VMSLOTS_SLOT(&tmp, arg2 + i);
        }
        break;

      case 1: // up
        assert(arg1 - swap_slots > arg2, "should be");

        tmp = *VMSLOTS_SLOT(arg1);
        for (int i = arg1 - swap_slots; i >= arg2; i--)
          SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + swap_slots);
        SET_VMSLOTS_SLOT(&tmp, arg2);

        break;

      case -1: // down
        assert(arg2 - swap_slots > arg1, "should be");

        tmp = *VMSLOTS_SLOT(arg1);
        for (int i = arg1 + swap_slots; i <= arg2; i++)
          SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i - swap_slots);
        SET_VMSLOTS_SLOT(&tmp, arg2);
        break;

      default:
        ShouldNotReachHere();
      }
    }
    break;

  case MethodHandles::_adapter_opt_i2l:
    {
      int arg_slot =
        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
      int arg = VMSLOTS_INT(arg_slot);
      intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
      insert_vmslots(arg_slot, 1, THREAD);
      if (HAS_PENDING_EXCEPTION) {
        // all oops trashed
        stack->set_sp(unwind_sp);
        return;
      }
      vmslots = stack->sp();
      arg_slot++;
      SET_VMSLOTS_LONG(arg, arg_slot);
    }
    break;

  case MethodHandles::_adapter_opt_unboxi:
  case MethodHandles::_adapter_opt_unboxl:
    {
      int arg_slot =
        java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
      oop arg = VMSLOTS_OBJECT(arg_slot);
      jvalue arg_value;
      BasicType arg_type = java_lang_boxing_object::get_value(arg, &arg_value);
      if (arg_type == T_LONG || arg_type == T_DOUBLE) {
        intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
        insert_vmslots(arg_slot, 1, THREAD);
        if (HAS_PENDING_EXCEPTION) {
          // all oops trashed
          stack->set_sp(unwind_sp);
          return;
        }
        vmslots = stack->sp();
        arg_slot++;
      }
      switch (arg_type) {
      case T_BOOLEAN:
        SET_VMSLOTS_INT(arg_value.z, arg_slot);
        break;
      case T_CHAR:
        SET_VMSLOTS_INT(arg_value.c, arg_slot);
        break;
      case T_BYTE:
        SET_VMSLOTS_INT(arg_value.b, arg_slot);
        break;
      case T_SHORT:
        SET_VMSLOTS_INT(arg_value.s, arg_slot);
        break;
      case T_INT:
        SET_VMSLOTS_INT(arg_value.i, arg_slot);
        break;
      case T_FLOAT:
        SET_VMSLOTS_FLOAT(arg_value.f, arg_slot);
        break;
      case T_LONG:
        SET_VMSLOTS_LONG(arg_value.j, arg_slot);
        break;
      case T_DOUBLE:
        SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot);
        break;
      default:
        tty->print_cr("unhandled type %s", type2name(arg_type));
        ShouldNotReachHere();
      }
    }
    break;

  default:
    tty->print_cr("unhandled entry_kind %s",
                  MethodHandles::entry_name(entry_kind));
    ShouldNotReachHere();
  }

  // Continue along the chain
  if (direct_to_method) {
    if (method == NULL) {
      method =
        (methodOop) java_lang_invoke_MethodHandle::vmtarget(method_handle);
    }
    address entry_point = method->from_interpreted_entry();
    Interpreter::invoke_method(method, entry_point, THREAD);
  }
  else {
    process_method_handle(
      java_lang_invoke_MethodHandle::vmtarget(method_handle), THREAD);
  }
  // NB all oops now trashed

  // Adapt the result type, if necessary
  if (src_rtype != dst_rtype && !HAS_PENDING_EXCEPTION) {
    switch (dst_rtype) {
    case T_VOID:
      for (int i = 0; i < type2size[src_rtype]; i++)
        stack->pop();
      return;

    case T_INT:
      switch (src_rtype) {
      case T_VOID:
        stack->overflow_check(1, CHECK);
        stack->push(0);
        return;

      case T_BOOLEAN:
      case T_CHAR:
      case T_BYTE:
      case T_SHORT:
        return;
      }
    }

    tty->print_cr("unhandled conversion:");
    tty->print_cr("src_rtype = %s", type2name(src_rtype));
    tty->print_cr("dst_rtype = %s", type2name(dst_rtype));
    ShouldNotReachHere();
  }
}

// The new slots will be inserted before slot insert_before.
// Slots < insert_before will have the same slot number after the insert.
// Slots >= insert_before will become old_slot + num_slots.
void CppInterpreter::insert_vmslots(int insert_before, int num_slots, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();

  // Allocate the space
  stack->overflow_check(num_slots, CHECK);
  stack->alloc(num_slots * wordSize);
  intptr_t *vmslots = stack->sp();

  // Shuffle everything up
  for (int i = 0; i < insert_before; i++)
    SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i + num_slots), i);
}

void CppInterpreter::remove_vmslots(int first_slot, int num_slots, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();
  intptr_t *vmslots = stack->sp();

  // Move everything down
  for (int i = first_slot - 1; i >= 0; i--)
    SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + num_slots);

  // Deallocate the space
  stack->set_sp(stack->sp() + num_slots);
}

BasicType CppInterpreter::result_type_of_handle(oop method_handle) {
  oop method_type = java_lang_invoke_MethodHandle::type(method_handle);
  oop return_type = java_lang_invoke_MethodType::rtype(method_type);
  return java_lang_Class::as_BasicType(return_type, (klassOop *) NULL);
}

intptr_t* CppInterpreter::calculate_unwind_sp(ZeroStack* stack,
                                              oop method_handle) {
  oop method_type = java_lang_invoke_MethodHandle::type(method_handle);
  oop form = java_lang_invoke_MethodType::form(method_type);
  int argument_slots = java_lang_invoke_MethodTypeForm::vmslots(form);

  return stack->sp() + argument_slots;
}

IRT_ENTRY(void, CppInterpreter::throw_exception(JavaThread* thread,
                                                Symbol*     name,
                                                char*       message))
  THROW_MSG(name, message);
IRT_END

InterpreterFrame *InterpreterFrame::build(const methodOop method, TRAPS) {
  JavaThread *thread = (JavaThread *) THREAD;
  ZeroStack *stack = thread->zero_stack();

  // Calculate the size of the frame we'll build, including
  // any adjustments to the caller's frame that we'll make.
  int extra_locals  = 0;
  int monitor_words = 0;
  int stack_words   = 0;

  if (!method->is_native()) {
    extra_locals = method->max_locals() - method->size_of_parameters();
    stack_words  = method->max_stack();
  }
  if (method->is_synchronized()) {
    monitor_words = frame::interpreter_frame_monitor_size();
  }
  stack->overflow_check(
    extra_locals + header_words + monitor_words + stack_words, CHECK_NULL);

  // Adjust the caller's stack frame to accomodate any additional
  // local variables we have contiguously with our parameters.
  for (int i = 0; i < extra_locals; i++)
    stack->push(0);

  intptr_t *locals;
  if (method->is_native())
    locals = stack->sp() + (method->size_of_parameters() - 1);
  else
    locals = stack->sp() + (method->max_locals() - 1);

  stack->push(0); // next_frame, filled in later
  intptr_t *fp = stack->sp();
  assert(fp - stack->sp() == next_frame_off, "should be");

  stack->push(INTERPRETER_FRAME);
  assert(fp - stack->sp() == frame_type_off, "should be");

  interpreterState istate =
    (interpreterState) stack->alloc(sizeof(BytecodeInterpreter));
  assert(fp - stack->sp() == istate_off, "should be");

  istate->set_locals(locals);
  istate->set_method(method);
  istate->set_self_link(istate);
  istate->set_prev_link(NULL);
  istate->set_thread(thread);
  istate->set_bcp(method->is_native() ? NULL : method->code_base());
  istate->set_constants(method->constants()->cache());
  istate->set_msg(BytecodeInterpreter::method_entry);
  istate->set_oop_temp(NULL);
  istate->set_mdx(NULL);
  istate->set_callee(NULL);

  istate->set_monitor_base((BasicObjectLock *) stack->sp());
  if (method->is_synchronized()) {
    BasicObjectLock *monitor =
      (BasicObjectLock *) stack->alloc(monitor_words * wordSize);
    oop object;
    if (method->is_static())
      object = method->constants()->pool_holder()->java_mirror();
    else
      object = (oop) locals[0];
    monitor->set_obj(object);
  }

  istate->set_stack_base(stack->sp());
  istate->set_stack(stack->sp() - 1);
  if (stack_words)
    stack->alloc(stack_words * wordSize);
  istate->set_stack_limit(stack->sp() - 1);

  return (InterpreterFrame *) fp;
}

int AbstractInterpreter::BasicType_as_index(BasicType type) {
  int i = 0;
  switch (type) {
    case T_BOOLEAN: i = 0; break;
    case T_CHAR   : i = 1; break;
    case T_BYTE   : i = 2; break;
    case T_SHORT  : i = 3; break;
    case T_INT    : i = 4; break;
    case T_LONG   : i = 5; break;
    case T_VOID   : i = 6; break;
    case T_FLOAT  : i = 7; break;
    case T_DOUBLE : i = 8; break;
    case T_OBJECT : i = 9; break;
    case T_ARRAY  : i = 9; break;
    default       : ShouldNotReachHere();
  }
  assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers,
         "index out of bounds");
  return i;
}

BasicType CppInterpreter::result_type_of(methodOop method) {
  BasicType t;
  switch (method->result_index()) {
    case 0 : t = T_BOOLEAN; break;
    case 1 : t = T_CHAR;    break;
    case 2 : t = T_BYTE;    break;
    case 3 : t = T_SHORT;   break;
    case 4 : t = T_INT;     break;
    case 5 : t = T_LONG;    break;
    case 6 : t = T_VOID;    break;
    case 7 : t = T_FLOAT;   break;
    case 8 : t = T_DOUBLE;  break;
    case 9 : t = T_OBJECT;  break;
    default: ShouldNotReachHere();
  }
  assert(AbstractInterpreter::BasicType_as_index(t) == method->result_index(),
         "out of step with AbstractInterpreter::BasicType_as_index");
  return t;
}

address InterpreterGenerator::generate_empty_entry() {
  if (!UseFastEmptyMethods)
    return NULL;

  return generate_entry((address) CppInterpreter::empty_entry);
}

address InterpreterGenerator::generate_accessor_entry() {
  if (!UseFastAccessorMethods)
    return NULL;

  return generate_entry((address) CppInterpreter::accessor_entry);
}

address InterpreterGenerator::generate_Reference_get_entry(void) {
#ifndef SERIALGC
  if (UseG1GC) {
    // We need to generate have a routine that generates code to:
    //   * load the value in the referent field
    //   * passes that value to the pre-barrier.
    //
    // In the case of G1 this will record the value of the
    // referent in an SATB buffer if marking is active.
    // This will cause concurrent marking to mark the referent
    // field as live.
    Unimplemented();
  }
#endif // SERIALGC

  // If G1 is not enabled then attempt to go through the accessor entry point
  // Reference.get is an accessor
  return generate_accessor_entry();
}

address InterpreterGenerator::generate_native_entry(bool synchronized) {
  assert(synchronized == false, "should be");

  return generate_entry((address) CppInterpreter::native_entry);
}

address InterpreterGenerator::generate_normal_entry(bool synchronized) {
  assert(synchronized == false, "should be");

  return generate_entry((address) CppInterpreter::normal_entry);
}

address AbstractInterpreterGenerator::generate_method_entry(
    AbstractInterpreter::MethodKind kind) {
  address entry_point = NULL;

  switch (kind) {
  case Interpreter::zerolocals:
  case Interpreter::zerolocals_synchronized:
    break;

  case Interpreter::native:
    entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false);
    break;

  case Interpreter::native_synchronized:
    entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false);
    break;

  case Interpreter::empty:
    entry_point = ((InterpreterGenerator*) this)->generate_empty_entry();
    break;

  case Interpreter::accessor:
    entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry();
    break;

  case Interpreter::abstract:
    entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry();
    break;

  case Interpreter::method_handle:
    entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();
    break;

  case Interpreter::java_lang_math_sin:
  case Interpreter::java_lang_math_cos:
  case Interpreter::java_lang_math_tan:
  case Interpreter::java_lang_math_abs:
  case Interpreter::java_lang_math_log:
  case Interpreter::java_lang_math_log10:
  case Interpreter::java_lang_math_sqrt:
    entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind);
    break;

  case Interpreter::java_lang_ref_reference_get:
    entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry();
    break;

  default:
    ShouldNotReachHere();
  }

  if (entry_point == NULL)
    entry_point = ((InterpreterGenerator*) this)->generate_normal_entry(false);

  return entry_point;
}

InterpreterGenerator::InterpreterGenerator(StubQueue* code)
 : CppInterpreterGenerator(code) {
   generate_all();
}

// Deoptimization helpers

InterpreterFrame *InterpreterFrame::build(int size, TRAPS) {
  ZeroStack *stack = ((JavaThread *) THREAD)->zero_stack();

  int size_in_words = size >> LogBytesPerWord;
  assert(size_in_words * wordSize == size, "unaligned");
  assert(size_in_words >= header_words, "too small");
  stack->overflow_check(size_in_words, CHECK_NULL);

  stack->push(0); // next_frame, filled in later
  intptr_t *fp = stack->sp();
  assert(fp - stack->sp() == next_frame_off, "should be");

  stack->push(INTERPRETER_FRAME);
  assert(fp - stack->sp() == frame_type_off, "should be");

  interpreterState istate =
    (interpreterState) stack->alloc(sizeof(BytecodeInterpreter));
  assert(fp - stack->sp() == istate_off, "should be");
  istate->set_self_link(NULL); // mark invalid

  stack->alloc((size_in_words - header_words) * wordSize);

  return (InterpreterFrame *) fp;
}

int AbstractInterpreter::layout_activation(methodOop method,
                                           int       tempcount,
                                           int       popframe_extra_args,
                                           int       moncount,
                                           int       caller_actual_parameters,
                                           int       callee_param_count,
                                           int       callee_locals,
                                           frame*    caller,
                                           frame*    interpreter_frame,
                                           bool      is_top_frame) {
  assert(popframe_extra_args == 0, "what to do?");
  assert(!is_top_frame || (!callee_locals && !callee_param_count),
         "top frame should have no caller");

  // This code must exactly match what InterpreterFrame::build
  // does (the full InterpreterFrame::build, that is, not the
  // one that creates empty frames for the deoptimizer).
  //
  // If interpreter_frame is not NULL then it will be filled in.
  // It's size is determined by a previous call to this method,
  // so it should be correct.
  //
  // Note that tempcount is the current size of the expression
  // stack.  For top most frames we will allocate a full sized
  // expression stack and not the trimmed version that non-top
  // frames have.

  int header_words        = InterpreterFrame::header_words;
  int monitor_words       = moncount * frame::interpreter_frame_monitor_size();
  int stack_words         = is_top_frame ? method->max_stack() : tempcount;
  int callee_extra_locals = callee_locals - callee_param_count;

  if (interpreter_frame) {
    intptr_t *locals        = interpreter_frame->fp() + method->max_locals();
    interpreterState istate = interpreter_frame->get_interpreterState();
    intptr_t *monitor_base  = (intptr_t*) istate;
    intptr_t *stack_base    = monitor_base - monitor_words;
    intptr_t *stack         = stack_base - tempcount - 1;

    BytecodeInterpreter::layout_interpreterState(istate,
                                                 caller,
                                                 NULL,
                                                 method,
                                                 locals,
                                                 stack,
                                                 stack_base,
                                                 monitor_base,
                                                 NULL,
                                                 is_top_frame);
  }
  return header_words + monitor_words + stack_words + callee_extra_locals;
}

void BytecodeInterpreter::layout_interpreterState(interpreterState istate,
                                                  frame*    caller,
                                                  frame*    current,
                                                  methodOop method,
                                                  intptr_t* locals,
                                                  intptr_t* stack,
                                                  intptr_t* stack_base,
                                                  intptr_t* monitor_base,
                                                  intptr_t* frame_bottom,
                                                  bool      is_top_frame) {
  istate->set_locals(locals);
  istate->set_method(method);
  istate->set_self_link(istate);
  istate->set_prev_link(NULL);
  // thread will be set by a hacky repurposing of frame::patch_pc()
  // bcp will be set by vframeArrayElement::unpack_on_stack()
  istate->set_constants(method->constants()->cache());
  istate->set_msg(BytecodeInterpreter::method_resume);
  istate->set_bcp_advance(0);
  istate->set_oop_temp(NULL);
  istate->set_mdx(NULL);
  if (caller->is_interpreted_frame()) {
    interpreterState prev = caller->get_interpreterState();
    prev->set_callee(method);
    if (*prev->bcp() == Bytecodes::_invokeinterface)
      prev->set_bcp_advance(5);
    else
      prev->set_bcp_advance(3);
  }
  istate->set_callee(NULL);
  istate->set_monitor_base((BasicObjectLock *) monitor_base);
  istate->set_stack_base(stack_base);
  istate->set_stack(stack);
  istate->set_stack_limit(stack_base - method->max_stack() - 1);
}

address CppInterpreter::return_entry(TosState state, int length) {
  ShouldNotCallThis();
}

address CppInterpreter::deopt_entry(TosState state, int length) {
  return NULL;
}

// Helper for (runtime) stack overflow checks

int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
  return 0;
}

// Helper for figuring out if frames are interpreter frames

bool CppInterpreter::contains(address pc) {
#ifdef PRODUCT
  ShouldNotCallThis();
#else
  return false; // make frame::print_value_on work
#endif // !PRODUCT
}

// Result handlers and convertors

address CppInterpreterGenerator::generate_result_handler_for(
    BasicType type) {
  assembler()->advance(1);
  return ShouldNotCallThisStub();
}

address CppInterpreterGenerator::generate_tosca_to_stack_converter(
    BasicType type) {
  assembler()->advance(1);
  return ShouldNotCallThisStub();
}

address CppInterpreterGenerator::generate_stack_to_stack_converter(
    BasicType type) {
  assembler()->advance(1);
  return ShouldNotCallThisStub();
}

address CppInterpreterGenerator::generate_stack_to_native_abi_converter(
    BasicType type) {
  assembler()->advance(1);
  return ShouldNotCallThisStub();
}

#endif // CC_INTERP