Revert "Revert^2 "JVMTI PopFrame support""
This reverts commit 1c7b1fcf0ff29d83d13d38d0451a54474ccf5964.
Bug: 73255278
Bug: 111357976
bug: 117533193
Reason for revert: Test failures
Change-Id: I9da863fd95264007c4efeb85539e704e83499dcf
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 48f326a..3213bbe 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -313,10 +313,10 @@
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 1218e3b..82f3866 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -249,7 +249,7 @@
.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 @@
// 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 @@
.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 7f3ec40..e98517f 100644
--- a/openjdkjvmti/events-inl.h
+++ b/openjdkjvmti/events-inl.h
@@ -359,7 +359,6 @@
// 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 @@
: 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 @@
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 3ba5d3a..220ad22 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -112,23 +112,6 @@
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 @@
// 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 @@
} 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 55c4269..b41fa4b 100644
--- a/openjdkjvmti/ti_stack.h
+++ b/openjdkjvmti/ti_stack.h
@@ -81,8 +81,6 @@
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 @@
}
}
- 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 15ab5f0..c29043e 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 @@
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 2ae95dc..df66061 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -261,12 +261,6 @@
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 @@
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 @@
// 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 @@
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 @@
} 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 @@
// 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 @@
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 d7e69a6..0d43b90 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -69,12 +69,6 @@
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 dc3cc45..92d4731 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -371,12 +371,6 @@
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 cb64ff4..04935cf 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -24,39 +24,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); \
@@ -67,7 +44,6 @@
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); \
@@ -76,39 +52,8 @@
#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 { \
@@ -122,22 +67,17 @@
}
// 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)
@@ -241,8 +181,7 @@
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);
}
@@ -282,9 +221,6 @@
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);
@@ -1671,84 +1607,84 @@
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: {
@@ -1756,7 +1692,7 @@
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: {
@@ -1764,7 +1700,7 @@
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: {
@@ -1772,7 +1708,7 @@
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: {
@@ -1780,7 +1716,7 @@
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 c385fb9..fbc96f7 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -152,11 +152,6 @@
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 9854f8f..91371d1 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -49,17 +49,6 @@
// - 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 @@
}
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 @@
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 @@
}
}
- 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 @@
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 c9131b5..a48f1fe 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -257,7 +257,6 @@
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 398a48d..478ff50 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -654,14 +654,6 @@
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_;
}
@@ -994,10 +986,6 @@
// 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 afb2c28..4a3d8cb 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3368,51 +3368,22 @@
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 10b87cc..0000000
--- a/test/1953-pop-frame/check
+++ /dev/null
@@ -1,21 +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. Some configurations cannot handle the class load events in
-# quite the right way so they are disabled there too.
-./default-check "$@" || \
- (patch -p0 expected.txt < jvm-expected.patch >/dev/null && ./default-check "$@")
diff --git a/test/1953-pop-frame/expected.txt b/test/1953-pop-frame/expected.txt
deleted file mode 100644
index 3439771..0000000
--- 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:104)
- art.Test1953.runTestOn(Test1953.java:53)
- art.Test1953.runTests(Test1953.java:867)
- art.Test1953.run(Test1953.java:654)
- <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:104)
- art.Test1953.runTestOn(Test1953.java:53)
- art.Test1953.runTests(Test1953.java:873)
- art.Test1953.run(Test1953.java:654)
- <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 b5eb546..0000000
--- 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 ff482d1..0000000
--- 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 92c7057..0000000
--- 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 4cd3917..0000000
--- a/test/1953-pop-frame/run
+++ /dev/null
@@ -1,26 +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 we are redefine-stress we need to turn off class-loading tests since that
-# agent affects the location of class-loads, causing the test to fail. On RI we
-# need to turn it off since those events are buggy around pop-frame (see
-# b/116003018).
-ARGS=""
-if [[ "$@" == *--jvmti-redefine-stress* ]] || [[ "$TEST_RUNTIME" == "jvm" ]]; then
- ARGS="--args DISABLE_CLASS_LOAD_TESTS"
-fi
-
-./default-run "$@" --jvmti $ARGS
diff --git a/test/1953-pop-frame/src/Main.java b/test/1953-pop-frame/src/Main.java
deleted file mode 100644
index 156076e..0000000
--- a/test/1953-pop-frame/src/Main.java
+++ /dev/null
@@ -1,23 +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.util.Arrays;
-import java.util.List;
-public class Main {
- public static void main(String[] args) throws Exception {
- art.Test1953.run(!Arrays.asList(args).contains("DISABLE_CLASS_LOAD_TESTS"));
- }
-}
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 bbb89f7..0000000
--- 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 56d2938..0000000
--- 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 2ea2f20..0000000
--- 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 16e62cc..0000000
--- 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 91437d5..0000000
--- a/test/1953-pop-frame/src/art/Test1953.java
+++ /dev/null
@@ -1,911 +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 final boolean canRunClassLoadTests;
- 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(boolean canRunClassLoadTests) throws Exception {
- new Test1953(canRunClassLoadTests, (x)-> {}).runTests();
- }
-
- public static void run() throws Exception {
- run(IS_ART);
- }
-
- public Test1953(boolean canRunClassLoadTests, Consumer<Object> preTest) {
- this.canRunClassLoadTests = canRunClassLoadTests;
- 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);
-
- // These tests might be disabled for either the RI (b/116003018) or for jvmti-stress. For the
- // later it is due to the additional agent causing classes to be loaded earlier as it forces
- // deeper verification during class redefinition, causing failures.
- if (canRunClassLoadTests) {
- // 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 10b87cc..0000000
--- a/test/1954-pop-frame-jit/check
+++ /dev/null
@@ -1,21 +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. Some configurations cannot handle the class load events in
-# quite the right way so they are disabled there too.
-./default-check "$@" || \
- (patch -p0 expected.txt < jvm-expected.patch >/dev/null && ./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 81f1ec8..0000000
--- 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:104)
- art.Test1953.runTestOn(Test1953.java:53)
- art.Test1953.runTests(Test1953.java:867)
- <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:104)
- art.Test1953.runTestOn(Test1953.java:53)
- art.Test1953.runTests(Test1953.java:873)
- <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 b5eb546..0000000
--- 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 ff482d1..0000000
--- 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 4cd3917..0000000
--- a/test/1954-pop-frame-jit/run
+++ /dev/null
@@ -1,26 +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 we are redefine-stress we need to turn off class-loading tests since that
-# agent affects the location of class-loads, causing the test to fail. On RI we
-# need to turn it off since those events are buggy around pop-frame (see
-# b/116003018).
-ARGS=""
-if [[ "$@" == *--jvmti-redefine-stress* ]] || [[ "$TEST_RUNTIME" == "jvm" ]]; then
- ARGS="--args DISABLE_CLASS_LOAD_TESTS"
-fi
-
-./default-run "$@" --jvmti $ARGS
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 12defcd..0000000
--- 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(boolean run_class_load_tests) {
- super(run_class_load_tests, (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(!Arrays.asList(args).contains("DISABLE_CLASS_LOAD_TESTS")).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 bbb89f7..0000000
--- 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 56d2938..0000000
--- 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 2ea2f20..0000000
--- 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 16e62cc..0000000
--- 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 f281434..0000000
--- 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 8c1c1bf..8f23058 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -291,7 +291,6 @@
"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 @@
"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 65127fc..4967834 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 @@
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 @@
}
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 6a2a040..a7fb189 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1087,15 +1087,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 0f316bc..6a36055 100755
--- a/test/run-test
+++ b/test/run-test
@@ -767,7 +767,7 @@
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