# HG changeset patch # User iklam # Date 1509042909 25200 # Node ID 32d741a2b271d284d7ec2acf9baaeec93eb054dc # Parent 80ea7a4c64270fe073aca1af91c4b96df7cc9816 8179624: [REDO] Avoid repeated calls to JavaThread::last_frame in InterpreterRuntime Summary: fixed typo in the original patch (8179305) Reviewed-by: dlong, coleenp diff -r 80ea7a4c6427 -r 32d741a2b271 src/hotspot/share/interpreter/interpreterRuntime.cpp --- 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* objects_to_revoke = new GrowableArray(); - 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 diff -r 80ea7a4c6427 -r 32d741a2b271 src/hotspot/share/interpreter/interpreterRuntime.hpp --- 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);