8179305: Avoid repeated calls to JavaThread::last_frame in InterpreterRuntime
authoriklam
Mon, 01 May 2017 11:16:01 -0700
changeset 46424 2dfc07162b35
parent 46423 62fac1c2c841
child 46426 02a1fc064144
8179305: Avoid repeated calls to JavaThread::last_frame in InterpreterRuntime Summary: Added LastFrameAccessor class Reviewed-by: dlong, dholmes
hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
hotspot/src/share/vm/interpreter/interpreterRuntime.hpp
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Mon May 01 10:50:38 2017 -0400
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Mon May 01 11:16:01 2017 -0700
@@ -86,14 +86,15 @@
 // State accessors
 
 void InterpreterRuntime::set_bcp_and_mdp(address bcp, JavaThread *thread) {
-  last_frame(thread).interpreter_frame_set_bcp(bcp);
+  LastFrameAccessor last_frame(thread);
+  last_frame.set_bcp(bcp);
   if (ProfileInterpreter) {
     // ProfileTraps uses MDOs independently of ProfileInterpreter.
     // That is why we must check both ProfileInterpreter and mdo != NULL.
-    MethodData* mdo = last_frame(thread).interpreter_frame_method()->method_data();
+    MethodData* mdo = last_frame.method()->method_data();
     if (mdo != NULL) {
       NEEDS_CLEANUP;
-      last_frame(thread).interpreter_frame_set_mdp(mdo->bci_to_dp(last_frame(thread).interpreter_frame_bci()));
+      last_frame.set_mdp(mdo->bci_to_dp(last_frame.bci()));
     }
   }
 }
@@ -104,8 +105,9 @@
 
 IRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* thread, bool wide))
   // access constant pool
-  ConstantPool* pool = method(thread)->constants();
-  int index = wide ? get_index_u2(thread, Bytecodes::_ldc_w) : get_index_u1(thread, Bytecodes::_ldc);
+  LastFrameAccessor last_frame(thread);
+  ConstantPool* pool = last_frame.method()->constants();
+  int index = wide ? last_frame.get_index_u2(Bytecodes::_ldc_w) : last_frame.get_index_u1(Bytecodes::_ldc);
   constantTag tag = pool->tag_at(index);
 
   assert (tag.is_unresolved_klass() || tag.is_klass(), "wrong ldc call");
@@ -118,13 +120,14 @@
   assert(bytecode == Bytecodes::_fast_aldc ||
          bytecode == Bytecodes::_fast_aldc_w, "wrong bc");
   ResourceMark rm(thread);
-  methodHandle m (thread, method(thread));
-  Bytecode_loadconstant ldc(m, bci(thread));
+  LastFrameAccessor last_frame(thread);
+  methodHandle m (thread, last_frame.method());
+  Bytecode_loadconstant ldc(m, last_frame.bci());
   oop result = ldc.resolve_constant(CHECK);
 #ifdef ASSERT
   {
     // The bytecode wrappers aren't GC-safe so construct a new one
-    Bytecode_loadconstant ldc2(m, bci(thread));
+    Bytecode_loadconstant ldc2(m, last_frame.bci());
     oop coop = m->constants()->resolved_references()->obj_at(ldc2.cache_index());
     assert(result == coop, "expected result for assembly code");
   }
@@ -181,10 +184,11 @@
 
 IRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* thread, jint* first_size_address))
   // We may want to pass in more arguments - could make this slightly faster
-  ConstantPool* constants = method(thread)->constants();
-  int          i = get_index_u2(thread, Bytecodes::_multianewarray);
-  Klass* klass = constants->klass_at(i, CHECK);
-  int   nof_dims = number_of_dimensions(thread);
+  LastFrameAccessor last_frame(thread);
+  ConstantPool* constants = last_frame.method()->constants();
+  int          i = last_frame.get_index_u2(Bytecodes::_multianewarray);
+  Klass* klass   = constants->klass_at(i, CHECK);
+  int   nof_dims = last_frame.number_of_dimensions();
   assert(klass->is_klass(), "not a class");
   assert(nof_dims >= 1, "multianewarray rank must be nonzero");
 
@@ -216,8 +220,9 @@
 // Quicken instance-of and check-cast bytecodes
 IRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* thread))
   // Force resolving; quicken the bytecode
