diff options
42 files changed, 81 insertions, 3490 deletions
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc index 48f326a54d..3213bbe91a 100644 --- a/openjdkjvmti/OpenjdkJvmTi.cc +++ b/openjdkjvmti/OpenjdkJvmTi.cc @@ -313,10 +313,10 @@ class JvmtiFunctions { return StackUtil::GetFrameCount(env, thread, count_ptr); } - static jvmtiError PopFrame(jvmtiEnv* env, jthread thread) { + static jvmtiError PopFrame(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) { ENSURE_VALID_ENV(env); ENSURE_HAS_CAP(env, can_pop_frame); - return StackUtil::PopFrame(env, thread); + return ERR(NOT_IMPLEMENTED); } static jvmtiError GetFrameLocation(jvmtiEnv* env, diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h index 1218e3b9a7..82f3866c65 100644 --- a/openjdkjvmti/art_jvmti.h +++ b/openjdkjvmti/art_jvmti.h @@ -249,7 +249,7 @@ const jvmtiCapabilities kPotentialCapabilities = { .can_get_owned_monitor_info = 1, .can_get_current_contended_monitor = 1, .can_get_monitor_info = 1, - .can_pop_frame = 1, + .can_pop_frame = 0, .can_redefine_classes = 1, .can_signal_thread = 1, .can_get_source_file_name = 1, @@ -291,7 +291,6 @@ const jvmtiCapabilities kPotentialCapabilities = { // can_retransform_classes: // can_redefine_any_class: // can_redefine_classes: -// can_pop_frame: // We need to ensure that inlined code is either not present or can always be deoptimized. This // is not guaranteed for non-debuggable processes since we might have inlined bootclasspath code // on a threads stack. @@ -304,7 +303,7 @@ const jvmtiCapabilities kNonDebuggableUnsupportedCapabilities = { .can_get_owned_monitor_info = 0, .can_get_current_contended_monitor = 0, .can_get_monitor_info = 0, - .can_pop_frame = 1, + .can_pop_frame = 0, .can_redefine_classes = 1, .can_signal_thread = 0, .can_get_source_file_name = 0, diff --git a/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h index 7f3ec40d7e..e98517fdff 100644 --- a/openjdkjvmti/events-inl.h +++ b/openjdkjvmti/events-inl.h @@ -359,7 +359,6 @@ inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>( // have to deal with use-after-free or the frames being reallocated later. art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_); return env->notify_frames.erase(frame) != 0 && - !frame->GetForcePopFrame() && ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread); } @@ -554,7 +553,6 @@ inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env, : ArtJvmtiEvent::kClassFileLoadHookRetransformable; return (added && caps.can_access_local_variables == 1) || caps.can_generate_breakpoint_events == 1 || - caps.can_pop_frame == 1 || (caps.can_retransform_classes == 1 && IsEventEnabledAnywhere(event) && env->event_masks.IsEnabledAnywhere(event)); @@ -575,11 +573,6 @@ inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env, if (caps.can_generate_breakpoint_events == 1) { HandleBreakpointEventsChanged(added); } - if (caps.can_pop_frame == 1 && added) { - // TODO We should keep track of how many of these have been enabled and remove it if there are - // no more possible users. This isn't expected to be too common. - art::Runtime::Current()->SetNonStandardExitsEnabled(); - } } } diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc index 3ba5d3a316..220ad22be5 100644 --- a/openjdkjvmti/ti_stack.cc +++ b/openjdkjvmti/ti_stack.cc @@ -112,23 +112,6 @@ struct GetStackTraceVisitor : public art::StackVisitor { size_t stop; }; -art::ShadowFrame* FindFrameAtDepthVisitor::GetOrCreateShadowFrame(bool* created_frame) { - art::ShadowFrame* cur = GetCurrentShadowFrame(); - if (cur == nullptr) { - *created_frame = true; - art::ArtMethod* method = GetMethod(); - const uint16_t num_regs = method->DexInstructionData().RegistersSize(); - cur = GetThread()->FindOrCreateDebuggerShadowFrame(GetFrameId(), - num_regs, - method, - GetDexPc()); - DCHECK(cur != nullptr); - } else { - *created_frame = false; - } - return cur; -} - template <typename FrameFn> GetStackTraceVisitor<FrameFn> MakeStackTraceVisitor(art::Thread* thread_in, size_t start, @@ -1082,7 +1065,16 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) // From here we are sure to succeed. bool needs_instrument = false; // Get/create a shadow frame - art::ShadowFrame* shadow_frame = visitor.GetOrCreateShadowFrame(&needs_instrument); + art::ShadowFrame* shadow_frame = visitor.GetCurrentShadowFrame(); + if (shadow_frame == nullptr) { + needs_instrument = true; + const size_t frame_id = visitor.GetFrameId(); + const uint16_t num_regs = method->DexInstructionData().RegistersSize(); + shadow_frame = target->FindOrCreateDebuggerShadowFrame(frame_id, + num_regs, + method, + visitor.GetDexPc()); + } { art::WriterMutexLock lk(self, tienv->event_info_mutex_); // Mark shadow frame as needs_notify_pop_ @@ -1097,76 +1089,4 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) } while (true); } -jvmtiError StackUtil::PopFrame(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread thread) { - art::Thread* self = art::Thread::Current(); - art::Thread* target; - do { - ThreadUtil::SuspendCheck(self); - art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_); - // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by a - // user-code suspension. We retry and do another SuspendCheck to clear this. - if (ThreadUtil::WouldSuspendForUserCodeLocked(self)) { - continue; - } - // From now on we know we cannot get suspended by user-code. - // NB This does a SuspendCheck (during thread state change) so we need to make sure we don't - // have the 'suspend_lock' locked here. - art::ScopedObjectAccess soa(self); - art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_); - jvmtiError err = ERR(INTERNAL); - if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) { - return err; - } - { - art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_); - if (target == self || target->GetUserCodeSuspendCount() == 0) { - // We cannot be the current thread for this function. - return ERR(THREAD_NOT_SUSPENDED); - } - } - // We hold the user_code_suspension_lock_ so the target thread is staying suspended until we are - // done. - std::unique_ptr<art::Context> context(art::Context::Create()); - FindFrameAtDepthVisitor final_frame(target, context.get(), 0); - FindFrameAtDepthVisitor penultimate_frame(target, context.get(), 1); - final_frame.WalkStack(); - penultimate_frame.WalkStack(); - - if (!final_frame.FoundFrame() || !penultimate_frame.FoundFrame()) { - // Cannot do it if there is only one frame! - return ERR(NO_MORE_FRAMES); - } - - art::ArtMethod* called_method = final_frame.GetMethod(); - art::ArtMethod* calling_method = penultimate_frame.GetMethod(); - if (calling_method->IsNative() || called_method->IsNative()) { - return ERR(OPAQUE_FRAME); - } - // From here we are sure to succeed. - - // Get/create a shadow frame - bool created_final_frame = false; - bool created_penultimate_frame = false; - art::ShadowFrame* called_shadow_frame = - final_frame.GetOrCreateShadowFrame(&created_final_frame); - art::ShadowFrame* calling_shadow_frame = - penultimate_frame.GetOrCreateShadowFrame(&created_penultimate_frame); - - bool needs_instrument = created_penultimate_frame || created_final_frame; - - CHECK_NE(called_shadow_frame, calling_shadow_frame) - << "Frames at different depths not different!"; - - // Tell the shadow-frame to return immediately and skip all exit events. - called_shadow_frame->SetForcePopFrame(true); - calling_shadow_frame->SetForceRetryInstruction(true); - - // Make sure can we will go to the interpreter and use the shadow frames. - if (needs_instrument) { - art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(target); - } - return OK; - } while (true); -} - } // namespace openjdkjvmti diff --git a/openjdkjvmti/ti_stack.h b/openjdkjvmti/ti_stack.h index 55c4269086..b41fa4bf5a 100644 --- a/openjdkjvmti/ti_stack.h +++ b/openjdkjvmti/ti_stack.h @@ -81,8 +81,6 @@ class StackUtil { jobject** owned_monitors_ptr); static jvmtiError NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth); - - static jvmtiError PopFrame(jvmtiEnv* env, jthread thread); }; struct FindFrameAtDepthVisitor : art::StackVisitor { @@ -112,9 +110,6 @@ struct FindFrameAtDepthVisitor : art::StackVisitor { } } - art::ShadowFrame* GetOrCreateShadowFrame(/*out*/bool* created_frame) - REQUIRES_SHARED(art::Locks::mutator_lock_); - private: bool found_frame_; size_t cnt_; diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 15ab5f0387..c29043e7c6 100644 --- a/runtime/common_dex_operations.h +++ b/runtime/common_dex_operations.h @@ -27,7 +27,6 @@ #include "dex/primitive.h" #include "handle_scope-inl.h" #include "instrumentation.h" -#include "interpreter/interpreter.h" #include "interpreter/shadow_frame.h" #include "interpreter/unstarted_runtime.h" #include "jvalue-inl.h" @@ -173,14 +172,6 @@ ALWAYS_INLINE bool DoFieldPutCommon(Thread* self, if (UNLIKELY(self->IsExceptionPending())) { return false; } - if (shadow_frame.GetForcePopFrame()) { - // We need to check this here since we expect that the FieldWriteEvent happens before the - // actual field write. If one pops the stack we should not modify the field. The next - // instruction will force a pop. Return true. - DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); - DCHECK(interpreter::PrevFrameWillRetry(self, shadow_frame)); - return true; - } } switch (field_type) { diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 2ae95dcc41..df66061d01 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -261,12 +261,6 @@ static inline JValue Execute( shadow_frame.GetThisObject(accessor.InsSize()), method, 0); - if (UNLIKELY(shadow_frame.GetForcePopFrame())) { - // The caller will retry this invoke. Just return immediately without any value. - DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); - DCHECK(PrevFrameWillRetry(self, shadow_frame)); - return JValue(); - } if (UNLIKELY(self->IsExceptionPending())) { instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(accessor.InsSize()), @@ -500,8 +494,8 @@ void EnterInterpreterFromDeoptimize(Thread* self, JValue value; // Set value to last known result in case the shadow frame chain is empty. value.SetJ(ret_val->GetJ()); - // How many frames we have executed. - size_t frame_cnt = 0; + // Are we executing the first shadow frame? + bool first = true; while (shadow_frame != nullptr) { // We do not want to recover lock state for lock counting when deoptimizing. Currently, // the compiler should not have compiled a method that failed structured-locking checks. @@ -516,30 +510,24 @@ void EnterInterpreterFromDeoptimize(Thread* self, // the instrumentation. To prevent from reporting it a second time, we simply pass a // null Instrumentation*. const instrumentation::Instrumentation* const instrumentation = - frame_cnt == 0 ? nullptr : Runtime::Current()->GetInstrumentation(); + first ? nullptr : Runtime::Current()->GetInstrumentation(); new_dex_pc = MoveToExceptionHandler( self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex; } else if (!from_code) { // Deoptimization is not called from code directly. const Instruction* instr = &accessor.InstructionAt(dex_pc); - if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc || - shadow_frame->GetForceRetryInstruction()) { - DCHECK(frame_cnt == 0 || (frame_cnt == 1 && shadow_frame->GetForceRetryInstruction())) - << "frame_cnt: " << frame_cnt - << " force-retry: " << shadow_frame->GetForceRetryInstruction(); + if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) { + DCHECK(first); // Need to re-execute the dex instruction. // (1) An invocation might be split into class initialization and invoke. // In this case, the invoke should not be skipped. // (2) A suspend check should also execute the dex instruction at the // corresponding dex pc. - // If the ForceRetryInstruction bit is set this must be the second frame (the first being - // the one that is being popped). DCHECK_EQ(new_dex_pc, dex_pc); - shadow_frame->SetForceRetryInstruction(false); } else if (instr->Opcode() == Instruction::MONITOR_ENTER || instr->Opcode() == Instruction::MONITOR_EXIT) { DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - DCHECK_EQ(frame_cnt, 0u); + DCHECK(first); // Non-idempotent dex instruction should not be re-executed. // On the other hand, if a MONITOR_ENTER is at the dex_pc of a suspend // check, that MONITOR_ENTER should be executed. That case is handled @@ -565,7 +553,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, DCHECK_EQ(new_dex_pc, dex_pc); } else { DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - DCHECK_EQ(frame_cnt, 0u); + DCHECK(first); // By default, we re-execute the dex instruction since if they are not // an invoke, so that we don't have to decode the dex instruction to move // result into the right vreg. All slow paths have been audited to be @@ -578,7 +566,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, } else { // Nothing to do, the dex_pc is the one at which the code requested // the deoptimization. - DCHECK_EQ(frame_cnt, 0u); + DCHECK(first); DCHECK_EQ(new_dex_pc, dex_pc); } if (new_dex_pc != dex::kDexNoIndex) { @@ -597,7 +585,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, // and should advance dex pc past the invoke instruction. from_code = false; deopt_method_type = DeoptimizationMethodType::kDefault; - frame_cnt++; + first = false; } ret_val->SetJ(value.GetJ()); } @@ -669,18 +657,5 @@ void InitInterpreterTls(Thread* self) { InitMterpTls(self); } -bool PrevFrameWillRetry(Thread* self, const ShadowFrame& frame) { - ShadowFrame* prev_frame = frame.GetLink(); - if (prev_frame == nullptr) { - NthCallerVisitor vis(self, 1, false); - vis.WalkStack(); - prev_frame = vis.GetCurrentShadowFrame(); - if (prev_frame == nullptr) { - prev_frame = self->FindDebuggerShadowFrame(vis.GetFrameId()); - } - } - return prev_frame != nullptr && prev_frame->GetForceRetryInstruction(); -} - } // namespace interpreter } // namespace art diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index d7e69a6755..0d43b9090a 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -69,12 +69,6 @@ void CheckInterpreterAsmConstants(); void InitInterpreterTls(Thread* self); -// Returns true if the previous frame has the ForceRetryInstruction bit set. This is required for -// ForPopFrame to work correctly since that will cause the java function return with null/0 which -// might not be expected by the code being run. -bool PrevFrameWillRetry(Thread* self, const ShadowFrame& frame) - REQUIRES_SHARED(Locks::mutator_lock_); - } // namespace interpreter } // namespace art diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index dc3cc4585f..92d4731480 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -371,12 +371,6 @@ bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint1 if (UNLIKELY(self->IsExceptionPending())) { return false; } - if (UNLIKELY(shadow_frame.GetForcePopFrame())) { - // Don't actually set the field. The next instruction will force us to pop. - DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); - DCHECK(PrevFrameWillRetry(self, shadow_frame)); - return true; - } } // Note: iput-x-quick instructions are only for non-volatile fields. switch (field_type) { diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index c4b03b2563..27626295c1 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -23,39 +23,16 @@ #include "interpreter_common.h" #include "jit/jit.h" #include "jvalue-inl.h" -#include "nth_caller_visitor.h" #include "safe_math.h" #include "shadow_frame-inl.h" -#include "thread.h" namespace art { namespace interpreter { -#define CHECK_FORCE_RETURN() \ - do { \ - if (UNLIKELY(shadow_frame.GetForcePopFrame())) { \ - DCHECK(PrevFrameWillRetry(self, shadow_frame)) \ - << "Pop frame forced without previous frame ready to retry instruction!"; \ - DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); \ - if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) { \ - SendMethodExitEvents(self, \ - instrumentation, \ - shadow_frame, \ - shadow_frame.GetThisObject(accessor.InsSize()), \ - shadow_frame.GetMethod(), \ - inst->GetDexPc(insns), \ - JValue()); \ - } \ - ctx->result = JValue(); /* Handled in caller. */ \ - return; \ - } \ - } while (false) - #define HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instr) \ do { \ DCHECK(self->IsExceptionPending()); \ self->AllowThreadSuspension(); \ - CHECK_FORCE_RETURN(); \ if (!MoveToExceptionHandler(self, shadow_frame, instr)) { \ /* Structured locking is to be enforced for abnormal termination, too. */ \ DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame); \ @@ -66,7 +43,6 @@ namespace interpreter { ctx->result = JValue(); /* Handled in caller. */ \ return; \ } else { \ - CHECK_FORCE_RETURN(); \ int32_t displacement = \ static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc); \ inst = inst->RelativeAt(displacement); \ @@ -75,39 +51,8 @@ namespace interpreter { #define HANDLE_PENDING_EXCEPTION() HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instrumentation) -#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, _next_function) \ - do { \ - if (UNLIKELY(shadow_frame.GetForceRetryInstruction())) { \ - /* Don't need to do anything except clear the flag and exception. We leave the */ \ - /* instruction the same so it will be re-executed on the next go-around. */ \ - DCHECK(inst->IsInvoke()); \ - shadow_frame.SetForceRetryInstruction(false); \ - if (UNLIKELY(_is_exception_pending)) { \ - DCHECK(self->IsExceptionPending()); \ - if (kIsDebugBuild) { \ - LOG(WARNING) << "Suppressing exception for instruction-retry: " \ - << self->GetException()->Dump(); \ - } \ - self->ClearException(); \ - } \ - } else if (UNLIKELY(_is_exception_pending)) { \ - /* Should have succeeded. */ \ - DCHECK(!shadow_frame.GetForceRetryInstruction()); \ - HANDLE_PENDING_EXCEPTION(); \ - } else { \ - inst = inst->_next_function(); \ - } \ - } while (false) - -#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(_is_exception_pending) \ - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_4xx) -#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(_is_exception_pending) \ - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_3xx) - #define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _next_function) \ do { \ - /* Should only be on invoke instructions. */ \ - DCHECK(!shadow_frame.GetForceRetryInstruction()); \ if (UNLIKELY(_is_exception_pending)) { \ HANDLE_PENDING_EXCEPTION(); \ } else { \ @@ -121,22 +66,17 @@ namespace interpreter { } // Code to run before each dex instruction. -#define PREAMBLE_SAVE(save_ref) \ +#define PREAMBLE_SAVE(save_ref) \ { \ - /* We need to put this before & after the instrumentation to avoid having to put in a */ \ - /* post-script macro. */ \ - CHECK_FORCE_RETURN(); \ - if (UNLIKELY(instrumentation->HasDexPcListeners())) { \ - if (UNLIKELY(!DoDexPcMoveEvent(self, \ - accessor, \ - shadow_frame, \ - dex_pc, \ - instrumentation, \ - save_ref))) { \ - HANDLE_PENDING_EXCEPTION(); \ - break; \ - } \ - CHECK_FORCE_RETURN(); \ + if (UNLIKELY(instrumentation->HasDexPcListeners()) && \ + UNLIKELY(!DoDexPcMoveEvent(self, \ + accessor, \ + shadow_frame, \ + dex_pc, \ + instrumentation, \ + save_ref))) { \ + HANDLE_PENDING_EXCEPTION(); \ + break; \ } \ } \ do {} while (false) @@ -240,8 +180,7 @@ NO_INLINE static bool SendMethodExitEvents(Thread* self, const JValue& result) REQUIRES_SHARED(Locks::mutator_lock_) { bool had_event = false; - // We don't send method-exit if it's a pop-frame. We still send frame_popped though. - if (UNLIKELY(instrumentation->HasMethodExitListeners() && !frame.GetForcePopFrame())) { + if (UNLIKELY(instrumentation->HasMethodExitListeners())) { had_event = true; instrumentation->MethodExitEvent(self, thiz.Ptr(), method, dex_pc, result); } @@ -278,9 +217,6 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { uint16_t inst_data; jit::Jit* jit = Runtime::Current()->GetJit(); - DCHECK(!shadow_frame.GetForceRetryInstruction()) - << "Entered interpreter from invoke without retry instruction being handled!"; - do { dex_pc = inst->GetDexPc(insns); shadow_frame.SetDexPC(dex_pc); @@ -1667,84 +1603,84 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { PREAMBLE(); bool success = DoInvoke<kVirtual, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_VIRTUAL_RANGE: { PREAMBLE(); bool success = DoInvoke<kVirtual, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_SUPER: { PREAMBLE(); bool success = DoInvoke<kSuper, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_SUPER_RANGE: { PREAMBLE(); bool success = DoInvoke<kSuper, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_DIRECT: { PREAMBLE(); bool success = DoInvoke<kDirect, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_DIRECT_RANGE: { PREAMBLE(); bool success = DoInvoke<kDirect, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_INTERFACE: { PREAMBLE(); bool success = DoInvoke<kInterface, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_INTERFACE_RANGE: { PREAMBLE(); bool success = DoInvoke<kInterface, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_STATIC: { PREAMBLE(); bool success = DoInvoke<kStatic, false, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_STATIC_RANGE: { PREAMBLE(); bool success = DoInvoke<kStatic, true, do_access_check>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_VIRTUAL_QUICK: { PREAMBLE(); bool success = DoInvokeVirtualQuick<false>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { PREAMBLE(); bool success = DoInvokeVirtualQuick<true>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_POLYMORPHIC: { @@ -1752,7 +1688,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokePolymorphic<false /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx); break; } case Instruction::INVOKE_POLYMORPHIC_RANGE: { @@ -1760,7 +1696,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokePolymorphic<true /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx); break; } case Instruction::INVOKE_CUSTOM: { @@ -1768,7 +1704,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokeCustom<false /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::INVOKE_CUSTOM_RANGE: { @@ -1776,7 +1712,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); bool success = DoInvokeCustom<true /* is_range */>( self, shadow_frame, inst, inst_data, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::NEG_INT: diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index c385fb9417..fbc96f7e18 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -152,11 +152,6 @@ extern "C" size_t MterpShouldSwitchInterpreters() const instrumentation::Instrumentation* const instrumentation = runtime->GetInstrumentation(); return instrumentation->NonJitProfilingActive() || Dbg::IsDebuggerActive() || - // mterp only knows how to deal with the normal exits. It cannot handle any of the - // non-standard force-returns. - // TODO We really only need to switch interpreters if a PopFrame has actually happened. We - // should check this here. - UNLIKELY(runtime->AreNonStandardExitsEnabled()) || // An async exception has been thrown. We need to go to the switch interpreter. MTerp doesn't // know how to deal with these so we could end up never dealing with it if we are in an // infinite loop. Since this can be called in a tight loop and getting the current thread diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h index f57339986a..0e4cf27e50 100644 --- a/runtime/interpreter/shadow_frame.h +++ b/runtime/interpreter/shadow_frame.h @@ -49,17 +49,6 @@ using ShadowFrameAllocaUniquePtr = std::unique_ptr<ShadowFrame, ShadowFrameDelet // - interpreter - separate VRegs and reference arrays. References are in the reference array. // - JNI - just VRegs, but where every VReg holds a reference. class ShadowFrame { - private: - // Used to keep track of extra state the shadowframe has. - enum class FrameFlags : uint32_t { - // We have been requested to notify when this frame gets popped. - kNotifyFramePop = 1 << 0, - // We have been asked to pop this frame off the stack as soon as possible. - kForcePopFrame = 1 << 1, - // We have been asked to re-execute the last instruction. - kForceRetryInst = 1 << 2, - }; - public: // Compute size of ShadowFrame in bytes assuming it has a reference array. static size_t ComputeSize(uint32_t num_vregs) { @@ -356,27 +345,11 @@ class ShadowFrame { } bool NeedsNotifyPop() const { - return GetFrameFlag(FrameFlags::kNotifyFramePop); + return needs_notify_pop_; } void SetNotifyPop(bool notify) { - UpdateFrameFlag(notify, FrameFlags::kNotifyFramePop); - } - - bool GetForcePopFrame() const { - return GetFrameFlag(FrameFlags::kForcePopFrame); - } - - void SetForcePopFrame(bool enable) { - UpdateFrameFlag(enable, FrameFlags::kForcePopFrame); - } - - bool GetForceRetryInstruction() const { - return GetFrameFlag(FrameFlags::kForceRetryInst); - } - - void SetForceRetryInstruction(bool enable) { - UpdateFrameFlag(enable, FrameFlags::kForceRetryInst); + needs_notify_pop_ = notify; } private: @@ -391,7 +364,7 @@ class ShadowFrame { dex_pc_(dex_pc), cached_hotness_countdown_(0), hotness_countdown_(0), - frame_flags_(0) { + needs_notify_pop_(0) { // TODO(iam): Remove this parameter, it's an an artifact of portable removal DCHECK(has_reference_array); if (has_reference_array) { @@ -401,18 +374,6 @@ class ShadowFrame { } } - void UpdateFrameFlag(bool enable, FrameFlags flag) { - if (enable) { - frame_flags_ |= static_cast<uint32_t>(flag); - } else { - frame_flags_ &= ~static_cast<uint32_t>(flag); - } - } - - bool GetFrameFlag(FrameFlags flag) const { - return (frame_flags_ & static_cast<uint32_t>(flag)) != 0; - } - const StackReference<mirror::Object>* References() const { DCHECK(HasReferenceArray()); const uint32_t* vreg_end = &vregs_[NumberOfVRegs()]; @@ -436,11 +397,9 @@ class ShadowFrame { uint32_t dex_pc_; int16_t cached_hotness_countdown_; int16_t hotness_countdown_; - - // This is a set of ShadowFrame::FrameFlags which denote special states this frame is in. - // NB alignment requires that this field takes 4 bytes no matter its size. Only 3 bits are - // currently used. - uint32_t frame_flags_; + // TODO Might be worth it to try to bit-pack this into some other field to reduce stack usage. + // NB alignment requires that this field takes 4 bytes. Only 1 bit is actually ever used. + bool needs_notify_pop_; // This is a two-part array: // - [0..number_of_vregs) holds the raw virtual registers, and each element here is always 4 diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c8a2d77a1c..48c172edab 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -257,7 +257,6 @@ Runtime::Runtime() is_native_bridge_loaded_(false), is_native_debuggable_(false), async_exceptions_thrown_(false), - non_standard_exits_enabled_(false), is_java_debuggable_(false), zygote_max_failed_boots_(0), experimental_flags_(ExperimentalFlags::kNone), diff --git a/runtime/runtime.h b/runtime/runtime.h index 008ddf0272..f0bf7548af 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -655,14 +655,6 @@ class Runtime { is_native_debuggable_ = value; } - bool AreNonStandardExitsEnabled() const { - return non_standard_exits_enabled_; - } - - void SetNonStandardExitsEnabled() { - non_standard_exits_enabled_ = true; - } - bool AreAsyncExceptionsThrown() const { return async_exceptions_thrown_; } @@ -996,10 +988,6 @@ class Runtime { // MterpShouldSwitchInterpreters function. bool async_exceptions_thrown_; - // Whether anything is going to be using the shadow-frame APIs to force a function to return - // early. Doing this requires that (1) we be debuggable and (2) that mterp is exited. - bool non_standard_exits_enabled_; - // Whether Java code needs to be debuggable. bool is_java_debuggable_; diff --git a/runtime/thread.cc b/runtime/thread.cc index afb2c2850e..4a3d8cbf66 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3368,51 +3368,22 @@ void Thread::QuickDeliverException() { HandleWrapperObjPtr<mirror::Throwable> h_exception(hs.NewHandleWrapper(&exception)); instrumentation->ExceptionThrownEvent(this, exception.Ptr()); } - // Does instrumentation need to deoptimize the stack or otherwise go to interpreter for something? - // Note: we do this *after* reporting the exception to instrumentation in case it now requires - // deoptimization. It may happen if a debugger is attached and requests new events (single-step, - // breakpoint, ...) when the exception is reported. - ShadowFrame* cf; - bool force_frame_pop = false; - { - NthCallerVisitor visitor(this, 0, false); - visitor.WalkStack(); - cf = visitor.GetCurrentShadowFrame(); - if (cf == nullptr) { - cf = FindDebuggerShadowFrame(visitor.GetFrameId()); - } - force_frame_pop = cf != nullptr && cf->GetForcePopFrame(); - if (kIsDebugBuild && force_frame_pop) { - NthCallerVisitor penultimate_visitor(this, 1, false); - penultimate_visitor.WalkStack(); - ShadowFrame* penultimate_frame = penultimate_visitor.GetCurrentShadowFrame(); - if (penultimate_frame == nullptr) { - penultimate_frame = FindDebuggerShadowFrame(penultimate_visitor.GetFrameId()); - } - DCHECK(penultimate_frame != nullptr && - penultimate_frame->GetForceRetryInstruction()) - << "Force pop frame without retry instruction found. penultimate frame is null: " - << (penultimate_frame == nullptr ? "true" : "false"); - } - } - if (Dbg::IsForcedInterpreterNeededForException(this) || force_frame_pop) { + // Does instrumentation need to deoptimize the stack? + // Note: we do this *after* reporting the exception to instrumentation in case it + // now requires deoptimization. It may happen if a debugger is attached and requests + // new events (single-step, breakpoint, ...) when the exception is reported. + if (Dbg::IsForcedInterpreterNeededForException(this)) { NthCallerVisitor visitor(this, 0, false); visitor.WalkStack(); if (Runtime::Current()->IsAsyncDeoptimizeable(visitor.caller_pc)) { - VLOG(deopt) << "Deopting " << cf->GetMethod()->PrettyMethod() << " for frame-pop"; // method_type shouldn't matter due to exception handling. const DeoptimizationMethodType method_type = DeoptimizationMethodType::kDefault; // Save the exception into the deoptimization context so it can be restored // before entering the interpreter. - if (force_frame_pop) { - DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); - // Get rid of the exception since we are doing a framepop instead. - ClearException(); - } PushDeoptimizationContext( JValue(), false /* is_reference */, - (force_frame_pop ? nullptr : exception), + exception, false /* from_code */, method_type); artDeoptimize(this); diff --git a/test/1953-pop-frame/check b/test/1953-pop-frame/check deleted file mode 100755 index 3e379962dd..0000000000 --- a/test/1953-pop-frame/check +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2018 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# The RI has restrictions and bugs around some PopFrame behavior that ART lacks. -# See b/116003018. -if [[ "$TEST_RUNTIME" == "jvm" ]]; then - patch -p0 expected.txt < jvm-expected.patch >/dev/null -fi - -./default-check "$@" diff --git a/test/1953-pop-frame/expected.txt b/test/1953-pop-frame/expected.txt deleted file mode 100644 index dff7aeef76..0000000000 --- a/test/1953-pop-frame/expected.txt +++ /dev/null @@ -1,108 +0,0 @@ -Test stopped using breakpoint -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped using breakpoint with declared synchronized function -Single call with PopFrame on SynchronizedFunctionTestObject { cnt: 0 } base-call-count: 0 -result is SynchronizedFunctionTestObject { cnt: 2 } base-call count: 1 -Test stopped using breakpoint with synchronized block -Single call with PopFrame on SynchronizedTestObject { cnt: 0 } base-call-count: 0 -result is SynchronizedTestObject { cnt: 2 } base-call count: 1 -Test stopped on single step -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped on field access -Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0 -result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1 -Test stopped on field modification -Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0 -result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1 -Test stopped during Method Exit of doNothing -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during Method Enter of doNothing -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during Method Exit of calledFunction -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped during Method Enter of calledFunction -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during Method Exit due to exception thrown in same function -Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: false } base-call-count: 0 -result is ExceptionOnceObject { cnt: 2, throwInSub: false } base-call count: 1 -Test stopped during Method Exit due to exception thrown in subroutine -Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: true } base-call-count: 0 -result is ExceptionOnceObject { cnt: 2, throwInSub: true } base-call count: 1 -Test stopped during notifyFramePop without exception on pop of calledFunction -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped during notifyFramePop without exception on pop of doNothing -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during notifyFramePop with exception on pop of calledFunction -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError thrown and caught! -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during notifyFramePop with exception on pop of doThrow -Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionCatchTestObject$TestError caught in called function. -result is ExceptionCatchTestObject { cnt: 1 } base-call count: 1 -Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in called function) -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError caught in same function. -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in subroutine) -Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionCatchTestObject$TestError caught in called function. -result is ExceptionCatchTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in calling function) -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError thrown and caught! -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in called function) -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError caught in same function. -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in parent of calling function) -Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowFarTestObject$TestError thrown and caught! -result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in called function) -Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowFarTestObject$TestError caught in same function. -result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1 -Test stopped during a ClassLoad event. -Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0 -TC0.foo == 1 -result is ClassLoadObject { cnt: 2, curClass: 1} base-call count: 1 -Test stopped during a ClassPrepare event. -Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0 -TC1.foo == 2 -result is ClassLoadObject { cnt: 2, curClass: 2} base-call count: 1 -Test stopped during random Suspend. -Single call with PopFrame on SuspendSuddenlyObject { cnt: 0 } base-call-count: 0 -result is SuspendSuddenlyObject { cnt: 2 } base-call count: 1 -Test redefining frame being popped. -Single call with PopFrame on RedefineTestObject { states: [] current: ORIGINAL } base-call-count: 0 -result is RedefineTestObject { states: [ORIGINAL, REDEFINED] current: REDEFINED } base-call count: 1 -Test stopped during a native method fails -Single call with PopFrame on NativeCalledObject { cnt: 0 } base-call-count: 0 -Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME - art.Test1953.popFrame(Native Method) - art.Test1953.runTestOn(Test1953.java:103) - art.Test1953.runTestOn(Test1953.java:52) - art.Test1953.runTests(Test1953.java:858) - art.Test1953.run(Test1953.java:653) - <Additional frames hidden> -result is NativeCalledObject { cnt: 1 } base-call count: 1 -Test stopped in a method called by native fails -Single call with PopFrame on NativeCallerObject { cnt: 0 } base-call-count: 0 -Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME - art.Test1953.popFrame(Native Method) - art.Test1953.runTestOn(Test1953.java:103) - art.Test1953.runTestOn(Test1953.java:52) - art.Test1953.runTests(Test1953.java:864) - art.Test1953.run(Test1953.java:653) - <Additional frames hidden> -result is NativeCallerObject { cnt: 1 } base-call count: 1 diff --git a/test/1953-pop-frame/info.txt b/test/1953-pop-frame/info.txt deleted file mode 100644 index b5eb5464b7..0000000000 --- a/test/1953-pop-frame/info.txt +++ /dev/null @@ -1,7 +0,0 @@ -Test basic JVMTI breakpoint functionality. - -This test places a breakpoint on the first instruction of a number of functions -that are entered in every way possible for the given class of method. - -It also tests that breakpoints don't interfere with each other by having -multiple breakpoints be set at once. diff --git a/test/1953-pop-frame/jvm-expected.patch b/test/1953-pop-frame/jvm-expected.patch deleted file mode 100644 index ff482d12c1..0000000000 --- a/test/1953-pop-frame/jvm-expected.patch +++ /dev/null @@ -1,9 +0,0 @@ -75,82d74 -< Test stopped during a ClassLoad event. -< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0 -< TC0.foo == 1 -< result is ClassLoadObject { cnt: 2, curClass: 1} base-call count: 1 -< Test stopped during a ClassPrepare event. -< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0 -< TC1.foo == 2 -< result is ClassLoadObject { cnt: 2, curClass: 2} base-call count: 1 diff --git a/test/1953-pop-frame/pop_frame.cc b/test/1953-pop-frame/pop_frame.cc deleted file mode 100644 index 92c7057de7..0000000000 --- a/test/1953-pop-frame/pop_frame.cc +++ /dev/null @@ -1,971 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <inttypes.h> - -#include <cstdio> -#include <memory> -#include <string> -#include <vector> - -#include "android-base/logging.h" -#include "android-base/stringprintf.h" - -#include "jni.h" -#include "jvmti.h" -#include "scoped_local_ref.h" - -// Test infrastructure -#include "jni_binder.h" -#include "jni_helper.h" -#include "jvmti_helper.h" -#include "test_env.h" -#include "ti_macros.h" - -namespace art { -namespace Test1953PopFrame { - -struct TestData { - jlocation target_loc; - jmethodID target_method; - jclass target_klass; - jfieldID target_field; - jrawMonitorID notify_monitor; - jint frame_pop_offset; - jmethodID frame_pop_setup_method; - std::vector<std::string> interesting_classes; - bool hit_location; - - TestData(jvmtiEnv* jvmti, - JNIEnv* env, - jlocation loc, - jobject meth, - jclass klass, - jobject field, - jobject setup_meth, - jint pop_offset, - const std::vector<std::string>&& interesting) - : target_loc(loc), - target_method(meth != nullptr ? env->FromReflectedMethod(meth) : nullptr), - target_klass(reinterpret_cast<jclass>(env->NewGlobalRef(klass))), - target_field(field != nullptr ? env->FromReflectedField(field) : nullptr), - frame_pop_offset(pop_offset), - frame_pop_setup_method(setup_meth != nullptr ? env->FromReflectedMethod(setup_meth) - : nullptr), - interesting_classes(interesting), - hit_location(false) { - JvmtiErrorToException(env, jvmti, jvmti->CreateRawMonitor("SuspendStopMonitor", - ¬ify_monitor)); - } - - void PerformSuspend(jvmtiEnv* jvmti, JNIEnv* env) { - // Wake up the waiting thread. - JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(notify_monitor)); - hit_location = true; - JvmtiErrorToException(env, jvmti, jvmti->RawMonitorNotifyAll(notify_monitor)); - JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(notify_monitor)); - // Suspend ourself - jvmti->SuspendThread(nullptr); - } -}; - -void JNICALL cbSingleStep(jvmtiEnv* jvmti, - JNIEnv* env, - jthread thr, - jmethodID meth, - jlocation loc) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (meth != data->target_method || loc != data->target_loc) { - return; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbExceptionCatch(jvmtiEnv *jvmti, - JNIEnv* env, - jthread thr, - jmethodID method, - jlocation location ATTRIBUTE_UNUSED, - jobject exception ATTRIBUTE_UNUSED) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (method != data->target_method) { - return; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbException(jvmtiEnv *jvmti, - JNIEnv* env, - jthread thr, - jmethodID method, - jlocation location ATTRIBUTE_UNUSED, - jobject exception ATTRIBUTE_UNUSED, - jmethodID catch_method ATTRIBUTE_UNUSED, - jlocation catch_location ATTRIBUTE_UNUSED) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (method != data->target_method) { - return; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbMethodEntry(jvmtiEnv *jvmti, - JNIEnv* env, - jthread thr, - jmethodID method) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (method != data->target_method) { - return; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbMethodExit(jvmtiEnv *jvmti, - JNIEnv* env, - jthread thr, - jmethodID method, - jboolean was_popped_by_exception ATTRIBUTE_UNUSED, - jvalue return_value ATTRIBUTE_UNUSED) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (method != data->target_method) { - return; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbFieldModification(jvmtiEnv* jvmti, - JNIEnv* env, - jthread thr, - jmethodID method ATTRIBUTE_UNUSED, - jlocation location ATTRIBUTE_UNUSED, - jclass field_klass ATTRIBUTE_UNUSED, - jobject object ATTRIBUTE_UNUSED, - jfieldID field, - char signature_type ATTRIBUTE_UNUSED, - jvalue new_value ATTRIBUTE_UNUSED) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (field != data->target_field) { - // TODO What to do here. - LOG(FATAL) << "Strange, shouldn't get here!"; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbFieldAccess(jvmtiEnv* jvmti, - JNIEnv* env, - jthread thr, - jmethodID method ATTRIBUTE_UNUSED, - jlocation location ATTRIBUTE_UNUSED, - jclass field_klass, - jobject object ATTRIBUTE_UNUSED, - jfieldID field) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (field != data->target_field || !env->IsSameObject(field_klass, data->target_klass)) { - // TODO What to do here. - LOG(FATAL) << "Strange, shouldn't get here!"; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbBreakpointHit(jvmtiEnv* jvmti, - JNIEnv* env, - jthread thr, - jmethodID method, - jlocation loc) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (data->frame_pop_setup_method == method) { - CHECK(loc == 0) << "We should have stopped at location 0"; - if (JvmtiErrorToException(env, - jvmti, - jvmti->NotifyFramePop(thr, data->frame_pop_offset))) { - return; - } - return; - } - if (method != data->target_method || loc != data->target_loc) { - // TODO What to do here. - LOG(FATAL) << "Strange, shouldn't get here!"; - } - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbFramePop(jvmtiEnv* jvmti, - JNIEnv* env, - jthread thr, - jmethodID method ATTRIBUTE_UNUSED, - jboolean was_popped_by_exception ATTRIBUTE_UNUSED) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - data->PerformSuspend(jvmti, env); -} - -void JNICALL cbClassLoadOrPrepare(jvmtiEnv* jvmti, - JNIEnv* env, - jthread thr, - jclass klass) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti, - jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - char* name; - if (JvmtiErrorToException(env, jvmti, jvmti->GetClassSignature(klass, &name, nullptr))) { - return; - } - std::string name_str(name); - if (JvmtiErrorToException(env, - jvmti, - jvmti->Deallocate(reinterpret_cast<unsigned char*>(name)))) { - return; - } - if (std::find(data->interesting_classes.cbegin(), - data->interesting_classes.cend(), - name_str) != data->interesting_classes.cend()) { - data->PerformSuspend(jvmti, env); - } -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupTest(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { - jvmtiCapabilities caps; - memset(&caps, 0, sizeof(caps)); - // Most of these will already be there but might as well be complete. - caps.can_pop_frame = 1; - caps.can_generate_single_step_events = 1; - caps.can_generate_breakpoint_events = 1; - caps.can_suspend = 1; - caps.can_generate_method_entry_events = 1; - caps.can_generate_method_exit_events = 1; - caps.can_generate_monitor_events = 1; - caps.can_generate_exception_events = 1; - caps.can_generate_frame_pop_events = 1; - caps.can_generate_field_access_events = 1; - caps.can_generate_field_modification_events = 1; - caps.can_redefine_classes = 1; - if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) { - return; - } - jvmtiEventCallbacks cb; - memset(&cb, 0, sizeof(cb)); - // TODO Add the rest of these. - cb.Breakpoint = cbBreakpointHit; - cb.SingleStep = cbSingleStep; - cb.FieldAccess = cbFieldAccess; - cb.FieldModification = cbFieldModification; - cb.MethodEntry = cbMethodEntry; - cb.MethodExit = cbMethodExit; - cb.Exception = cbException; - cb.ExceptionCatch = cbExceptionCatch; - cb.FramePop = cbFramePop; - cb.ClassLoad = cbClassLoadOrPrepare; - cb.ClassPrepare = cbClassLoadOrPrepare; - JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb))); -} - -static bool DeleteTestData(JNIEnv* env, jthread thr, TestData* data) { - env->DeleteGlobalRef(data->target_klass); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, nullptr))) { - return false; - } - return JvmtiErrorToException(env, - jvmti_env, - jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data))); -} - -static TestData* SetupTestData(JNIEnv* env, - jobject meth, - jlocation loc, - jclass target_klass, - jobject field, - jobject setup_meth, - jint pop_offset, - const std::vector<std::string>&& interesting_names) { - void* data_ptr; - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->Allocate(sizeof(TestData), - reinterpret_cast<uint8_t**>(&data_ptr)))) { - return nullptr; - } - data = new (data_ptr) TestData(jvmti_env, - env, - loc, - meth, - target_klass, - field, - setup_meth, - pop_offset, - std::move(interesting_names)); - if (env->ExceptionCheck()) { - env->DeleteGlobalRef(data->target_klass); - jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data)); - return nullptr; - } - return data; -} - -static TestData* SetupTestData(JNIEnv* env, - jobject meth, - jlocation loc, - jclass target_klass, - jobject field, - jobject setup_meth, - jint pop_offset) { - std::vector<std::string> empty; - return SetupTestData( - env, meth, loc, target_klass, field, setup_meth, pop_offset, std::move(empty)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupSuspendClassEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jint event_num, - jobjectArray interesting_names, - jthread thr) { - CHECK(event_num == JVMTI_EVENT_CLASS_LOAD || event_num == JVMTI_EVENT_CLASS_PREPARE); - std::vector<std::string> names; - jint cnt = env->GetArrayLength(interesting_names); - for (jint i = 0; i < cnt; i++) { - env->PushLocalFrame(1); - jstring name_obj = reinterpret_cast<jstring>(env->GetObjectArrayElement(interesting_names, i)); - const char* name_chr = env->GetStringUTFChars(name_obj, nullptr); - names.push_back(std::string(name_chr)); - env->ReleaseStringUTFChars(name_obj, name_chr); - env->PopLocalFrame(nullptr); - } - TestData* data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0, std::move(names)); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - static_cast<jvmtiEvent>(event_num), - thr)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearSuspendClassEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_CLASS_LOAD, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_CLASS_PREPARE, - thr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupSuspendSingleStepAt(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jobject meth, - jlocation loc, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_SINGLE_STEP, - thr)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearSuspendSingleStepFor(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_SINGLE_STEP, - thr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupSuspendPopFrameEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jint offset, - jobject breakpoint_func, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, nullptr, 0, nullptr, nullptr, breakpoint_func, offset); - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_FRAME_POP, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_BREAKPOINT, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetBreakpoint(data->frame_pop_setup_method, 0))) { - return; - } -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearSuspendPopFrameEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_FRAME_POP, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_BREAKPOINT, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->ClearBreakpoint(data->frame_pop_setup_method, 0))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupSuspendBreakpointFor(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jobject meth, - jlocation loc, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_BREAKPOINT, - thr))) { - return; - } - JvmtiErrorToException(env, jvmti_env, jvmti_env->SetBreakpoint(data->target_method, - data->target_loc)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearSuspendBreakpointFor(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_BREAKPOINT, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->ClearBreakpoint(data->target_method, - data->target_loc))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, nullptr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupSuspendExceptionEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jobject method, - jboolean is_catch, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage( - thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode( - JVMTI_ENABLE, - is_catch ? JVMTI_EVENT_EXCEPTION_CATCH : JVMTI_EVENT_EXCEPTION, - thr)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearSuspendExceptionEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_EXCEPTION_CATCH, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_EXCEPTION, - thr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupSuspendMethodEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jobject method, - jboolean enter, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage( - thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode( - JVMTI_ENABLE, - enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT, - thr)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearSuspendMethodEvent(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_METHOD_EXIT, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_METHOD_ENTRY, - thr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupFieldSuspendFor(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jclass target_klass, - jobject field, - jboolean access, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage( - thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, nullptr, 0, target_klass, field, nullptr, 0); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode( - JVMTI_ENABLE, - access ? JVMTI_EVENT_FIELD_ACCESS : JVMTI_EVENT_FIELD_MODIFICATION, - thr))) { - return; - } - if (access) { - JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldAccessWatch(data->target_klass, - data->target_field)); - } else { - JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldModificationWatch(data->target_klass, - data->target_field)); - } -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearFieldSuspendFor(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_FIELD_ACCESS, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_FIELD_MODIFICATION, - thr))) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->ClearFieldModificationWatch( - data->target_klass, data->target_field)) && - JvmtiErrorToException(env, - jvmti_env, - jvmti_env->ClearFieldAccessWatch( - data->target_klass, data->target_field))) { - return; - } else { - env->ExceptionClear(); - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, nullptr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_setupWaitForNativeCall(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage( - thr, reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data == nullptr) << "Data was not cleared!"; - data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0); - if (data == nullptr) { - return; - } - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, data))) { - return; - } -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_clearWaitForNativeCall(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->SetThreadLocalStorage(thr, nullptr))) { - return; - } - DeleteTestData(env, thr, data); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_waitForSuspendHit(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(thr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(data->notify_monitor))) { - return; - } - while (!data->hit_location) { - if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorWait(data->notify_monitor, -1))) { - return; - } - } - if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(data->notify_monitor))) { - return; - } - jint state = 0; - while (!JvmtiErrorToException(env, jvmti_env, jvmti_env->GetThreadState(thr, &state)) && - (state & JVMTI_THREAD_STATE_SUSPENDED) == 0) { } -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_popFrame(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jthread thr) { - JvmtiErrorToException(env, jvmti_env, jvmti_env->PopFrame(thr)); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_00024NativeCalledObject_calledFunction( - JNIEnv* env, jobject thiz) { - env->PushLocalFrame(1); - jclass klass = env->GetObjectClass(thiz); - jfieldID cnt = env->GetFieldID(klass, "cnt", "I"); - env->SetIntField(thiz, cnt, env->GetIntField(thiz, cnt) + 1); - env->PopLocalFrame(nullptr); - TestData *data; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetThreadLocalStorage(/* thread */ nullptr, - reinterpret_cast<void**>(&data)))) { - return; - } - CHECK(data != nullptr); - data->PerformSuspend(jvmti_env, env); -} - -extern "C" JNIEXPORT -void JNICALL Java_art_Test1953_00024NativeCallerObject_run( - JNIEnv* env, jobject thiz) { - env->PushLocalFrame(1); - jclass klass = env->GetObjectClass(thiz); - jfieldID baseCnt = env->GetFieldID(klass, "baseCnt", "I"); - env->SetIntField(thiz, baseCnt, env->GetIntField(thiz, baseCnt) + 1); - jmethodID called = env->GetMethodID(klass, "calledFunction", "()V"); - env->CallVoidMethod(thiz, called); - env->PopLocalFrame(nullptr); -} - -} // namespace Test1953PopFrame -} // namespace art - diff --git a/test/1953-pop-frame/run b/test/1953-pop-frame/run deleted file mode 100755 index 51875a7e86..0000000000 --- a/test/1953-pop-frame/run +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Ask for stack traces to be dumped to a file rather than to stdout. -./default-run "$@" --jvmti diff --git a/test/1953-pop-frame/src/Main.java b/test/1953-pop-frame/src/Main.java deleted file mode 100644 index 5c364ec858..0000000000 --- a/test/1953-pop-frame/src/Main.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -public class Main { - public static void main(String[] args) throws Exception { - art.Test1953.run(); - } -} diff --git a/test/1953-pop-frame/src/art/Breakpoint.java b/test/1953-pop-frame/src/art/Breakpoint.java deleted file mode 100644 index bbb89f707f..0000000000 --- a/test/1953-pop-frame/src/art/Breakpoint.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.lang.reflect.Executable; -import java.util.HashSet; -import java.util.Set; -import java.util.Objects; - -public class Breakpoint { - public static class Manager { - public static class BP { - public final Executable method; - public final long location; - - public BP(Executable method) { - this(method, getStartLocation(method)); - } - - public BP(Executable method, long location) { - this.method = method; - this.location = location; - } - - @Override - public boolean equals(Object other) { - return (other instanceof BP) && - method.equals(((BP)other).method) && - location == ((BP)other).location; - } - - @Override - public String toString() { - return method.toString() + " @ " + getLine(); - } - - @Override - public int hashCode() { - return Objects.hash(method, location); - } - - public int getLine() { - try { - LineNumber[] lines = getLineNumberTable(method); - int best = -1; - for (LineNumber l : lines) { - if (l.location > location) { - break; - } else { - best = l.line; - } - } - return best; - } catch (Exception e) { - return -1; - } - } - } - - private Set<BP> breaks = new HashSet<>(); - - public void setBreakpoints(BP... bs) { - for (BP b : bs) { - if (breaks.add(b)) { - Breakpoint.setBreakpoint(b.method, b.location); - } - } - } - public void setBreakpoint(Executable method, long location) { - setBreakpoints(new BP(method, location)); - } - - public void clearBreakpoints(BP... bs) { - for (BP b : bs) { - if (breaks.remove(b)) { - Breakpoint.clearBreakpoint(b.method, b.location); - } - } - } - public void clearBreakpoint(Executable method, long location) { - clearBreakpoints(new BP(method, location)); - } - - public void clearAllBreakpoints() { - clearBreakpoints(breaks.toArray(new BP[0])); - } - } - - public static void startBreakpointWatch(Class<?> methodClass, - Executable breakpointReached, - Thread thr) { - startBreakpointWatch(methodClass, breakpointReached, false, thr); - } - - /** - * Enables the trapping of breakpoint events. - * - * If allowRecursive == true then breakpoints will be sent even if one is currently being handled. - */ - public static native void startBreakpointWatch(Class<?> methodClass, - Executable breakpointReached, - boolean allowRecursive, - Thread thr); - public static native void stopBreakpointWatch(Thread thr); - - public static final class LineNumber implements Comparable<LineNumber> { - public final long location; - public final int line; - - private LineNumber(long loc, int line) { - this.location = loc; - this.line = line; - } - - public boolean equals(Object other) { - return other instanceof LineNumber && ((LineNumber)other).line == line && - ((LineNumber)other).location == location; - } - - public int compareTo(LineNumber other) { - int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line)); - if (v != 0) { - return v; - } else { - return Long.valueOf(location).compareTo(Long.valueOf(other.location)); - } - } - } - - public static native void setBreakpoint(Executable m, long loc); - public static void setBreakpoint(Executable m, LineNumber l) { - setBreakpoint(m, l.location); - } - - public static native void clearBreakpoint(Executable m, long loc); - public static void clearBreakpoint(Executable m, LineNumber l) { - clearBreakpoint(m, l.location); - } - - private static native Object[] getLineNumberTableNative(Executable m); - public static LineNumber[] getLineNumberTable(Executable m) { - Object[] nativeTable = getLineNumberTableNative(m); - long[] location = (long[])(nativeTable[0]); - int[] lines = (int[])(nativeTable[1]); - if (lines.length != location.length) { - throw new Error("Lines and locations have different lengths!"); - } - LineNumber[] out = new LineNumber[lines.length]; - for (int i = 0; i < lines.length; i++) { - out[i] = new LineNumber(location[i], lines[i]); - } - return out; - } - - public static native long getStartLocation(Executable m); - - public static int locationToLine(Executable m, long location) { - try { - Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); - int best = -1; - for (Breakpoint.LineNumber l : lines) { - if (l.location > location) { - break; - } else { - best = l.line; - } - } - return best; - } catch (Exception e) { - return -1; - } - } - - public static long lineToLocation(Executable m, int line) throws Exception { - try { - Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); - for (Breakpoint.LineNumber l : lines) { - if (l.line == line) { - return l.location; - } - } - throw new Exception("Unable to find line " + line + " in " + m); - } catch (Exception e) { - throw new Exception("Unable to get line number info for " + m, e); - } - } -} - diff --git a/test/1953-pop-frame/src/art/Redefinition.java b/test/1953-pop-frame/src/art/Redefinition.java deleted file mode 100644 index 56d2938a01..0000000000 --- a/test/1953-pop-frame/src/art/Redefinition.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.util.ArrayList; -// Common Redefinition functions. Placed here for use by CTS -public class Redefinition { - public static final class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; - - public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } - } - - // A set of possible test configurations. Test should set this if they need to. - // This must be kept in sync with the defines in ti-agent/common_helper.cc - public static enum Config { - COMMON_REDEFINE(0), - COMMON_RETRANSFORM(1), - COMMON_TRANSFORM(2); - - private final int val; - private Config(int val) { - this.val = val; - } - } - - public static void setTestConfiguration(Config type) { - nativeSetTestConfiguration(type.val); - } - - private static native void nativeSetTestConfiguration(int type); - - // Transforms the class - public static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - public static void addMultiTransformationResults(CommonClassDefinition... defs) { - for (CommonClassDefinition d : defs) { - addCommonTransformationResult(d.target.getCanonicalName(), - d.class_file_bytes, - d.dex_file_bytes); - } - } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); - public static native void doCommonClassRetransformation(Class<?>... target); - public static native void setPopRetransformations(boolean pop); - public static native void popTransformationFor(String name); - public static native void enableCommonRetransformation(boolean enable); - public static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); -} diff --git a/test/1953-pop-frame/src/art/StackTrace.java b/test/1953-pop-frame/src/art/StackTrace.java deleted file mode 100644 index 2ea2f201e8..0000000000 --- a/test/1953-pop-frame/src/art/StackTrace.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.lang.reflect.Field; -import java.lang.reflect.Executable; - -public class StackTrace { - public static class StackFrameData { - public final Thread thr; - public final Executable method; - public final long current_location; - public final int depth; - - public StackFrameData(Thread thr, Executable e, long loc, int depth) { - this.thr = thr; - this.method = e; - this.current_location = loc; - this.depth = depth; - } - @Override - public String toString() { - return String.format( - "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }", - this.thr, - this.method, - this.current_location, - this.depth); - } - } - - public static native int GetStackDepth(Thread thr); - - private static native StackFrameData[] nativeGetStackTrace(Thread thr); - - public static StackFrameData[] GetStackTrace(Thread thr) { - // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not - // suspended. The spec says that not being suspended is fine but since we want this to be - // consistent we will suspend for the RI. - boolean suspend_thread = - !System.getProperty("java.vm.name").equals("Dalvik") && - !thr.equals(Thread.currentThread()) && - !Suspension.isSuspended(thr); - if (suspend_thread) { - Suspension.suspend(thr); - } - StackFrameData[] out = nativeGetStackTrace(thr); - if (suspend_thread) { - Suspension.resume(thr); - } - return out; - } -} - diff --git a/test/1953-pop-frame/src/art/Suspension.java b/test/1953-pop-frame/src/art/Suspension.java deleted file mode 100644 index 16e62ccac9..0000000000 --- a/test/1953-pop-frame/src/art/Suspension.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -public class Suspension { - // Suspends a thread using jvmti. - public native static void suspend(Thread thr); - - // Resumes a thread using jvmti. - public native static void resume(Thread thr); - - public native static boolean isSuspended(Thread thr); - - public native static int[] suspendList(Thread... threads); - public native static int[] resumeList(Thread... threads); -} diff --git a/test/1953-pop-frame/src/art/Test1953.java b/test/1953-pop-frame/src/art/Test1953.java deleted file mode 100644 index 95ec6982b1..0000000000 --- a/test/1953-pop-frame/src/art/Test1953.java +++ /dev/null @@ -1,902 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Base64; -import java.util.EnumSet; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class Test1953 { - public static final boolean IS_ART = System.getProperty("java.vm.name").equals("Dalvik"); - public static void doNothing() {} - - public interface TestRunnable extends Runnable { - public int getBaseCallCount(); - } - - public static interface TestSuspender { - public void setup(Thread thr); - public void waitForSuspend(Thread thr); - public void cleanup(Thread thr); - } - - public static interface ThreadRunnable { public void run(Thread thr); } - public static TestSuspender makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean) { - return new TestSuspender() { - public void setup(Thread thr) { setup.run(thr); } - public void waitForSuspend(Thread thr) { Test1953.waitForSuspendHit(thr); } - public void cleanup(Thread thr) { clean.run(thr); } - }; - } - - public void runTestOn(TestRunnable testObj, ThreadRunnable su, ThreadRunnable cl) throws - Exception { - runTestOn(testObj, makeSuspend(su, cl)); - } - - private static void SafePrintStackTrace(StackTraceElement st[]) { - for (StackTraceElement e : st) { - if (e.getClassName().contains("Test1953")) { - System.out.println("\t" + e); - } else { - System.out.println("\t<Additional frames hidden>"); - break; - } - } - } - - public void runTestOn(TestRunnable testObj, TestSuspender su) throws Exception { - System.out.println("Single call with PopFrame on " + testObj + " base-call-count: " + - testObj.getBaseCallCount()); - final CountDownLatch continue_latch = new CountDownLatch(1); - final CountDownLatch startup_latch = new CountDownLatch(1); - Runnable await = () -> { - try { - startup_latch.countDown(); - continue_latch.await(); - } catch (Exception e) { - throw new Error("Failed to await latch", e); - } - }; - Thread thr = new Thread(() -> { await.run(); testObj.run(); }); - thr.start(); - - // Wait until the other thread is started. - startup_latch.await(); - - // Do any final setup. - preTest.accept(testObj); - - // Setup suspension method on the thread. - su.setup(thr); - - // Let the other thread go. - continue_latch.countDown(); - - // Wait for the other thread to hit the breakpoint/watchpoint/whatever and suspend itself - // (without re-entering java) - su.waitForSuspend(thr); - - // Cleanup the breakpoint/watchpoint/etc. - su.cleanup(thr); - - try { - // Pop the frame. - popFrame(thr); - } catch (Exception e) { - System.out.println("Failed to pop frame due to " + e); - SafePrintStackTrace(e.getStackTrace()); - } - - // Start the other thread going again. - Suspension.resume(thr); - - // Wait for the other thread to finish. - thr.join(); - - // See how many times calledFunction was called. - System.out.println("result is " + testObj + " base-call count: " + testObj.getBaseCallCount()); - } - - public static abstract class AbstractTestObject implements TestRunnable { - public int callerCnt; - - public AbstractTestObject() { - callerCnt = 0; - } - - public int getBaseCallCount() { - return callerCnt; - } - - public void run() { - callerCnt++; - // This function should be re-executed by the popFrame. - calledFunction(); - } - - public abstract void calledFunction(); - } - - public static class RedefineTestObject extends AbstractTestObject implements Runnable { - public static enum RedefineState { ORIGINAL, REDEFINED, }; - /* public static class RedefineTestObject extends AbstractTestObject implements Runnable { - * public static final byte[] CLASS_BYTES; - * public static final byte[] DEX_BYTES; - * static { - * CLASS_BYTES = null; - * DEX_BYTES = null; - * } - * - * public EnumSet<RedefineState> redefine_states; - * public RedefineTestObject() { - * super(); - * redefine_states = EnumSet.noneOf(RedefineState.class); - * } - * public String toString() { - * return "RedefineTestObject { states: " + redefine_states.toString() - * + " current: REDEFINED }"; - * } - * public void calledFunction() { - * redefine_states.add(RedefineState.REDEFINED); // line +0 - * // We will trigger the redefinition using a breakpoint on the next line. - * doNothing(); // line +2 - * } - * } - */ - public static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADUATQoADQAjBwAkCgAlACYJAAwAJwoAJQAoEgAAACwJAAIALQoAJQAuCgAvADAJAAwA" + - "MQkADAAyBwAzBwA0BwA2AQASUmVkZWZpbmVUZXN0T2JqZWN0AQAMSW5uZXJDbGFzc2VzAQANUmVk" + - "ZWZpbmVTdGF0ZQEAC0NMQVNTX0JZVEVTAQACW0IBAAlERVhfQllURVMBAA9yZWRlZmluZV9zdGF0" + - "ZXMBABNMamF2YS91dGlsL0VudW1TZXQ7AQAJU2lnbmF0dXJlAQBETGphdmEvdXRpbC9FbnVtU2V0" + - "PExhcnQvVGVzdDE5NTMkUmVkZWZpbmVUZXN0T2JqZWN0JFJlZGVmaW5lU3RhdGU7PjsBAAY8aW5p" + - "dD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xh" + - "bmcvU3RyaW5nOwEADmNhbGxlZEZ1bmN0aW9uAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQANVGVz" + - "dDE5NTMuamF2YQwAGQAaAQAtYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmlu" + - "ZVN0YXRlBwA3DAA4ADkMABUAFgwAHQAeAQAQQm9vdHN0cmFwTWV0aG9kcw8GADoIADsMADwAPQwA" + - "PgA/DABAAEEHAEIMAEMAGgwAEgATDAAUABMBAB9hcnQvVGVzdDE5NTMkUmVkZWZpbmVUZXN0T2Jq" + - "ZWN0AQAfYXJ0L1Rlc3QxOTUzJEFic3RyYWN0VGVzdE9iamVjdAEAEkFic3RyYWN0VGVzdE9iamVj" + - "dAEAEmphdmEvbGFuZy9SdW5uYWJsZQEAEWphdmEvdXRpbC9FbnVtU2V0AQAGbm9uZU9mAQAmKExq" + - "YXZhL2xhbmcvQ2xhc3M7KUxqYXZhL3V0aWwvRW51bVNldDsKAEQARQEAM1JlZGVmaW5lVGVzdE9i" + - "amVjdCB7IHN0YXRlczogASBjdXJyZW50OiBSRURFRklORUQgfQEAF21ha2VDb25jYXRXaXRoQ29u" + - "c3RhbnRzAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAlSRURFRklO" + - "RUQBAC9MYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmluZVN0YXRlOwEAA2Fk" + - "ZAEAFShMamF2YS9sYW5nL09iamVjdDspWgEADGFydC9UZXN0MTk1MwEACWRvTm90aGluZwcARgwA" + - "PABJAQAkamF2YS9sYW5nL2ludm9rZS9TdHJpbmdDb25jYXRGYWN0b3J5BwBLAQAGTG9va3VwAQCY" + - "KExqYXZhL2xhbmcvaW52b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwO0xqYXZhL2xhbmcvU3RyaW5n" + - "O0xqYXZhL2xhbmcvaW52b2tlL01ldGhvZFR5cGU7TGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xh" + - "bmcvT2JqZWN0OylMamF2YS9sYW5nL2ludm9rZS9DYWxsU2l0ZTsHAEwBACVqYXZhL2xhbmcvaW52" + - "b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwAQAeamF2YS9sYW5nL2ludm9rZS9NZXRob2RIYW5kbGVz" + - "ACEADAANAAEADgADABkAEgATAAAAGQAUABMAAAABABUAFgABABcAAAACABgABAABABkAGgABABsA" + - "AAAuAAIAAQAAAA4qtwABKhICuAADtQAEsQAAAAEAHAAAAA4AAwAAACEABAAiAA0AIwABAB0AHgAB" + - "ABsAAAAlAAEAAQAAAA0qtAAEtgAFugAGAACwAAAAAQAcAAAABgABAAAAJQABAB8AGgABABsAAAAv" + - "AAIAAQAAAA8qtAAEsgAHtgAIV7gACbEAAAABABwAAAAOAAMAAAApAAsAKwAOACwACAAgABoAAQAb" + - "AAAAKQABAAAAAAAJAbMACgGzAAuxAAAAAQAcAAAADgADAAAAGwAEABwACAAdAAMAIQAAAAIAIgAQ" + - "AAAAIgAEAAwALwAPAAkAAgAMABFAGQANAC8ANQQJAEcASgBIABkAKQAAAAgAAQAqAAEAKw=="); - public static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAaR23N6WpunLRVX+BexSuzzNNiHNOvQpFoBwAAcAAAAHhWNBIAAAAAAAAAAKQGAAAq" + - "AAAAcAAAABEAAAAYAQAABQAAAFwBAAAEAAAAmAEAAAwAAAC4AQAAAQAAABgCAAAwBQAAOAIAACID" + - "AAA5AwAAQwMAAEsDAABPAwAAXAMAAGcDAABqAwAAbgMAAJEDAADCAwAA5QMAAPUDAAAZBAAAOQQA" + - "AFwEAAB7BAAAjgQAAKIEAAC4BAAAzAQAAOcEAAD8BAAAEQUAABwFAAAwBQAATwUAAF4FAABhBQAA" + - "ZAUAAGgFAABsBQAAeQUAAH4FAACGBQAAlgUAAKEFAACnBQAArwUAAMAFAADKBQAA0QUAAAgAAAAJ" + - "AAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAGwAAABwA" + - "AAAeAAAABgAAAAsAAAAAAAAABwAAAAwAAAAMAwAABwAAAA0AAAAUAwAAGwAAAA4AAAAAAAAAHQAA" + - "AA8AAAAcAwAAAQABABcAAAACABAABAAAAAIAEAAFAAAAAgANACYAAAAAAAMAAgAAAAIAAwABAAAA" + - "AgADAAIAAAACAAMAIgAAAAIAAAAnAAAAAwADACMAAAAMAAMAAgAAAAwAAQAhAAAADAAAACcAAAAN" + - "AAQAIAAAAA0AAgAlAAAADQAAACcAAAACAAAAAQAAAAAAAAAEAwAAGgAAAIwGAABRBgAAAAAAAAQA" + - "AQACAAAA+gIAAB0AAABUMAMAbhALAAAADAAiAQwAcBAGAAEAGgIZAG4gBwAhAG4gBwABABoAAABu" + - "IAcAAQBuEAgAAQAMABEAAAABAAAAAAAAAPQCAAAGAAAAEgBpAAEAaQACAA4AAgABAAEAAADuAgAA" + - "DAAAAHAQAAABABwAAQBxEAoAAAAMAFsQAwAOAAMAAQACAAAA/gIAAAsAAABUIAMAYgEAAG4gCQAQ" + - "AHEABQAAAA4AIQAOPIcAGwAOPC0AJQAOACkADnk8AAEAAAAKAAAAAQAAAAsAAAABAAAACAAAAAEA" + - "AAAJABUgY3VycmVudDogUkVERUZJTkVEIH0ACDxjbGluaXQ+AAY8aW5pdD4AAj47AAtDTEFTU19C" + - "WVRFUwAJREVYX0JZVEVTAAFMAAJMTAAhTGFydC9UZXN0MTk1MyRBYnN0cmFjdFRlc3RPYmplY3Q7" + - "AC9MYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmluZVN0YXRlOwAhTGFydC9U" + - "ZXN0MTk1MyRSZWRlZmluZVRlc3RPYmplY3Q7AA5MYXJ0L1Rlc3QxOTUzOwAiTGRhbHZpay9hbm5v" + - "dGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ACFM" + - "ZGFsdmlrL2Fubm90YXRpb24vTWVtYmVyQ2xhc3NlczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWdu" + - "YXR1cmU7ABFMamF2YS9sYW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5n" + - "L1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" + - "ABNMamF2YS91dGlsL0VudW1TZXQ7ABNMamF2YS91dGlsL0VudW1TZXQ8AAlSRURFRklORUQAElJl" + - "ZGVmaW5lVGVzdE9iamVjdAAdUmVkZWZpbmVUZXN0T2JqZWN0IHsgc3RhdGVzOiAADVRlc3QxOTUz" + - "LmphdmEAAVYAAVoAAlpMAAJbQgALYWNjZXNzRmxhZ3MAA2FkZAAGYXBwZW5kAA5jYWxsZWRGdW5j" + - "dGlvbgAJZG9Ob3RoaW5nAARuYW1lAAZub25lT2YAD3JlZGVmaW5lX3N0YXRlcwAIdG9TdHJpbmcA" + - "BXZhbHVlAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjUyNzNjM2RmZWUxMDQ2NzIwYWY0MjVm" + - "YTg1NTMxNmM5OWM4NmM4ZDIiLCJ2ZXJzaW9uIjoiMS4zLjE4LWRldiJ9AAIHASgcAxcWFwkXAwIE" + - "ASgYAwIFAh8ECSQXGAIGASgcARgBAgECAgEZARkDAQGIgASEBQGBgASgBQMByAUBAbgEAAAAAAAB" + - "AAAALgYAAAMAAAA6BgAAQAYAAEkGAAB8BgAAAQAAAAAAAAAAAAAAAwAAAHQGAAAQAAAAAAAAAAEA" + - "AAAAAAAAAQAAACoAAABwAAAAAgAAABEAAAAYAQAAAwAAAAUAAABcAQAABAAAAAQAAACYAQAABQAA" + - "AAwAAAC4AQAABgAAAAEAAAAYAgAAASAAAAQAAAA4AgAAAyAAAAQAAADuAgAAARAAAAQAAAAEAwAA" + - "AiAAACoAAAAiAwAABCAAAAQAAAAuBgAAACAAAAEAAABRBgAAAxAAAAMAAABwBgAABiAAAAEAAACM" + - "BgAAABAAAAEAAACkBgAA"); - - public EnumSet<RedefineState> redefine_states; - public RedefineTestObject() { - super(); - redefine_states = EnumSet.noneOf(RedefineState.class); - } - - public String toString() { - return "RedefineTestObject { states: " + redefine_states.toString() + " current: ORIGINAL }"; - } - - public void calledFunction() { - redefine_states.add(RedefineState.ORIGINAL); // line +0 - // We will trigger the redefinition using a breakpoint on the next line. - doNothing(); // line +2 - } - } - - public static class ClassLoadObject implements TestRunnable { - public int cnt; - public int baseCallCnt; - - public static final String[] CLASS_NAMES = new String[] { - "Lart/Test1953$ClassLoadObject$TC0;", - "Lart/Test1953$ClassLoadObject$TC1;", - "Lart/Test1953$ClassLoadObject$TC2;", - "Lart/Test1953$ClassLoadObject$TC3;", - "Lart/Test1953$ClassLoadObject$TC4;", - "Lart/Test1953$ClassLoadObject$TC5;", - "Lart/Test1953$ClassLoadObject$TC6;", - "Lart/Test1953$ClassLoadObject$TC7;", - "Lart/Test1953$ClassLoadObject$TC8;", - "Lart/Test1953$ClassLoadObject$TC9;", - }; - - private static int curClass = 0; - - private static class TC0 { public static int foo; static { foo = 1; } } - private static class TC1 { public static int foo; static { foo = 2; } } - private static class TC2 { public static int foo; static { foo = 3; } } - private static class TC3 { public static int foo; static { foo = 4; } } - private static class TC4 { public static int foo; static { foo = 5; } } - private static class TC5 { public static int foo; static { foo = 6; } } - private static class TC6 { public static int foo; static { foo = 7; } } - private static class TC7 { public static int foo; static { foo = 8; } } - private static class TC8 { public static int foo; static { foo = 9; } } - private static class TC9 { public static int foo; static { foo = 10; } } - - public ClassLoadObject() { - super(); - cnt = 0; - baseCallCnt = 0; - } - - public int getBaseCallCount() { - return baseCallCnt; - } - - public void run() { - baseCallCnt++; - if (curClass == 0) { - $noprecompile$calledFunction0(); - } else if (curClass == 1) { - $noprecompile$calledFunction1(); - } else if (curClass == 2) { - $noprecompile$calledFunction2(); - } else if (curClass == 3) { - $noprecompile$calledFunction3(); - } else if (curClass == 4) { - $noprecompile$calledFunction4(); - } else if (curClass == 5) { - $noprecompile$calledFunction5(); - } else if (curClass == 6) { - $noprecompile$calledFunction6(); - } else if (curClass == 7) { - $noprecompile$calledFunction7(); - } else if (curClass == 8) { - $noprecompile$calledFunction8(); - } else if (curClass == 9) { - $noprecompile$calledFunction9(); - } - curClass++; - } - - // Give these all a tag to prevent 1954 from compiling them (and loading the class as a - // consequence). - public void $noprecompile$calledFunction0() { - cnt++; - System.out.println("TC0.foo == " + TC0.foo); - } - - public void $noprecompile$calledFunction1() { - cnt++; - System.out.println("TC1.foo == " + TC1.foo); - } - - public void $noprecompile$calledFunction2() { - cnt++; - System.out.println("TC2.foo == " + TC2.foo); - } - - public void $noprecompile$calledFunction3() { - cnt++; - System.out.println("TC3.foo == " + TC3.foo); - } - - public void $noprecompile$calledFunction4() { - cnt++; - System.out.println("TC4.foo == " + TC4.foo); - } - - public void $noprecompile$calledFunction5() { - cnt++; - System.out.println("TC5.foo == " + TC5.foo); - } - - public void $noprecompile$calledFunction6() { - cnt++; - System.out.println("TC6.foo == " + TC6.foo); - } - - public void $noprecompile$calledFunction7() { - cnt++; - System.out.println("TC7.foo == " + TC7.foo); - } - - public void $noprecompile$calledFunction8() { - cnt++; - System.out.println("TC8.foo == " + TC8.foo); - } - - public void $noprecompile$calledFunction9() { - cnt++; - System.out.println("TC9.foo == " + TC9.foo); - } - - public String toString() { - return "ClassLoadObject { cnt: " + cnt + ", curClass: " + curClass + "}"; - } - } - - public static class FieldBasedTestObject extends AbstractTestObject implements Runnable { - public int cnt; - public int TARGET_FIELD; - public FieldBasedTestObject() { - super(); - cnt = 0; - TARGET_FIELD = 0; - } - - public void calledFunction() { - cnt++; - // We put a watchpoint here and PopFrame when we are at it. - TARGET_FIELD += 10; - if (cnt == 1) { System.out.println("FAILED: No pop on first call!"); } - } - - public String toString() { - return "FieldBasedTestObject { cnt: " + cnt + ", TARGET_FIELD: " + TARGET_FIELD + " }"; - } - } - - public static class StandardTestObject extends AbstractTestObject implements Runnable { - public int cnt; - public final boolean check; - - public StandardTestObject(boolean check) { - super(); - cnt = 0; - this.check = check; - } - - public StandardTestObject() { - this(true); - } - - public void calledFunction() { - cnt++; // line +0 - // We put a breakpoint here and PopFrame when we are at it. - doNothing(); // line +2 - if (check && cnt == 1) { System.out.println("FAILED: No pop on first call!"); } - } - - public String toString() { - return "StandardTestObject { cnt: " + cnt + " }"; - } - } - - public static class SynchronizedFunctionTestObject extends AbstractTestObject implements Runnable { - public int cnt; - - public SynchronizedFunctionTestObject() { - super(); - cnt = 0; - } - - public synchronized void calledFunction() { - cnt++; // line +0 - // We put a breakpoint here and PopFrame when we are at it. - doNothing(); // line +2 - } - - public String toString() { - return "SynchronizedFunctionTestObject { cnt: " + cnt + " }"; - } - } - public static class SynchronizedTestObject extends AbstractTestObject implements Runnable { - public int cnt; - public final Object lock; - - public SynchronizedTestObject() { - super(); - cnt = 0; - lock = new Object(); - } - - public void calledFunction() { - synchronized (lock) { // line +0 - cnt++; // line +1 - // We put a breakpoint here and PopFrame when we are at it. - doNothing(); // line +3 - } - } - - public String toString() { - return "SynchronizedTestObject { cnt: " + cnt + " }"; - } - } - - public static class ExceptionCatchTestObject extends AbstractTestObject implements Runnable { - public static class TestError extends Error {} - - public int cnt; - public ExceptionCatchTestObject() { - super(); - cnt = 0; - } - - public void calledFunction() { - cnt++; - try { - doThrow(); - } catch (TestError e) { - System.out.println(e.getClass().getName() + " caught in called function."); - } - } - - public void doThrow() { - throw new TestError(); - } - - public String toString() { - return "ExceptionCatchTestObject { cnt: " + cnt + " }"; - } - } - - public static class ExceptionThrowFarTestObject implements TestRunnable { - public static class TestError extends Error {} - - public int cnt; - public int baseCallCnt; - public final boolean catchInCalled; - public ExceptionThrowFarTestObject(boolean catchInCalled) { - super(); - cnt = 0; - baseCallCnt = 0; - this.catchInCalled = catchInCalled; - } - - public int getBaseCallCount() { - return baseCallCnt; - } - - public void run() { - baseCallCnt++; - try { - callingFunction(); - } catch (TestError e) { - System.out.println(e.getClass().getName() + " thrown and caught!"); - } - } - - public void callingFunction() { - calledFunction(); - } - public void calledFunction() { - cnt++; - if (catchInCalled) { - try { - throw new TestError(); // We put a watch here. - } catch (TestError e) { - System.out.println(e.getClass().getName() + " caught in same function."); - } - } else { - throw new TestError(); // We put a watch here. - } - } - - public String toString() { - return "ExceptionThrowFarTestObject { cnt: " + cnt + " }"; - } - } - - public static class ExceptionOnceObject extends AbstractTestObject { - public static final class TestError extends Error {} - public int cnt; - public final boolean throwInSub; - public ExceptionOnceObject(boolean throwInSub) { - super(); - cnt = 0; - this.throwInSub = throwInSub; - } - - public void calledFunction() { - cnt++; - if (cnt == 1) { - if (throwInSub) { - doThrow(); - } else { - throw new TestError(); - } - } - } - - public void doThrow() { - throw new TestError(); - } - - public String toString() { - return "ExceptionOnceObject { cnt: " + cnt + ", throwInSub: " + throwInSub + " }"; - } - } - - public static class ExceptionThrowTestObject implements TestRunnable { - public static class TestError extends Error {} - - public int cnt; - public int baseCallCnt; - public final boolean catchInCalled; - public ExceptionThrowTestObject(boolean catchInCalled) { - super(); - cnt = 0; - baseCallCnt = 0; - this.catchInCalled = catchInCalled; - } - - public int getBaseCallCount() { - return baseCallCnt; - } - - public void run() { - baseCallCnt++; - try { - calledFunction(); - } catch (TestError e) { - System.out.println(e.getClass().getName() + " thrown and caught!"); - } - } - - public void calledFunction() { - cnt++; - if (catchInCalled) { - try { - throw new TestError(); // We put a watch here. - } catch (TestError e) { - System.out.println(e.getClass().getName() + " caught in same function."); - } - } else { - throw new TestError(); // We put a watch here. - } - } - - public String toString() { - return "ExceptionThrowTestObject { cnt: " + cnt + " }"; - } - } - - public static class NativeCalledObject extends AbstractTestObject { - public int cnt = 0; - - public native void calledFunction(); - - public String toString() { - return "NativeCalledObject { cnt: " + cnt + " }"; - } - } - - public static class NativeCallerObject implements TestRunnable { - public int baseCnt = 0; - public int cnt = 0; - - public int getBaseCallCount() { - return baseCnt; - } - - public native void run(); - - public void calledFunction() { - cnt++; - // We will stop using a MethodExit event. - } - - public String toString() { - return "NativeCallerObject { cnt: " + cnt + " }"; - } - } - public static class SuspendSuddenlyObject extends AbstractTestObject { - public volatile boolean stop_spinning = false; - public volatile boolean is_spinning = false; - public int cnt = 0; - - public void calledFunction() { - cnt++; - while (!stop_spinning) { - is_spinning = true; - } - } - - public String toString() { - return "SuspendSuddenlyObject { cnt: " + cnt + " }"; - } - } - - public static void run() throws Exception { - new Test1953((x)-> {}).runTests(); - } - - public Test1953(Consumer<Object> preTest) { - this.preTest = preTest; - } - - private Consumer<Object> preTest; - - public void runTests() throws Exception { - setupTest(); - - final Method calledFunction = StandardTestObject.class.getDeclaredMethod("calledFunction"); - final Method doNothingMethod = Test1953.class.getDeclaredMethod("doNothing"); - // Add a breakpoint on the second line after the start of the function - final int line = Breakpoint.locationToLine(calledFunction, 0) + 2; - final long loc = Breakpoint.lineToLocation(calledFunction, line); - System.out.println("Test stopped using breakpoint"); - runTestOn(new StandardTestObject(), - (thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr), - Test1953::clearSuspendBreakpointFor); - - final Method syncFunctionCalledFunction = - SynchronizedFunctionTestObject.class.getDeclaredMethod("calledFunction"); - // Add a breakpoint on the second line after the start of the function - // Annoyingly r8 generally has the first instruction (a monitor enter) not be marked as being - // on any line but javac has it marked as being on the first line of the function. Just use the - // second entry on the line-number table to get the breakpoint. This should be good for both. - final long syncFunctionLoc = - Breakpoint.getLineNumberTable(syncFunctionCalledFunction)[1].location; - System.out.println("Test stopped using breakpoint with declared synchronized function"); - runTestOn(new SynchronizedFunctionTestObject(), - (thr) -> setupSuspendBreakpointFor(syncFunctionCalledFunction, syncFunctionLoc, thr), - Test1953::clearSuspendBreakpointFor); - - final Method syncCalledFunction = - SynchronizedTestObject.class.getDeclaredMethod("calledFunction"); - // Add a breakpoint on the second line after the start of the function - final int syncLine = Breakpoint.locationToLine(syncCalledFunction, 0) + 3; - final long syncLoc = Breakpoint.lineToLocation(syncCalledFunction, syncLine); - System.out.println("Test stopped using breakpoint with synchronized block"); - runTestOn(new SynchronizedTestObject(), - (thr) -> setupSuspendBreakpointFor(syncCalledFunction, syncLoc, thr), - Test1953::clearSuspendBreakpointFor); - - System.out.println("Test stopped on single step"); - runTestOn(new StandardTestObject(), - (thr) -> setupSuspendSingleStepAt(calledFunction, loc, thr), - Test1953::clearSuspendSingleStepFor); - - final Field target_field = FieldBasedTestObject.class.getDeclaredField("TARGET_FIELD"); - System.out.println("Test stopped on field access"); - runTestOn(new FieldBasedTestObject(), - (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, true, thr), - Test1953::clearFieldSuspendFor); - - System.out.println("Test stopped on field modification"); - runTestOn(new FieldBasedTestObject(), - (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, false, thr), - Test1953::clearFieldSuspendFor); - - System.out.println("Test stopped during Method Exit of doNothing"); - runTestOn(new StandardTestObject(false), - (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ false, thr), - Test1953::clearSuspendMethodEvent); - - // NB We need another test to make sure the MethodEntered event is triggered twice. - System.out.println("Test stopped during Method Enter of doNothing"); - runTestOn(new StandardTestObject(false), - (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ true, thr), - Test1953::clearSuspendMethodEvent); - - System.out.println("Test stopped during Method Exit of calledFunction"); - runTestOn(new StandardTestObject(false), - (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ false, thr), - Test1953::clearSuspendMethodEvent); - - System.out.println("Test stopped during Method Enter of calledFunction"); - runTestOn(new StandardTestObject(false), - (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ true, thr), - Test1953::clearSuspendMethodEvent); - - final Method exceptionOnceCalledMethod = - ExceptionOnceObject.class.getDeclaredMethod("calledFunction"); - System.out.println("Test stopped during Method Exit due to exception thrown in same function"); - runTestOn(new ExceptionOnceObject(/*throwInSub*/ false), - (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr), - Test1953::clearSuspendMethodEvent); - - System.out.println("Test stopped during Method Exit due to exception thrown in subroutine"); - runTestOn(new ExceptionOnceObject(/*throwInSub*/ true), - (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr), - Test1953::clearSuspendMethodEvent); - - System.out.println("Test stopped during notifyFramePop without exception on pop of calledFunction"); - runTestOn(new StandardTestObject(false), - (thr) -> setupSuspendPopFrameEvent(1, doNothingMethod, thr), - Test1953::clearSuspendPopFrameEvent); - - System.out.println("Test stopped during notifyFramePop without exception on pop of doNothing"); - runTestOn(new StandardTestObject(false), - (thr) -> setupSuspendPopFrameEvent(0, doNothingMethod, thr), - Test1953::clearSuspendPopFrameEvent); - - final Method exceptionThrowCalledMethod = - ExceptionThrowTestObject.class.getDeclaredMethod("calledFunction"); - System.out.println("Test stopped during notifyFramePop with exception on pop of calledFunction"); - runTestOn(new ExceptionThrowTestObject(false), - (thr) -> setupSuspendPopFrameEvent(0, exceptionThrowCalledMethod, thr), - Test1953::clearSuspendPopFrameEvent); - - final Method exceptionCatchThrowMethod = - ExceptionCatchTestObject.class.getDeclaredMethod("doThrow"); - System.out.println("Test stopped during notifyFramePop with exception on pop of doThrow"); - runTestOn(new ExceptionCatchTestObject(), - (thr) -> setupSuspendPopFrameEvent(0, exceptionCatchThrowMethod, thr), - Test1953::clearSuspendPopFrameEvent); - - System.out.println("Test stopped during ExceptionCatch event of calledFunction " + - "(catch in called function, throw in called function)"); - runTestOn(new ExceptionThrowTestObject(true), - (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ true, thr), - Test1953::clearSuspendExceptionEvent); - - final Method exceptionCatchCalledMethod = - ExceptionCatchTestObject.class.getDeclaredMethod("calledFunction"); - System.out.println("Test stopped during ExceptionCatch event of calledFunction " + - "(catch in called function, throw in subroutine)"); - runTestOn(new ExceptionCatchTestObject(), - (thr) -> setupSuspendExceptionEvent(exceptionCatchCalledMethod, /*catch*/ true, thr), - Test1953::clearSuspendExceptionEvent); - - System.out.println("Test stopped during Exception event of calledFunction " + - "(catch in calling function)"); - runTestOn(new ExceptionThrowTestObject(false), - (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr), - Test1953::clearSuspendExceptionEvent); - - System.out.println("Test stopped during Exception event of calledFunction " + - "(catch in called function)"); - runTestOn(new ExceptionThrowTestObject(true), - (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr), - Test1953::clearSuspendExceptionEvent); - - final Method exceptionThrowFarCalledMethod = - ExceptionThrowFarTestObject.class.getDeclaredMethod("calledFunction"); - System.out.println("Test stopped during Exception event of calledFunction " + - "(catch in parent of calling function)"); - runTestOn(new ExceptionThrowFarTestObject(false), - (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr), - Test1953::clearSuspendExceptionEvent); - - System.out.println("Test stopped during Exception event of calledFunction " + - "(catch in called function)"); - runTestOn(new ExceptionThrowFarTestObject(true), - (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr), - Test1953::clearSuspendExceptionEvent); - - if (IS_ART) { - // This test doesn't work on RI since the RI disallows use of PopFrame during a ClassLoad - // event. See b/116003018 for more information. - System.out.println("Test stopped during a ClassLoad event."); - runTestOn(new ClassLoadObject(), - (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr), - Test1953::clearSuspendClassEvent); - - // The RI handles a PopFrame during a ClassPrepare event incorrectly. See b/116003018 for - // more information. - System.out.println("Test stopped during a ClassPrepare event."); - runTestOn(new ClassLoadObject(), - (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_PREPARE, - ClassLoadObject.CLASS_NAMES, - thr), - Test1953::clearSuspendClassEvent); - } - System.out.println("Test stopped during random Suspend."); - final SuspendSuddenlyObject sso = new SuspendSuddenlyObject(); - runTestOn( - sso, - new TestSuspender() { - public void setup(Thread thr) { } - public void waitForSuspend(Thread thr) { - while (!sso.is_spinning) {} - Suspension.suspend(thr); - } - public void cleanup(Thread thr) { - sso.stop_spinning = true; - } - }); - - final Method redefineCalledFunction = - RedefineTestObject.class.getDeclaredMethod("calledFunction"); - final int redefLine = Breakpoint.locationToLine(redefineCalledFunction, 0) + 2; - final long redefLoc = Breakpoint.lineToLocation(redefineCalledFunction, redefLine); - System.out.println("Test redefining frame being popped."); - runTestOn(new RedefineTestObject(), - (thr) -> setupSuspendBreakpointFor(redefineCalledFunction, redefLoc, thr), - (thr) -> { - clearSuspendBreakpointFor(thr); - Redefinition.doCommonClassRedefinition(RedefineTestObject.class, - RedefineTestObject.CLASS_BYTES, - RedefineTestObject.DEX_BYTES); - }); - - System.out.println("Test stopped during a native method fails"); - runTestOn(new NativeCalledObject(), - Test1953::setupWaitForNativeCall, - Test1953::clearWaitForNativeCall); - - System.out.println("Test stopped in a method called by native fails"); - final Method nativeCallerMethod = NativeCallerObject.class.getDeclaredMethod("calledFunction"); - runTestOn(new NativeCallerObject(), - (thr) -> setupSuspendMethodEvent(nativeCallerMethod, /*enter*/ false, thr), - Test1953::clearSuspendMethodEvent); - } - - public static native void setupTest(); - public static native void popFrame(Thread thr); - - public static native void setupSuspendBreakpointFor(Executable meth, long loc, Thread thr); - public static native void clearSuspendBreakpointFor(Thread thr); - - public static native void setupSuspendSingleStepAt(Executable meth, long loc, Thread thr); - public static native void clearSuspendSingleStepFor(Thread thr); - - public static native void setupFieldSuspendFor(Class klass, Field f, boolean access, Thread thr); - public static native void clearFieldSuspendFor(Thread thr); - - public static native void setupSuspendMethodEvent(Executable meth, boolean enter, Thread thr); - public static native void clearSuspendMethodEvent(Thread thr); - - public static native void setupSuspendExceptionEvent( - Executable meth, boolean is_catch, Thread thr); - public static native void clearSuspendExceptionEvent(Thread thr); - - public static native void setupSuspendPopFrameEvent( - int offset, Executable breakpointFunction, Thread thr); - public static native void clearSuspendPopFrameEvent(Thread thr); - - public static final int EVENT_TYPE_CLASS_LOAD = 55; - public static final int EVENT_TYPE_CLASS_PREPARE = 56; - public static native void setupSuspendClassEvent( - int eventType, String[] interestingNames, Thread thr); - public static native void clearSuspendClassEvent(Thread thr); - - public static native void setupWaitForNativeCall(Thread thr); - public static native void clearWaitForNativeCall(Thread thr); - - public static native void waitForSuspendHit(Thread thr); -} diff --git a/test/1954-pop-frame-jit/check b/test/1954-pop-frame-jit/check deleted file mode 100755 index 3e379962dd..0000000000 --- a/test/1954-pop-frame-jit/check +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2018 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# The RI has restrictions and bugs around some PopFrame behavior that ART lacks. -# See b/116003018. -if [[ "$TEST_RUNTIME" == "jvm" ]]; then - patch -p0 expected.txt < jvm-expected.patch >/dev/null -fi - -./default-check "$@" diff --git a/test/1954-pop-frame-jit/expected.txt b/test/1954-pop-frame-jit/expected.txt deleted file mode 100644 index 0828907369..0000000000 --- a/test/1954-pop-frame-jit/expected.txt +++ /dev/null @@ -1,106 +0,0 @@ -Test stopped using breakpoint -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped using breakpoint with declared synchronized function -Single call with PopFrame on SynchronizedFunctionTestObject { cnt: 0 } base-call-count: 0 -result is SynchronizedFunctionTestObject { cnt: 2 } base-call count: 1 -Test stopped using breakpoint with synchronized block -Single call with PopFrame on SynchronizedTestObject { cnt: 0 } base-call-count: 0 -result is SynchronizedTestObject { cnt: 2 } base-call count: 1 -Test stopped on single step -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped on field access -Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0 -result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1 -Test stopped on field modification -Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0 -result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1 -Test stopped during Method Exit of doNothing -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during Method Enter of doNothing -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during Method Exit of calledFunction -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped during Method Enter of calledFunction -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during Method Exit due to exception thrown in same function -Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: false } base-call-count: 0 -result is ExceptionOnceObject { cnt: 2, throwInSub: false } base-call count: 1 -Test stopped during Method Exit due to exception thrown in subroutine -Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: true } base-call-count: 0 -result is ExceptionOnceObject { cnt: 2, throwInSub: true } base-call count: 1 -Test stopped during notifyFramePop without exception on pop of calledFunction -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 2 } base-call count: 1 -Test stopped during notifyFramePop without exception on pop of doNothing -Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0 -result is StandardTestObject { cnt: 1 } base-call count: 1 -Test stopped during notifyFramePop with exception on pop of calledFunction -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError thrown and caught! -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during notifyFramePop with exception on pop of doThrow -Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionCatchTestObject$TestError caught in called function. -result is ExceptionCatchTestObject { cnt: 1 } base-call count: 1 -Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in called function) -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError caught in same function. -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in subroutine) -Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionCatchTestObject$TestError caught in called function. -result is ExceptionCatchTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in calling function) -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError thrown and caught! -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in called function) -Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowTestObject$TestError caught in same function. -result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in parent of calling function) -Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowFarTestObject$TestError thrown and caught! -result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1 -Test stopped during Exception event of calledFunction (catch in called function) -Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0 -art.Test1953$ExceptionThrowFarTestObject$TestError caught in same function. -result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1 -Test stopped during a ClassLoad event. -Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0 -TC0.foo == 1 -result is ClassLoadObject { cnt: 2, curClass: 1} base-call count: 1 -Test stopped during a ClassPrepare event. -Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0 -TC1.foo == 2 -result is ClassLoadObject { cnt: 2, curClass: 2} base-call count: 1 -Test stopped during random Suspend. -Single call with PopFrame on SuspendSuddenlyObject { cnt: 0 } base-call-count: 0 -result is SuspendSuddenlyObject { cnt: 2 } base-call count: 1 -Test redefining frame being popped. -Single call with PopFrame on RedefineTestObject { states: [] current: ORIGINAL } base-call-count: 0 -result is RedefineTestObject { states: [ORIGINAL, REDEFINED] current: REDEFINED } base-call count: 1 -Test stopped during a native method fails -Single call with PopFrame on NativeCalledObject { cnt: 0 } base-call-count: 0 -Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME - art.Test1953.popFrame(Native Method) - art.Test1953.runTestOn(Test1953.java:103) - art.Test1953.runTestOn(Test1953.java:52) - art.Test1953.runTests(Test1953.java:858) - <Additional frames hidden> -result is NativeCalledObject { cnt: 1 } base-call count: 1 -Test stopped in a method called by native fails -Single call with PopFrame on NativeCallerObject { cnt: 0 } base-call-count: 0 -Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME - art.Test1953.popFrame(Native Method) - art.Test1953.runTestOn(Test1953.java:103) - art.Test1953.runTestOn(Test1953.java:52) - art.Test1953.runTests(Test1953.java:864) - <Additional frames hidden> -result is NativeCallerObject { cnt: 1 } base-call count: 1 diff --git a/test/1954-pop-frame-jit/info.txt b/test/1954-pop-frame-jit/info.txt deleted file mode 100644 index b5eb5464b7..0000000000 --- a/test/1954-pop-frame-jit/info.txt +++ /dev/null @@ -1,7 +0,0 @@ -Test basic JVMTI breakpoint functionality. - -This test places a breakpoint on the first instruction of a number of functions -that are entered in every way possible for the given class of method. - -It also tests that breakpoints don't interfere with each other by having -multiple breakpoints be set at once. diff --git a/test/1954-pop-frame-jit/jvm-expected.patch b/test/1954-pop-frame-jit/jvm-expected.patch deleted file mode 100644 index ff482d12c1..0000000000 --- a/test/1954-pop-frame-jit/jvm-expected.patch +++ /dev/null @@ -1,9 +0,0 @@ -75,82d74 -< Test stopped during a ClassLoad event. -< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0 -< TC0.foo == 1 -< result is ClassLoadObject { cnt: 2, curClass: 1} base-call count: 1 -< Test stopped during a ClassPrepare event. -< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0 -< TC1.foo == 2 -< result is ClassLoadObject { cnt: 2, curClass: 2} base-call count: 1 diff --git a/test/1954-pop-frame-jit/run b/test/1954-pop-frame-jit/run deleted file mode 100755 index 9163dbc9d9..0000000000 --- a/test/1954-pop-frame-jit/run +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# if [[ "$@" != *"--jit"* ]]; then -# # On interpreter we are fully capable of providing the full jvmti api so we -# # have a slightly different expected output. -# # TODO We should really be changing this in the 'check' script. -# patch -s expected.txt < non-jit-expected.patch -# fi - -# Ask for stack traces to be dumped to a file rather than to stdout. -./default-run "$@" --jvmti diff --git a/test/1954-pop-frame-jit/src/Main.java b/test/1954-pop-frame-jit/src/Main.java deleted file mode 100644 index 5dd4d64d79..0000000000 --- a/test/1954-pop-frame-jit/src/Main.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import java.time.Duration; - -import java.util.concurrent.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.Stack; -import java.util.Vector; - -import java.util.function.Supplier; - -import art.*; - -public class Main extends Test1953 { - public Main() { - super((testObj) -> { - try { - // Make sure everything is jitted in the method. We do this before calling setup since the - // suspend setup might make it impossible to jit the methods (by setting breakpoints or - // something). - for (Method m : testObj.getClass().getMethods()) { - if ((m.getModifiers() & Modifier.NATIVE) == 0 && - !m.getName().startsWith("$noprecompile$")) { - ensureMethodJitCompiled(m); - } - } - } catch (Exception e) {} - }); - } - - public static void main(String[] args) throws Exception { - new Main().runTests(); - } - - public static native void ensureMethodJitCompiled(Method meth); -} diff --git a/test/1954-pop-frame-jit/src/art/Breakpoint.java b/test/1954-pop-frame-jit/src/art/Breakpoint.java deleted file mode 100644 index bbb89f707f..0000000000 --- a/test/1954-pop-frame-jit/src/art/Breakpoint.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.lang.reflect.Executable; -import java.util.HashSet; -import java.util.Set; -import java.util.Objects; - -public class Breakpoint { - public static class Manager { - public static class BP { - public final Executable method; - public final long location; - - public BP(Executable method) { - this(method, getStartLocation(method)); - } - - public BP(Executable method, long location) { - this.method = method; - this.location = location; - } - - @Override - public boolean equals(Object other) { - return (other instanceof BP) && - method.equals(((BP)other).method) && - location == ((BP)other).location; - } - - @Override - public String toString() { - return method.toString() + " @ " + getLine(); - } - - @Override - public int hashCode() { - return Objects.hash(method, location); - } - - public int getLine() { - try { - LineNumber[] lines = getLineNumberTable(method); - int best = -1; - for (LineNumber l : lines) { - if (l.location > location) { - break; - } else { - best = l.line; - } - } - return best; - } catch (Exception e) { - return -1; - } - } - } - - private Set<BP> breaks = new HashSet<>(); - - public void setBreakpoints(BP... bs) { - for (BP b : bs) { - if (breaks.add(b)) { - Breakpoint.setBreakpoint(b.method, b.location); - } - } - } - public void setBreakpoint(Executable method, long location) { - setBreakpoints(new BP(method, location)); - } - - public void clearBreakpoints(BP... bs) { - for (BP b : bs) { - if (breaks.remove(b)) { - Breakpoint.clearBreakpoint(b.method, b.location); - } - } - } - public void clearBreakpoint(Executable method, long location) { - clearBreakpoints(new BP(method, location)); - } - - public void clearAllBreakpoints() { - clearBreakpoints(breaks.toArray(new BP[0])); - } - } - - public static void startBreakpointWatch(Class<?> methodClass, - Executable breakpointReached, - Thread thr) { - startBreakpointWatch(methodClass, breakpointReached, false, thr); - } - - /** - * Enables the trapping of breakpoint events. - * - * If allowRecursive == true then breakpoints will be sent even if one is currently being handled. - */ - public static native void startBreakpointWatch(Class<?> methodClass, - Executable breakpointReached, - boolean allowRecursive, - Thread thr); - public static native void stopBreakpointWatch(Thread thr); - - public static final class LineNumber implements Comparable<LineNumber> { - public final long location; - public final int line; - - private LineNumber(long loc, int line) { - this.location = loc; - this.line = line; - } - - public boolean equals(Object other) { - return other instanceof LineNumber && ((LineNumber)other).line == line && - ((LineNumber)other).location == location; - } - - public int compareTo(LineNumber other) { - int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line)); - if (v != 0) { - return v; - } else { - return Long.valueOf(location).compareTo(Long.valueOf(other.location)); - } - } - } - - public static native void setBreakpoint(Executable m, long loc); - public static void setBreakpoint(Executable m, LineNumber l) { - setBreakpoint(m, l.location); - } - - public static native void clearBreakpoint(Executable m, long loc); - public static void clearBreakpoint(Executable m, LineNumber l) { - clearBreakpoint(m, l.location); - } - - private static native Object[] getLineNumberTableNative(Executable m); - public static LineNumber[] getLineNumberTable(Executable m) { - Object[] nativeTable = getLineNumberTableNative(m); - long[] location = (long[])(nativeTable[0]); - int[] lines = (int[])(nativeTable[1]); - if (lines.length != location.length) { - throw new Error("Lines and locations have different lengths!"); - } - LineNumber[] out = new LineNumber[lines.length]; - for (int i = 0; i < lines.length; i++) { - out[i] = new LineNumber(location[i], lines[i]); - } - return out; - } - - public static native long getStartLocation(Executable m); - - public static int locationToLine(Executable m, long location) { - try { - Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); - int best = -1; - for (Breakpoint.LineNumber l : lines) { - if (l.location > location) { - break; - } else { - best = l.line; - } - } - return best; - } catch (Exception e) { - return -1; - } - } - - public static long lineToLocation(Executable m, int line) throws Exception { - try { - Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m); - for (Breakpoint.LineNumber l : lines) { - if (l.line == line) { - return l.location; - } - } - throw new Exception("Unable to find line " + line + " in " + m); - } catch (Exception e) { - throw new Exception("Unable to get line number info for " + m, e); - } - } -} - diff --git a/test/1954-pop-frame-jit/src/art/Redefinition.java b/test/1954-pop-frame-jit/src/art/Redefinition.java deleted file mode 100644 index 56d2938a01..0000000000 --- a/test/1954-pop-frame-jit/src/art/Redefinition.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.util.ArrayList; -// Common Redefinition functions. Placed here for use by CTS -public class Redefinition { - public static final class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; - - public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } - } - - // A set of possible test configurations. Test should set this if they need to. - // This must be kept in sync with the defines in ti-agent/common_helper.cc - public static enum Config { - COMMON_REDEFINE(0), - COMMON_RETRANSFORM(1), - COMMON_TRANSFORM(2); - - private final int val; - private Config(int val) { - this.val = val; - } - } - - public static void setTestConfiguration(Config type) { - nativeSetTestConfiguration(type.val); - } - - private static native void nativeSetTestConfiguration(int type); - - // Transforms the class - public static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - public static void addMultiTransformationResults(CommonClassDefinition... defs) { - for (CommonClassDefinition d : defs) { - addCommonTransformationResult(d.target.getCanonicalName(), - d.class_file_bytes, - d.dex_file_bytes); - } - } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); - public static native void doCommonClassRetransformation(Class<?>... target); - public static native void setPopRetransformations(boolean pop); - public static native void popTransformationFor(String name); - public static native void enableCommonRetransformation(boolean enable); - public static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); -} diff --git a/test/1954-pop-frame-jit/src/art/StackTrace.java b/test/1954-pop-frame-jit/src/art/StackTrace.java deleted file mode 100644 index 2ea2f201e8..0000000000 --- a/test/1954-pop-frame-jit/src/art/StackTrace.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -import java.lang.reflect.Field; -import java.lang.reflect.Executable; - -public class StackTrace { - public static class StackFrameData { - public final Thread thr; - public final Executable method; - public final long current_location; - public final int depth; - - public StackFrameData(Thread thr, Executable e, long loc, int depth) { - this.thr = thr; - this.method = e; - this.current_location = loc; - this.depth = depth; - } - @Override - public String toString() { - return String.format( - "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }", - this.thr, - this.method, - this.current_location, - this.depth); - } - } - - public static native int GetStackDepth(Thread thr); - - private static native StackFrameData[] nativeGetStackTrace(Thread thr); - - public static StackFrameData[] GetStackTrace(Thread thr) { - // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not - // suspended. The spec says that not being suspended is fine but since we want this to be - // consistent we will suspend for the RI. - boolean suspend_thread = - !System.getProperty("java.vm.name").equals("Dalvik") && - !thr.equals(Thread.currentThread()) && - !Suspension.isSuspended(thr); - if (suspend_thread) { - Suspension.suspend(thr); - } - StackFrameData[] out = nativeGetStackTrace(thr); - if (suspend_thread) { - Suspension.resume(thr); - } - return out; - } -} - diff --git a/test/1954-pop-frame-jit/src/art/Suspension.java b/test/1954-pop-frame-jit/src/art/Suspension.java deleted file mode 100644 index 16e62ccac9..0000000000 --- a/test/1954-pop-frame-jit/src/art/Suspension.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package art; - -public class Suspension { - // Suspends a thread using jvmti. - public native static void suspend(Thread thr); - - // Resumes a thread using jvmti. - public native static void resume(Thread thr); - - public native static boolean isSuspended(Thread thr); - - public native static int[] suspendList(Thread... threads); - public native static int[] resumeList(Thread... threads); -} diff --git a/test/1954-pop-frame-jit/src/art/Test1953.java b/test/1954-pop-frame-jit/src/art/Test1953.java deleted file mode 120000 index f28143484a..0000000000 --- a/test/1954-pop-frame-jit/src/art/Test1953.java +++ /dev/null @@ -1 +0,0 @@ -../../../1953-pop-frame/src/art/Test1953.java
\ No newline at end of file diff --git a/test/Android.bp b/test/Android.bp index 096171a660..4b61463585 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -291,7 +291,6 @@ art_cc_defaults { "1946-list-descriptors/descriptors.cc", "1950-unprepared-transform/unprepared_transform.cc", "1951-monitor-enter-no-suspend/raw_monitor.cc", - "1953-pop-frame/pop_frame.cc", ], // Use NDK-compatible headers for ctstiagent. header_libs: [ @@ -321,7 +320,6 @@ art_cc_defaults { "983-source-transform-verify/source_transform_art.cc", "1940-ddms-ext/ddm_ext.cc", "1944-sudden-exit/sudden_exit.cc", - // "1952-pop-frame-jit/pop_frame.cc", ], static_libs: [ "libz", diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 90eb61b4f1..c9b789e169 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -21,13 +21,11 @@ #include "art_method-inl.h" #include "base/enums.h" -#include "common_throws.h" #include "dex/dex_file-inl.h" #include "instrumentation.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/profiling_info.h" -#include "jni/jni_internal.h" #include "mirror/class-inl.h" #include "nativehelper/ScopedUtfChars.h" #include "oat_file.h" @@ -197,56 +195,6 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env, return jit->GetCodeCache()->ContainsMethod(method); } -static void ForceJitCompiled(Thread* self, ArtMethod* method) REQUIRES(!Locks::mutator_lock_) { - { - ScopedObjectAccess soa(self); - if (method->IsNative()) { - std::string msg(method->PrettyMethod()); - msg += ": is native"; - ThrowIllegalArgumentException(msg.c_str()); - return; - } else if (!Runtime::Current()->GetRuntimeCallbacks()->IsMethodSafeToJit(method)) { - std::string msg(method->PrettyMethod()); - msg += ": is not safe to jit!"; - ThrowIllegalStateException(msg.c_str()); - return; - } - } - jit::Jit* jit = GetJitIfEnabled(); - jit::JitCodeCache* code_cache = jit->GetCodeCache(); - // Update the code cache to make sure the JIT code does not get deleted. - // Note: this will apply to all JIT compilations. - code_cache->SetGarbageCollectCode(false); - while (true) { - if (code_cache->WillExecuteJitCode(method)) { - break; - } else { - // Sleep to yield to the compiler thread. - usleep(1000); - ScopedObjectAccess soa(self); - // Make sure there is a profiling info, required by the compiler. - ProfilingInfo::Create(self, method, /* retry_allocation */ true); - // Will either ensure it's compiled or do the compilation itself. - jit->CompileMethod(method, self, /* osr */ false); - } - } -} - -extern "C" JNIEXPORT void JNICALL Java_Main_ensureMethodJitCompiled(JNIEnv*, jclass, jobject meth) { - jit::Jit* jit = GetJitIfEnabled(); - if (jit == nullptr) { - return; - } - - Thread* self = Thread::Current(); - ArtMethod* method; - { - ScopedObjectAccess soa(self); - method = ArtMethod::FromReflectedMethod(soa, meth); - } - ForceJitCompiled(self, method); -} - extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env, jclass, jclass cls, @@ -271,7 +219,24 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env, } DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str(); } - ForceJitCompiled(self, method); + + jit::JitCodeCache* code_cache = jit->GetCodeCache(); + // Update the code cache to make sure the JIT code does not get deleted. + // Note: this will apply to all JIT compilations. + code_cache->SetGarbageCollectCode(false); + while (true) { + if (code_cache->WillExecuteJitCode(method)) { + break; + } else { + // Sleep to yield to the compiler thread. + usleep(1000); + ScopedObjectAccess soa(self); + // Make sure there is a profiling info, required by the compiler. + ProfilingInfo::Create(self, method, /* retry_allocation */ true); + // Will either ensure it's compiled or do the compilation itself. + jit->CompileMethod(method, self, /* osr */ false); + } + } } extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* env, diff --git a/test/knownfailures.json b/test/knownfailures.json index 660ba167f6..fc4b25fa2b 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -1090,15 +1090,6 @@ "description": ["We do not inline with debuggable."] }, { - "tests": ["1953-pop-frame", "1954-pop-frame-jit"], - "variant": "interp-ac", - "description": [ - "Interp-ac causes the verifier to run in a mode where it will load classes, ", - "this makes it impossible to run tests such as the class-load and class-prepare ", - "pop-frames because the classes have already been loaded and prepared." - ] - }, - { "tests": ["135-MirandaDispatch"], "variant": "interp-ac & 32 & host", "env_vars": {"SANITIZE_HOST": "address"}, diff --git a/test/run-test b/test/run-test index a599a50589..ef173026c1 100755 --- a/test/run-test +++ b/test/run-test @@ -774,7 +774,7 @@ fi echo "${test_dir}: building..." 1>&2 rm -rf "$tmp_dir" -cp -LRp "$test_dir" "$tmp_dir" +cp -Rp "$test_dir" "$tmp_dir" cd "$tmp_dir" if [ '!' -r "$build" ]; then |