8179624: [REDO] Avoid repeated calls to JavaThread::last_frame in InterpreterRuntime
authoriklam
Thu, 26 Oct 2017 11:35:09 -0700
changeset 47770 32d741a2b271
parent 47769 80ea7a4c6427
child 47771 8024fff2e247
8179624: [REDO] Avoid repeated calls to JavaThread::last_frame in InterpreterRuntime Summary: fixed typo in the original patch (8179305) Reviewed-by: dlong, coleenp
src/hotspot/share/interpreter/interpreterRuntime.cpp
src/hotspot/share/interpreter/interpreterRuntime.hpp
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp	Wed Nov 01 19:43:13 2017 -0400
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp	Thu Oct 26 11:35:09 2017 -0700
@@ -87,14 +87,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()));
     }
   }
 }
@@ -105,8 +106,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");
@@ -119,13 +121,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");
   }
@@ -182,10 +185,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");
 
@@ -217,8 +221,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.
@@ -257,8 +262,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);
 }
 
@@ -391,12 +397,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,16 +726,17 @@
 
 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 ||
       bytecode == Bytecodes::_invokespecial) {
     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() ||
@@ -737,12 +746,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;
@@ -754,14 +763,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
@@ -825,33 +834,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,
@@ -905,9 +916,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
@@ -927,11 +938,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);
@@ -947,9 +958,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()));
         }
@@ -974,9 +985,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");
@@ -1021,9 +1032,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.
@@ -1031,11 +1042,11 @@
 
   // 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()));
   guarantee(data != NULL, "profile data must be valid");
   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))
@@ -1060,7 +1071,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
 
@@ -1083,7 +1095,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,
@@ -1138,17 +1151,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))
@@ -1372,10 +1388,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
@@ -1421,10 +1437,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/src/hotspot/share/interpreter/interpreterRuntime.hpp	Wed Nov 01 19:43:13 2017 -0400
+++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp	Thu Oct 26 11:35:09 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_begin();
+    }
+    BasicObjectLock* monitor_end() const {
+      return _last_frame.interpreter_frame_monitor_end();
+    }
+    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,
                                    const 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);