-  int which = get_index_u2(thread, Bytecodes::_checkcast);
-  ConstantPool* cpool = method(thread)->constants();
+  LastFrameAccessor last_frame(thread);
+  int which = last_frame.get_index_u2(Bytecodes::_checkcast);
+  ConstantPool* cpool = last_frame.method()->constants();
   // We'd expect to assert that we're only here to quicken bytecodes, but in a multithreaded
   // program we might have seen an unquick'd bytecode in the interpreter but have another
   // thread quicken the bytecode before we get here.
@@ -256,8 +261,9 @@
 // If necessary, create an MDO to hold the information, and record it.
 void InterpreterRuntime::note_trap(JavaThread* thread, int reason, TRAPS) {
   assert(ProfileTraps, "call me only if profiling");
-  methodHandle trap_method(thread, method(thread));
-  int trap_bci = trap_method->bci_from(bcp(thread));
+  LastFrameAccessor last_frame(thread);
+  methodHandle trap_method(thread, last_frame.method());
+  int trap_bci = trap_method->bci_from(last_frame.bcp());
   note_trap_inner(thread, reason, trap_method, trap_bci, THREAD);
 }
 
@@ -390,12 +396,13 @@
 // invoke w/o arguments (i.e., as if one were inside the call).
 IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* thread, oopDesc* exception))
 
+  LastFrameAccessor last_frame(thread);
   Handle             h_exception(thread, exception);
-  methodHandle       h_method   (thread, method(thread));
+  methodHandle       h_method   (thread, last_frame.method());
   constantPoolHandle h_constants(thread, h_method->constants());
   bool               should_repeat;
   int                handler_bci;
-  int                current_bci = bci(thread);
+  int                current_bci = last_frame.bci();
 
   if (thread->frames_to_pop_failed_realloc() > 0) {
     // Allocation of scalar replaced object used in this frame
@@ -493,7 +500,7 @@
   // notify JVMTI of an exception throw; JVMTI will detect if this is a first
   // time throw or a stack unwinding throw and accordingly notify the debugger
   if (JvmtiExport::can_post_on_exceptions()) {
-    JvmtiExport::post_exception_throw(thread, h_method(), bcp(thread), h_exception());
+    JvmtiExport::post_exception_throw(thread, h_method(), last_frame.bcp(), h_exception());
   }
 
 #ifdef CC_INTERP
@@ -556,20 +563,21 @@
   Thread* THREAD = thread;
   // resolve field
   fieldDescriptor info;
-  constantPoolHandle pool(thread, method(thread)->constants());
-  methodHandle m(thread, method(thread));
+  LastFrameAccessor last_frame(thread);
+  constantPoolHandle pool(thread, last_frame.method()->constants());
+  methodHandle m(thread, last_frame.method());
   bool is_put    = (bytecode == Bytecodes::_putfield  || bytecode == Bytecodes::_nofast_putfield ||
                     bytecode == Bytecodes::_putstatic);
   bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
 
   {
     JvmtiHideSingleStepping jhss(thread);
-    LinkResolver::resolve_field_access(info, pool, get_index_u2_cpcache(thread, bytecode),
+    LinkResolver::resolve_field_access(info, pool, last_frame.get_index_u2_cpcache(bytecode),
                                        m, bytecode, CHECK);
   } // end JvmtiHideSingleStepping
 
   // check if link resolution caused cpCache to be updated
-  ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread);
+  ConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry();
   if (cp_cache_entry->is_resolved(bytecode)) return;
 
   // compute auxiliary field attributes
@@ -718,15 +726,15 @@
 
 void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode) {
   Thread* THREAD = thread;
+  LastFrameAccessor last_frame(thread);
   // extract receiver from the outgoing argument list if necessary
   Handle receiver(thread, NULL);
   if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
     ResourceMark rm(thread);
-    methodHandle m (thread, method(thread));
-    Bytecode_invoke call(m, bci(thread));
+    methodHandle m (thread, last_frame.method());
+    Bytecode_invoke call(m, last_frame.bci());
     Symbol* signature = call.signature();
-    receiver = Handle(thread,
-                  thread->last_frame().interpreter_callee_receiver(signature));
+    receiver = Handle(thread, last_frame.callee_receiver(signature));
     assert(Universe::heap()->is_in_reserved_or_null(receiver()),
            "sanity check");
     assert(receiver.is_null() ||
@@ -736,12 +744,12 @@
 
   // resolve method
   CallInfo info;
-  constantPoolHandle pool(thread, method(thread)->constants());
+  constantPoolHandle pool(thread, last_frame.method()->constants());
 
   {
     JvmtiHideSingleStepping jhss(thread);
     LinkResolver::resolve_invoke(info, receiver, pool,
-                                 get_index_u2_cpcache(thread, bytecode), bytecode,
+                                 last_frame.get_index_u2_cpcache(bytecode), bytecode,
                                  CHECK);
     if (JvmtiExport::can_hotswap_or_post_breakpoint()) {
       int retry_count = 0;
@@ -753,14 +761,14 @@
                   "Could not resolve to latest version of redefined method");
         // method is redefined in the middle of resolve so re-try.
         LinkResolver::resolve_invoke(info, receiver, pool,
-                                     get_index_u2_cpcache(thread, bytecode), bytecode,
+                                     last_frame.get_index_u2_cpcache(bytecode), bytecode,
                                      CHECK);
       }
     }
   } // end JvmtiHideSingleStepping
 
   // check if link resolution caused cpCache to be updated
-  ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread);
+  ConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry();
   if (cp_cache_entry->is_resolved(bytecode)) return;
 
 #ifdef ASSERT
@@ -815,33 +823,35 @@
 void InterpreterRuntime::resolve_invokehandle(JavaThread* thread) {
   Thread* THREAD = thread;
   const Bytecodes::Code bytecode = Bytecodes::_invokehandle;
+  LastFrameAccessor last_frame(thread);
 
   // resolve method
   CallInfo info;
-  constantPoolHandle pool(thread, method(thread)->constants());
+  constantPoolHandle pool(thread, last_frame.method()->constants());
   {
     JvmtiHideSingleStepping jhss(thread);
     LinkResolver::resolve_invoke(info, Handle(), pool,
-                                 get_index_u2_cpcache(thread, bytecode), bytecode,
+                                 last_frame.get_index_u2_cpcache(bytecode), bytecode,
                                  CHECK);
   } // end JvmtiHideSingleStepping
 
-  ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread);
+  ConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry();
   cp_cache_entry->set_method_handle(pool, info);
 }
 
 // First time execution:  Resolve symbols, create a permanent CallSite object.
 void InterpreterRuntime::resolve_invokedynamic(JavaThread* thread) {
   Thread* THREAD = thread;
+  LastFrameAccessor last_frame(thread);
   const Bytecodes::Code bytecode = Bytecodes::_invokedynamic;
 
   //TO DO: consider passing BCI to Java.
-  //  int caller_bci = method(thread)->bci_from(bcp(thread));
+  //  int caller_bci = last_frame.method()->bci_from(last_frame.bcp());
 
   // resolve method
   CallInfo info;
-  constantPoolHandle pool(thread, method(thread)->constants());
-  int index = get_index_u4(thread, bytecode);
+  constantPoolHandle pool(thread, last_frame.method()->constants());
+  int index = last_frame.get_index_u4(bytecode);
   {
     JvmtiHideSingleStepping jhss(thread);
     LinkResolver::resolve_invoke(info, Handle(), pool,
@@ -895,9 +905,9 @@
     // nm could have been unloaded so look it up again.  It's unsafe
     // to examine nm directly since it might have been freed and used
     // for something else.
-    frame fr = thread->last_frame();
-    Method* method =  fr.interpreter_frame_method();
-    int bci = method->bci_from(fr.interpreter_frame_bcp());
+    LastFrameAccessor last_frame(thread);
+    Method* method =  last_frame.method();
+    int bci = method->bci_from(last_frame.bcp());
     nm = method->lookup_osr_nmethod_for(bci, CompLevel_none, false);
   }
 #ifndef PRODUCT
@@ -917,11 +927,11 @@
   // flag, in case this method triggers classloading which will call into Java.
   UnlockFlagSaver fs(thread);
 
-  frame fr = thread->last_frame();
-  assert(fr.is_interpreted_frame(), "must come from interpreter");
-  methodHandle method(thread, fr.interpreter_frame_method());
+  LastFrameAccessor last_frame(thread);
+  assert(last_frame.is_interpreted_frame(), "must come from interpreter");
+  methodHandle method(thread, last_frame.method());
   const int branch_bci = branch_bcp != NULL ? method->bci_from(branch_bcp) : InvocationEntryBci;
-  const int bci = branch_bcp != NULL ? method->bci_from(fr.interpreter_frame_bcp()) : InvocationEntryBci;
+  const int bci = branch_bcp != NULL ? method->bci_from(last_frame.bcp()) : InvocationEntryBci;
 
   assert(!HAS_PENDING_EXCEPTION, "Should not have any exceptions pending");
   nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, NULL, thread);
@@ -937,9 +947,9 @@
     if (UseBiasedLocking) {
       ResourceMark rm;
       GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
-      for( BasicObjectLock *kptr = fr.interpreter_frame_monitor_end();
-           kptr < fr.interpreter_frame_monitor_begin();
-           kptr = fr.next_monitor_in_interpreter_frame(kptr) ) {
+      for( BasicObjectLock *kptr = last_frame.monitor_end();
+           kptr < last_frame.monitor_begin();
+           kptr = last_frame.next_monitor(kptr) ) {
         if( kptr->obj() != NULL ) {
           objects_to_revoke->append(Handle(THREAD, kptr->obj()));
         }
@@ -964,9 +974,9 @@
   UnlockFlagSaver fs(thread);
 
   assert(ProfileInterpreter, "must be profiling interpreter");
-  frame fr = thread->last_frame();
-  assert(fr.is_interpreted_frame(), "must come from interpreter");
-  methodHandle method(thread, fr.interpreter_frame_method());
+  LastFrameAccessor last_frame(thread);
+  assert(last_frame.is_interpreted_frame(), "must come from interpreter");
+  methodHandle method(thread, last_frame.method());
   Method::build_interpreter_method_data(method, THREAD);
   if (HAS_PENDING_EXCEPTION) {
     assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here");
@@ -1011,9 +1021,9 @@
   assert(ProfileInterpreter, "must be profiling interpreter");
   ResourceMark rm(thread);
   HandleMark hm(thread);
-  frame fr = thread->last_frame();
-  assert(fr.is_interpreted_frame(), "must come from interpreter");
-  MethodData* h_mdo = fr.interpreter_frame_method()->method_data();
+  LastFrameAccessor last_frame(thread);
+  assert(last_frame.is_interpreted_frame(), "must come from interpreter");
+  MethodData* h_mdo = last_frame.method()->method_data();
 
   // Grab a lock to ensure atomic access to setting the return bci and
   // the displacement.  This can block and GC, invalidating all naked oops.
@@ -1021,10 +1031,10 @@
 
   // ProfileData is essentially a wrapper around a derived oop, so we
   // need to take the lock before making any ProfileData structures.
-  ProfileData* data = h_mdo->data_at(h_mdo->dp_to_di(fr.interpreter_frame_mdp()));
+  ProfileData* data = h_mdo->data_at(h_mdo->dp_to_di(last_frame.mdp()));
   RetData* rdata = data->as_RetData();
   address new_mdp = rdata->fixup_ret(return_bci, h_mdo);
-  fr.interpreter_frame_set_mdp(new_mdp);
+  last_frame.set_mdp(new_mdp);
 IRT_END
 
 IRT_ENTRY(MethodCounters*, InterpreterRuntime::build_method_counters(JavaThread* thread, Method* m))
@@ -1049,7 +1059,8 @@
     // We are called during regular safepoints and when the VM is
     // single stepping. If any thread is marked for single stepping,
     // then we may have JVMTI work to do.
-    JvmtiExport::at_single_stepping_point(thread, method(thread), bcp(thread));
+    LastFrameAccessor last_frame(thread);
+    JvmtiExport::at_single_stepping_point(thread, last_frame.method(), last_frame.bcp());
   }
 IRT_END
 
@@ -1072,7 +1083,8 @@
   }
   InstanceKlass* cp_entry_f1 = InstanceKlass::cast(cp_entry->f1_as_klass());
   jfieldID fid = jfieldIDWorkaround::to_jfieldID(cp_entry_f1, cp_entry->f2_as_index(), is_static);
-  JvmtiExport::post_field_access(thread, method(thread), bcp(thread), cp_entry_f1, h_obj, fid);
+  LastFrameAccessor last_frame(thread);
+  JvmtiExport::post_field_access(thread, last_frame.method(), last_frame.bcp(), cp_entry_f1, h_obj, fid);
 IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread *thread,
@@ -1127,17 +1139,20 @@
     h_obj = Handle(thread, obj);
   }
 
-  JvmtiExport::post_raw_field_modification(thread, method(thread), bcp(thread), ik, h_obj,
+  LastFrameAccessor last_frame(thread);
+  JvmtiExport::post_raw_field_modification(thread, last_frame.method(), last_frame.bcp(), ik, h_obj,
                                            fid, sig_type, &fvalue);
 IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::post_method_entry(JavaThread *thread))
-  JvmtiExport::post_method_entry(thread, InterpreterRuntime::method(thread), InterpreterRuntime::last_frame(thread));
+  LastFrameAccessor last_frame(thread);
+  JvmtiExport::post_method_entry(thread, last_frame.method(), last_frame.get_frame());
 IRT_END
 
 
 IRT_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread))
-  JvmtiExport::post_method_exit(thread, InterpreterRuntime::method(thread), InterpreterRuntime::last_frame(thread));
+  LastFrameAccessor last_frame(thread);
+  JvmtiExport::post_method_exit(thread, last_frame.method(), last_frame.get_frame());
 IRT_END
 
 IRT_LEAF(int, InterpreterRuntime::interpreter_contains(address pc))
@@ -1362,10 +1377,10 @@
   ResetNoHandleMark rnm; // In a LEAF entry.
   HandleMark hm;
   ResourceMark rm;
-  frame fr = thread->last_frame();
-  assert(fr.is_interpreted_frame(), "");
-  jint bci = fr.interpreter_frame_bci();
-  methodHandle mh(thread, fr.interpreter_frame_method());
+  LastFrameAccessor last_frame(thread);
+  assert(last_frame.is_interpreted_frame(), "");
+  jint bci = last_frame.bci();
+  methodHandle mh(thread, last_frame.method());
   Bytecode_invoke invoke(mh, bci);
   ArgumentSizeComputer asc(invoke.signature());
   int size_of_arguments = (asc.size() + (invoke.has_receiver() ? 1 : 0)); // receiver
@@ -1411,10 +1426,10 @@
 // The generated code still uses call_VM because that will set up the frame pointer for
 // bcp and method.
 IRT_LEAF(intptr_t, InterpreterRuntime::trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2))
-  const frame f = thread->last_frame();
-  assert(f.is_interpreted_frame(), "must be an interpreted frame");
-  methodHandle mh(thread, f.interpreter_frame_method());
-  BytecodeTracer::trace(mh, f.interpreter_frame_bcp(), tos, tos2);
+  LastFrameAccessor last_frame(thread);
+  assert(last_frame.is_interpreted_frame(), "must be an interpreted frame");
+  methodHandle mh(thread, last_frame.method());
+  BytecodeTracer::trace(mh, last_frame.bcp(), tos, tos2);
   return preserve_this_value;
 IRT_END
 #endif // !PRODUCT
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp	Mon May 01 10:50:38 2017 -0400
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp	Mon May 01 11:16:01 2017 -0700
@@ -42,29 +42,54 @@
   friend class PrintingClosure; // for method and bcp
 
  private:
-  // Helper functions to access current interpreter state
-  static frame     last_frame(JavaThread *thread)    { return thread->last_frame(); }
-  static Method*   method(JavaThread *thread)        { return last_frame(thread).interpreter_frame_method(); }
-  static address   bcp(JavaThread *thread)           { return last_frame(thread).interpreter_frame_bcp(); }
-  static int       bci(JavaThread *thread)           { return last_frame(thread).interpreter_frame_bci(); }
-  static void      set_bcp_and_mdp(address bcp, JavaThread*thread);
-  static Bytecodes::Code code(JavaThread *thread)    {
+  // Helper class to access current interpreter state
+  class LastFrameAccessor : public StackObj {
+    frame _last_frame;
+  public:
+    LastFrameAccessor(JavaThread* thread) {
+      assert(thread == Thread::current(), "sanity");
+      _last_frame = thread->last_frame();
+    }
+    bool is_interpreted_frame() const              { return _last_frame.is_interpreted_frame(); }
+    Method*   method() const                       { return _last_frame.interpreter_frame_method(); }
+    address   bcp() const                          { return _last_frame.interpreter_frame_bcp(); }
+    int       bci() const                          { return _last_frame.interpreter_frame_bci(); }
+    address   mdp() const                          { return _last_frame.interpreter_frame_mdp(); }
+
+    void      set_bcp(address bcp)                 { _last_frame.interpreter_frame_set_bcp(bcp); }
+    void      set_mdp(address dp)                  { _last_frame.interpreter_frame_set_mdp(dp); }
+
     // pass method to avoid calling unsafe bcp_to_method (partial fix 4926272)
-    return Bytecodes::code_at(method(thread), bcp(thread));
-  }
-  static Bytecode  bytecode(JavaThread *thread)      { return Bytecode(method(thread), bcp(thread)); }
-  static int       get_index_u1(JavaThread *thread, Bytecodes::Code bc)
-                                                        { return bytecode(thread).get_index_u1(bc); }
-  static int       get_index_u2(JavaThread *thread, Bytecodes::Code bc)
-                                                        { return bytecode(thread).get_index_u2(bc); }
-  static int       get_index_u2_cpcache(JavaThread *thread, Bytecodes::Code bc)
-                                                        { return bytecode(thread).get_index_u2_cpcache(bc); }
-  static int       get_index_u4(JavaThread *thread, Bytecodes::Code bc)
-                                                        { return bytecode(thread).get_index_u4(bc); }
-  static int       number_of_dimensions(JavaThread *thread)  { return bcp(thread)[3]; }
+    Bytecodes::Code code() const                   { return Bytecodes::code_at(method(), bcp()); }
+
+    Bytecode  bytecode() const                     { return Bytecode(method(), bcp()); }
+    int get_index_u1(Bytecodes::Code bc) const     { return bytecode().get_index_u1(bc); }
+    int get_index_u2(Bytecodes::Code bc) const     { return bytecode().get_index_u2(bc); }
+    int get_index_u2_cpcache(Bytecodes::Code bc) const
+                                                   { return bytecode().get_index_u2_cpcache(bc); }
+    int get_index_u4(Bytecodes::Code bc) const     { return bytecode().get_index_u4(bc); }
+    int number_of_dimensions() const               { return bcp()[3]; }
+    ConstantPoolCacheEntry* cache_entry_at(int i) const
+                                                   { return method()->constants()->cache()->entry_at(i); }
+    ConstantPoolCacheEntry* cache_entry() const    { return cache_entry_at(Bytes::get_native_u2(bcp() + 1)); }
 
-  static ConstantPoolCacheEntry* cache_entry_at(JavaThread *thread, int i)  { return method(thread)->constants()->cache()->entry_at(i); }
-  static ConstantPoolCacheEntry* cache_entry(JavaThread *thread)            { return cache_entry_at(thread, Bytes::get_native_u2(bcp(thread) + 1)); }
+    oop callee_receiver(Symbol* signature) {
+      return _last_frame.interpreter_callee_receiver(signature);
+    }
+    BasicObjectLock* monitor_begin() const {
+      return _last_frame.interpreter_frame_monitor_end();
+    }
+    BasicObjectLock* monitor_end() const {
+      return _last_frame.interpreter_frame_monitor_begin();
+    }
+    BasicObjectLock* next_monitor(BasicObjectLock* current) const {
+      return _last_frame.next_monitor_in_interpreter_frame(current);
+    }
+
+    frame& get_frame()                             { return _last_frame; }
+  };
+
+  static void      set_bcp_and_mdp(address bcp, JavaThread*thread);
   static void      note_trap_inner(JavaThread* thread, int reason,
                                    methodHandle trap_method, int trap_bci, TRAPS);
   static void      note_trap(JavaThread *thread, int reason, TRAPS);
@@ -139,7 +164,7 @@
   static void _breakpoint(JavaThread* thread, Method* method, address bcp);
   static Bytecodes::Code get_original_bytecode_at(JavaThread* thread, Method* method, address bcp);
   static void            set_original_bytecode_at(JavaThread* thread, Method* method, address bcp, Bytecodes::Code new_code);
-  static bool is_breakpoint(JavaThread *thread) { return Bytecodes::code_or_bp_at(bcp(thread)) == Bytecodes::_breakpoint; }
+  static bool is_breakpoint(JavaThread *thread) { return Bytecodes::code_or_bp_at(LastFrameAccessor(thread).bcp()) == Bytecodes::_breakpoint; }
 
   // Safepoints
   static void    at_safepoint(JavaThread* thread);