diff options
| -rw-r--r-- | runtime/art_method-inl.h | 6 | ||||
| -rw-r--r-- | runtime/art_method.h | 3 | ||||
| -rw-r--r-- | runtime/debugger.cc | 54 | ||||
| -rw-r--r-- | runtime/instrumentation.cc | 125 | ||||
| -rw-r--r-- | runtime/instrumentation.h | 106 | ||||
| -rw-r--r-- | runtime/instrumentation_test.cc | 184 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_switch_impl.cc | 2 | ||||
| -rw-r--r-- | runtime/trace.cc | 28 | ||||
| -rw-r--r-- | runtime/trace.h | 48 | ||||
| -rw-r--r-- | test/Instrumentation/Instrumentation.java | 13 |
10 files changed, 437 insertions, 132 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index d1afcb8dd3..07ca35fb00 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -36,7 +36,9 @@ #include "mirror/string.h" #include "oat.h" #include "obj_ptr-inl.h" +#include "primitive.h" #include "quick/quick_method_frame_info.h" +#include "read_barrier-inl.h" #include "runtime-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" @@ -340,6 +342,10 @@ inline const char* ArtMethod::GetReturnTypeDescriptor() { return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_)); } +inline Primitive::Type ArtMethod::GetReturnTypePrimitive() { + return Primitive::GetType(GetReturnTypeDescriptor()[0]); +} + inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) { DCHECK(!IsProxyMethod()); const DexFile* dex_file = GetDexFile(); diff --git a/runtime/art_method.h b/runtime/art_method.h index d8dfdd7959..3a8d279606 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -27,6 +27,7 @@ #include "modifiers.h" #include "obj_ptr.h" #include "offsets.h" +#include "primitive.h" #include "read_barrier_option.h" namespace art { @@ -569,6 +570,8 @@ class ArtMethod FINAL { const char* GetReturnTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE Primitive::Type GetReturnTypePrimitive() REQUIRES_SHARED(Locks::mutator_lock_); + const char* GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/debugger.cc b/runtime/debugger.cc index cfa56a5769..7e70b7564c 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -149,7 +149,9 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati DebugInstrumentationListener() {} virtual ~DebugInstrumentationListener() {} - void MethodEntered(Thread* thread, mirror::Object* this_object, ArtMethod* method, + void MethodEntered(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, uint32_t dex_pc) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { if (method->IsNative()) { @@ -171,12 +173,15 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati // also group it with other events for this location like BREAKPOINT or SINGLE_STEP. thread->SetDebugMethodEntry(); } else { - Dbg::UpdateDebugger(thread, this_object, method, 0, Dbg::kMethodEntry, nullptr); + Dbg::UpdateDebugger(thread, this_object.Get(), method, 0, Dbg::kMethodEntry, nullptr); } } - void MethodExited(Thread* thread, mirror::Object* this_object, ArtMethod* method, - uint32_t dex_pc, const JValue& return_value) + void MethodExited(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + const JValue& return_value) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { if (method->IsNative()) { // TODO: post location events is a suspension point and native method entry stubs aren't. @@ -189,18 +194,22 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati events |= Dbg::kMethodEntry; thread->ClearDebugMethodEntry(); } - Dbg::UpdateDebugger(thread, this_object, method, dex_pc, events, &return_value); + Dbg::UpdateDebugger(thread, this_object.Get(), method, dex_pc, events, &return_value); } - void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object ATTRIBUTE_UNUSED, - ArtMethod* method, uint32_t dex_pc) + void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, + ArtMethod* method, + uint32_t dex_pc) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { // We're not recorded to listen to this kind of event, so complain. LOG(ERROR) << "Unexpected method unwind event in debugger " << ArtMethod::PrettyMethod(method) << " " << dex_pc; } - void DexPcMoved(Thread* thread, mirror::Object* this_object, ArtMethod* method, + void DexPcMoved(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, uint32_t new_dex_pc) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { if (IsListeningToMethodExit() && IsReturn(method, new_dex_pc)) { @@ -217,26 +226,33 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati events = Dbg::kMethodEntry; thread->ClearDebugMethodEntry(); } - Dbg::UpdateDebugger(thread, this_object, method, new_dex_pc, events, nullptr); + Dbg::UpdateDebugger(thread, this_object.Get(), method, new_dex_pc, events, nullptr); } } - void FieldRead(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, ArtField* field) + void FieldRead(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - Dbg::PostFieldAccessEvent(method, dex_pc, this_object, field); + Dbg::PostFieldAccessEvent(method, dex_pc, this_object.Get(), field); } - void FieldWritten(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, ArtField* field, + void FieldWritten(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, const JValue& field_value) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - Dbg::PostFieldModificationEvent(method, dex_pc, this_object, field, &field_value); + Dbg::PostFieldModificationEvent(method, dex_pc, this_object.Get(), field, &field_value); } - void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, mirror::Throwable* exception_object) + void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Throwable> exception_object) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - Dbg::PostException(exception_object); + Dbg::PostException(exception_object.Get()); } // We only care about branches in the Jit. @@ -248,10 +264,10 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati // We only care about invokes in the Jit. void InvokeVirtualOrInterface(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object*, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method, uint32_t dex_pc, - ArtMethod*) + ArtMethod* target ATTRIBUTE_UNUSED) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { LOG(ERROR) << "Unexpected invoke event in debugger " << ArtMethod::PrettyMethod(method) << " " << dex_pc; diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index d862ff2708..540b2e7e9b 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -20,6 +20,7 @@ #include "arch/context.h" #include "art_method-inl.h" +#include "art_field-inl.h" #include "atomic.h" #include "class_linker.h" #include "debugger.h" @@ -31,6 +32,7 @@ #include "interpreter/interpreter.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" +#include "jvalue-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" #include "mirror/object_array-inl.h" @@ -45,6 +47,30 @@ namespace instrumentation { constexpr bool kVerboseInstrumentation = false; +void InstrumentationListener::MethodExited(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + Handle<mirror::Object> return_value) { + DCHECK_EQ(method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetReturnTypePrimitive(), + Primitive::kPrimNot); + JValue v; + v.SetL(return_value.Get()); + MethodExited(thread, this_object, method, dex_pc, v); +} + +void InstrumentationListener::FieldWritten(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, + Handle<mirror::Object> field_value) { + DCHECK(!field->IsPrimitiveType()); + JValue v; + v.SetL(field_value.Get()); + FieldWritten(thread, this_object, method, dex_pc, field, v); +} + // Instrumentation works on non-inlined frames by updating returned PCs // of compiled frames. static constexpr StackVisitor::StackWalkKind kInstrumentationStackWalk = @@ -916,48 +942,75 @@ const void* Instrumentation::GetQuickCodeFor(ArtMethod* method, PointerSize poin return class_linker->GetQuickOatCodeFor(method); } -void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object, +void Instrumentation::MethodEnterEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, ArtMethod* method, uint32_t dex_pc) const { if (HasMethodEntryListeners()) { + Thread* self = Thread::Current(); + StackHandleScope<1> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); for (InstrumentationListener* listener : method_entry_listeners_) { if (listener != nullptr) { - listener->MethodEntered(thread, this_object, method, dex_pc); + listener->MethodEntered(thread, thiz, method, dex_pc); } } } } -void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object, +void Instrumentation::MethodExitEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, ArtMethod* method, - uint32_t dex_pc, const JValue& return_value) const { + uint32_t dex_pc, + const JValue& return_value) const { if (HasMethodExitListeners()) { - for (InstrumentationListener* listener : method_exit_listeners_) { - if (listener != nullptr) { - listener->MethodExited(thread, this_object, method, dex_pc, return_value); + Thread* self = Thread::Current(); + StackHandleScope<2> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); + if (method->GetInterfaceMethodIfProxy(kRuntimePointerSize) + ->GetReturnTypePrimitive() != Primitive::kPrimNot) { + for (InstrumentationListener* listener : method_exit_listeners_) { + if (listener != nullptr) { + listener->MethodExited(thread, thiz, method, dex_pc, return_value); + } + } + } else { + Handle<mirror::Object> ret(hs.NewHandle(return_value.GetL())); + for (InstrumentationListener* listener : method_exit_listeners_) { + if (listener != nullptr) { + listener->MethodExited(thread, thiz, method, dex_pc, ret); + } } } } } -void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object, +void Instrumentation::MethodUnwindEvent(Thread* thread, + mirror::Object* this_object, ArtMethod* method, uint32_t dex_pc) const { if (HasMethodUnwindListeners()) { + Thread* self = Thread::Current(); + StackHandleScope<1> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); for (InstrumentationListener* listener : method_unwind_listeners_) { if (listener != nullptr) { - listener->MethodUnwind(thread, this_object, method, dex_pc); + listener->MethodUnwind(thread, thiz, method, dex_pc); } } } } -void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object, +void Instrumentation::DexPcMovedEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, ArtMethod* method, uint32_t dex_pc) const { + Thread* self = Thread::Current(); + StackHandleScope<1> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); for (InstrumentationListener* listener : dex_pc_listeners_) { if (listener != nullptr) { - listener->DexPcMoved(thread, this_object, method, dex_pc); + listener->DexPcMoved(thread, thiz, method, dex_pc); } } } @@ -974,36 +1027,56 @@ void Instrumentation::BranchImpl(Thread* thread, } void Instrumentation::InvokeVirtualOrInterfaceImpl(Thread* thread, - mirror::Object* this_object, + ObjPtr<mirror::Object> this_object, ArtMethod* caller, uint32_t dex_pc, ArtMethod* callee) const { - // We cannot have thread suspension since that would cause the this_object parameter to - // potentially become a dangling pointer. An alternative could be to put it in a handle instead. - ScopedAssertNoThreadSuspension ants(__FUNCTION__); + Thread* self = Thread::Current(); + StackHandleScope<1> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); for (InstrumentationListener* listener : invoke_virtual_or_interface_listeners_) { if (listener != nullptr) { - listener->InvokeVirtualOrInterface(thread, this_object, caller, dex_pc, callee); + listener->InvokeVirtualOrInterface(thread, thiz, caller, dex_pc, callee); } } } -void Instrumentation::FieldReadEventImpl(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, +void Instrumentation::FieldReadEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, ArtField* field) const { + Thread* self = Thread::Current(); + StackHandleScope<1> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); for (InstrumentationListener* listener : field_read_listeners_) { if (listener != nullptr) { - listener->FieldRead(thread, this_object, method, dex_pc, field); + listener->FieldRead(thread, thiz, method, dex_pc, field); } } } -void Instrumentation::FieldWriteEventImpl(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, - ArtField* field, const JValue& field_value) const { - for (InstrumentationListener* listener : field_write_listeners_) { - if (listener != nullptr) { - listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value); +void Instrumentation::FieldWriteEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, + const JValue& field_value) const { + Thread* self = Thread::Current(); + StackHandleScope<2> hs(self); + Handle<mirror::Object> thiz(hs.NewHandle(this_object)); + if (field->IsPrimitiveType()) { + for (InstrumentationListener* listener : field_write_listeners_) { + if (listener != nullptr) { + listener->FieldWritten(thread, thiz, method, dex_pc, field, field_value); + } + } + } else { + Handle<mirror::Object> val(hs.NewHandle(field_value.GetL())); + for (InstrumentationListener* listener : field_write_listeners_) { + if (listener != nullptr) { + listener->FieldWritten(thread, thiz, method, dex_pc, field, val); + } } } } @@ -1018,7 +1091,7 @@ void Instrumentation::ExceptionCaughtEvent(Thread* thread, thread->ClearException(); for (InstrumentationListener* listener : exception_caught_listeners_) { if (listener != nullptr) { - listener->ExceptionCaught(thread, h_exception.Get()); + listener->ExceptionCaught(thread, h_exception); } } thread->SetException(h_exception.Get()); diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index 01071a541f..363985fd62 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -36,6 +36,7 @@ namespace mirror { } // namespace mirror class ArtField; class ArtMethod; +template <typename T> class Handle; union JValue; class Thread; @@ -62,37 +63,70 @@ struct InstrumentationListener { virtual ~InstrumentationListener() {} // Call-back for when a method is entered. - virtual void MethodEntered(Thread* thread, mirror::Object* this_object, + virtual void MethodEntered(Thread* thread, + Handle<mirror::Object> this_object, ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) = 0; - // Call-back for when a method is exited. - virtual void MethodExited(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, + virtual void MethodExited(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + Handle<mirror::Object> return_value) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Call-back for when a method is exited. The implementor should either handler-ize the return + // value (if appropriate) or use the alternate MethodExited callback instead if they need to + // go through a suspend point. + virtual void MethodExited(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, const JValue& return_value) REQUIRES_SHARED(Locks::mutator_lock_) = 0; // Call-back for when a method is popped due to an exception throw. A method will either cause a // MethodExited call-back or a MethodUnwind call-back when its activation is removed. - virtual void MethodUnwind(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc) + virtual void MethodUnwind(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) = 0; // Call-back for when the dex pc moves in a method. - virtual void DexPcMoved(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t new_dex_pc) + virtual void DexPcMoved(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t new_dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) = 0; // Call-back for when we read from a field. - virtual void FieldRead(Thread* thread, mirror::Object* this_object, ArtMethod* method, - uint32_t dex_pc, ArtField* field) = 0; + virtual void FieldRead(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field) = 0; + + virtual void FieldWritten(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, + Handle<mirror::Object> field_value) + REQUIRES_SHARED(Locks::mutator_lock_); // Call-back for when we write into a field. - virtual void FieldWritten(Thread* thread, mirror::Object* this_object, ArtMethod* method, - uint32_t dex_pc, ArtField* field, const JValue& field_value) = 0; + virtual void FieldWritten(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, + const JValue& field_value) + REQUIRES_SHARED(Locks::mutator_lock_) = 0; // Call-back when an exception is caught. - virtual void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object) + virtual void ExceptionCaught(Thread* thread, + Handle<mirror::Throwable> exception_object) REQUIRES_SHARED(Locks::mutator_lock_) = 0; // Call-back for when we execute a branch. @@ -104,11 +138,10 @@ struct InstrumentationListener { // Call-back for when we get an invokevirtual or an invokeinterface. virtual void InvokeVirtualOrInterface(Thread* thread, - mirror::Object* this_object, + Handle<mirror::Object> this_object, ArtMethod* caller, uint32_t dex_pc, ArtMethod* callee) - REQUIRES(Roles::uninterruptible_) REQUIRES_SHARED(Locks::mutator_lock_) = 0; }; @@ -323,8 +356,10 @@ class Instrumentation { } // Inform listeners that a method has been exited. - void MethodExitEvent(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, + void MethodExitEvent(Thread* thread, + mirror::Object* this_object, + ArtMethod* method, + uint32_t dex_pc, const JValue& return_value) const REQUIRES_SHARED(Locks::mutator_lock_) { if (UNLIKELY(HasMethodExitListeners())) { @@ -465,31 +500,42 @@ class Instrumentation { // exclusive access to mutator lock which you can't get if the runtime isn't started. void SetEntrypointsInstrumented(bool instrumented) NO_THREAD_SAFETY_ANALYSIS; - void MethodEnterEventImpl(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc) const + void MethodEnterEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc) const REQUIRES_SHARED(Locks::mutator_lock_); - void MethodExitEventImpl(Thread* thread, mirror::Object* this_object, + void MethodExitEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, ArtMethod* method, - uint32_t dex_pc, const JValue& return_value) const + uint32_t dex_pc, + const JValue& return_value) const REQUIRES_SHARED(Locks::mutator_lock_); - void DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc) const + void DexPcMovedEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc) const REQUIRES_SHARED(Locks::mutator_lock_); void BranchImpl(Thread* thread, ArtMethod* method, uint32_t dex_pc, int32_t offset) const REQUIRES_SHARED(Locks::mutator_lock_); void InvokeVirtualOrInterfaceImpl(Thread* thread, - mirror::Object* this_object, + ObjPtr<mirror::Object> this_object, ArtMethod* caller, uint32_t dex_pc, ArtMethod* callee) const REQUIRES_SHARED(Locks::mutator_lock_); - void FieldReadEventImpl(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, - ArtField* field) const + void FieldReadEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_); - void FieldWriteEventImpl(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, - ArtField* field, const JValue& field_value) const + void FieldWriteEventImpl(Thread* thread, + ObjPtr<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, + const JValue& field_value) const REQUIRES_SHARED(Locks::mutator_lock_); // Read barrier-aware utility functions for accessing deoptimized_methods_ diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc index 9926ee7386..2a601c9cf2 100644 --- a/runtime/instrumentation_test.cc +++ b/runtime/instrumentation_test.cc @@ -23,11 +23,13 @@ #include "dex_file.h" #include "gc/scoped_gc_critical_section.h" #include "handle_scope-inl.h" +#include "jni_internal.h" #include "jvalue.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "thread_list.h" -#include "thread-current-inl.h" +#include "thread-inl.h" +#include "well_known_classes.h" namespace art { namespace instrumentation { @@ -35,16 +37,22 @@ namespace instrumentation { class TestInstrumentationListener FINAL : public instrumentation::InstrumentationListener { public: TestInstrumentationListener() - : received_method_enter_event(false), received_method_exit_event(false), - received_method_unwind_event(false), received_dex_pc_moved_event(false), - received_field_read_event(false), received_field_written_event(false), - received_exception_caught_event(false), received_branch_event(false), + : received_method_enter_event(false), + received_method_exit_event(false), + received_method_exit_object_event(false), + received_method_unwind_event(false), + received_dex_pc_moved_event(false), + received_field_read_event(false), + received_field_written_event(false), + received_field_written_object_event(false), + received_exception_caught_event(false), + received_branch_event(false), received_invoke_virtual_or_interface_event(false) {} virtual ~TestInstrumentationListener() {} void MethodEntered(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { @@ -52,7 +60,16 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void MethodExited(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, + ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + Handle<mirror::Object> return_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + received_method_exit_object_event = true; + } + + void MethodExited(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, const JValue& return_value ATTRIBUTE_UNUSED) @@ -61,7 +78,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { @@ -69,7 +86,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void DexPcMoved(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t new_dex_pc ATTRIBUTE_UNUSED) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { @@ -77,7 +94,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void FieldRead(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, ArtField* field ATTRIBUTE_UNUSED) @@ -86,7 +103,17 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void FieldWritten(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, + ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + ArtField* field ATTRIBUTE_UNUSED, + Handle<mirror::Object> field_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + received_field_written_object_event = true; + } + + void FieldWritten(Thread* thread ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, ArtField* field ATTRIBUTE_UNUSED, @@ -96,7 +123,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, - mirror::Throwable* exception_object ATTRIBUTE_UNUSED) + Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { received_exception_caught_event = true; } @@ -110,7 +137,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio } void InvokeVirtualOrInterface(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* caller ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, ArtMethod* callee ATTRIBUTE_UNUSED) @@ -121,10 +148,12 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio void Reset() { received_method_enter_event = false; received_method_exit_event = false; + received_method_exit_object_event = false; received_method_unwind_event = false; received_dex_pc_moved_event = false; received_field_read_event = false; received_field_written_event = false; + received_field_written_object_event = false; received_exception_caught_event = false; received_branch_event = false; received_invoke_virtual_or_interface_event = false; @@ -132,10 +161,12 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio bool received_method_enter_event; bool received_method_exit_event; + bool received_method_exit_object_event; bool received_method_unwind_event; bool received_dex_pc_moved_event; bool received_field_read_event; bool received_field_written_event; + bool received_field_written_object_event; bool received_exception_caught_event; bool received_branch_event; bool received_invoke_virtual_or_interface_event; @@ -171,6 +202,13 @@ class InstrumentationTest : public CommonRuntimeTest { } void TestEvent(uint32_t instrumentation_event) { + TestEvent(instrumentation_event, nullptr, nullptr, false); + } + + void TestEvent(uint32_t instrumentation_event, + ArtMethod* event_method, + ArtField* event_field, + bool with_object) { ScopedObjectAccess soa(Thread::Current()); instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation(); TestInstrumentationListener listener; @@ -180,15 +218,20 @@ class InstrumentationTest : public CommonRuntimeTest { instr->AddListener(&listener, instrumentation_event); } - ArtMethod* const event_method = nullptr; mirror::Object* const event_obj = nullptr; const uint32_t event_dex_pc = 0; // Check the listener is registered and is notified of the event. EXPECT_TRUE(HasEventListener(instr, instrumentation_event)); - EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event)); - ReportEvent(instr, instrumentation_event, soa.Self(), event_method, event_obj, event_dex_pc); - EXPECT_TRUE(DidListenerReceiveEvent(listener, instrumentation_event)); + EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event, with_object)); + ReportEvent(instr, + instrumentation_event, + soa.Self(), + event_method, + event_obj, + event_field, + event_dex_pc); + EXPECT_TRUE(DidListenerReceiveEvent(listener, instrumentation_event, with_object)); listener.Reset(); { @@ -199,9 +242,15 @@ class InstrumentationTest : public CommonRuntimeTest { // Check the listener is not registered and is not notified of the event. EXPECT_FALSE(HasEventListener(instr, instrumentation_event)); - EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event)); - ReportEvent(instr, instrumentation_event, soa.Self(), event_method, event_obj, event_dex_pc); - EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event)); + EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event, with_object)); + ReportEvent(instr, + instrumentation_event, + soa.Self(), + event_method, + event_obj, + event_field, + event_dex_pc); + EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event, with_object)); } void DeoptimizeMethod(Thread* self, ArtMethod* method, bool enable_deoptimization) @@ -317,8 +366,12 @@ class InstrumentationTest : public CommonRuntimeTest { } } - static void ReportEvent(const instrumentation::Instrumentation* instr, uint32_t event_type, - Thread* self, ArtMethod* method, mirror::Object* obj, + static void ReportEvent(const instrumentation::Instrumentation* instr, + uint32_t event_type, + Thread* self, + ArtMethod* method, + mirror::Object* obj, + ArtField* field, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) { switch (event_type) { @@ -337,11 +390,11 @@ class InstrumentationTest : public CommonRuntimeTest { instr->DexPcMovedEvent(self, obj, method, dex_pc); break; case instrumentation::Instrumentation::kFieldRead: - instr->FieldReadEvent(self, obj, method, dex_pc, nullptr); + instr->FieldReadEvent(self, obj, method, dex_pc, field); break; case instrumentation::Instrumentation::kFieldWritten: { JValue value; - instr->FieldWriteEvent(self, obj, method, dex_pc, nullptr, value); + instr->FieldWriteEvent(self, obj, method, dex_pc, field, value); break; } case instrumentation::Instrumentation::kExceptionCaught: { @@ -364,12 +417,14 @@ class InstrumentationTest : public CommonRuntimeTest { } static bool DidListenerReceiveEvent(const TestInstrumentationListener& listener, - uint32_t event_type) { + uint32_t event_type, + bool with_object) { switch (event_type) { case instrumentation::Instrumentation::kMethodEntered: return listener.received_method_enter_event; case instrumentation::Instrumentation::kMethodExited: - return listener.received_method_exit_event; + return (!with_object && listener.received_method_exit_event) || + (with_object && listener.received_method_exit_object_event); case instrumentation::Instrumentation::kMethodUnwind: return listener.received_method_unwind_event; case instrumentation::Instrumentation::kDexPcMoved: @@ -377,7 +432,8 @@ class InstrumentationTest : public CommonRuntimeTest { case instrumentation::Instrumentation::kFieldRead: return listener.received_field_read_event; case instrumentation::Instrumentation::kFieldWritten: - return listener.received_field_written_event; + return (!with_object && listener.received_field_written_event) || + (with_object && listener.received_field_written_object_event); case instrumentation::Instrumentation::kExceptionCaught: return listener.received_exception_caught_event; case instrumentation::Instrumentation::kBranch: @@ -419,8 +475,42 @@ TEST_F(InstrumentationTest, MethodEntryEvent) { TestEvent(instrumentation::Instrumentation::kMethodEntered); } -TEST_F(InstrumentationTest, MethodExitEvent) { - TestEvent(instrumentation::Instrumentation::kMethodExited); +TEST_F(InstrumentationTest, MethodExitObjectEvent) { + ScopedObjectAccess soa(Thread::Current()); + jobject class_loader = LoadDex("Instrumentation"); + Runtime* const runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); + mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ASSERT_TRUE(klass != nullptr); + ArtMethod* method = klass->FindDeclaredDirectMethod("returnReference", + "()Ljava/lang/Object;", + kRuntimePointerSize); + ASSERT_TRUE(method != nullptr); + TestEvent(instrumentation::Instrumentation::kMethodExited, + /*event_method*/ method, + /*event_field*/ nullptr, + /*with_object*/ true); +} + +TEST_F(InstrumentationTest, MethodExitPrimEvent) { + ScopedObjectAccess soa(Thread::Current()); + jobject class_loader = LoadDex("Instrumentation"); + Runtime* const runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); + mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ASSERT_TRUE(klass != nullptr); + ArtMethod* method = klass->FindDeclaredDirectMethod("returnPrimitive", + "()I", + kRuntimePointerSize); + ASSERT_TRUE(method != nullptr); + TestEvent(instrumentation::Instrumentation::kMethodExited, + /*event_method*/ method, + /*event_field*/ nullptr, + /*with_object*/ false); } TEST_F(InstrumentationTest, MethodUnwindEvent) { @@ -435,8 +525,40 @@ TEST_F(InstrumentationTest, FieldReadEvent) { TestEvent(instrumentation::Instrumentation::kFieldRead); } -TEST_F(InstrumentationTest, FieldWriteEvent) { - TestEvent(instrumentation::Instrumentation::kFieldWritten); +TEST_F(InstrumentationTest, FieldWriteObjectEvent) { + ScopedObjectAccess soa(Thread::Current()); + jobject class_loader = LoadDex("Instrumentation"); + Runtime* const runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); + mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ASSERT_TRUE(klass != nullptr); + ArtField* field = klass->FindDeclaredStaticField("referenceField", "Ljava/lang/Object;"); + ASSERT_TRUE(field != nullptr); + + TestEvent(instrumentation::Instrumentation::kFieldWritten, + /*event_method*/ nullptr, + /*event_field*/ field, + /*with_object*/ true); +} + +TEST_F(InstrumentationTest, FieldWritePrimEvent) { + ScopedObjectAccess soa(Thread::Current()); + jobject class_loader = LoadDex("Instrumentation"); + Runtime* const runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); + mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ASSERT_TRUE(klass != nullptr); + ArtField* field = klass->FindDeclaredStaticField("primitiveField", "I"); + ASSERT_TRUE(field != nullptr); + + TestEvent(instrumentation::Instrumentation::kFieldWritten, + /*event_method*/ nullptr, + /*event_field*/ field, + /*with_object*/ false); } TEST_F(InstrumentationTest, ExceptionCaughtEvent) { diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index b191dd79a1..32a23783b7 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -307,6 +307,8 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), inst->GetDexPc(insns), result); + // Re-load since it might have moved during the MethodExitEvent. + result.SetL(shadow_frame.GetVRegReference(ref_idx)); } if (interpret_one_instruction) { /* Signal mterp to return to caller */ diff --git a/runtime/trace.cc b/runtime/trace.cc index 3550d56bd8..cabd1620a7 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -740,7 +740,7 @@ void Trace::FinishTracing() { } void Trace::DexPcMoved(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method, uint32_t new_dex_pc) { // We're not recorded to listen to this kind of event, so complain. @@ -749,7 +749,7 @@ void Trace::DexPcMoved(Thread* thread ATTRIBUTE_UNUSED, } void Trace::FieldRead(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method, uint32_t dex_pc, ArtField* field ATTRIBUTE_UNUSED) @@ -760,7 +760,7 @@ void Trace::FieldRead(Thread* thread ATTRIBUTE_UNUSED, } void Trace::FieldWritten(Thread* thread ATTRIBUTE_UNUSED, - mirror::Object* this_object ATTRIBUTE_UNUSED, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, ArtMethod* method, uint32_t dex_pc, ArtField* field ATTRIBUTE_UNUSED, @@ -771,8 +771,10 @@ void Trace::FieldWritten(Thread* thread ATTRIBUTE_UNUSED, << " " << dex_pc; } -void Trace::MethodEntered(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED, - ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) { +void Trace::MethodEntered(Thread* thread, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, + ArtMethod* method, + uint32_t dex_pc ATTRIBUTE_UNUSED) { uint32_t thread_clock_diff = 0; uint32_t wall_clock_diff = 0; ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); @@ -780,8 +782,10 @@ void Trace::MethodEntered(Thread* thread, mirror::Object* this_object ATTRIBUTE_ thread_clock_diff, wall_clock_diff); } -void Trace::MethodExited(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED, - ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED, +void Trace::MethodExited(Thread* thread, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, + ArtMethod* method, + uint32_t dex_pc ATTRIBUTE_UNUSED, const JValue& return_value ATTRIBUTE_UNUSED) { uint32_t thread_clock_diff = 0; uint32_t wall_clock_diff = 0; @@ -790,8 +794,10 @@ void Trace::MethodExited(Thread* thread, mirror::Object* this_object ATTRIBUTE_U thread_clock_diff, wall_clock_diff); } -void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED, - ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) { +void Trace::MethodUnwind(Thread* thread, + Handle<mirror::Object> this_object ATTRIBUTE_UNUSED, + ArtMethod* method, + uint32_t dex_pc ATTRIBUTE_UNUSED) { uint32_t thread_clock_diff = 0; uint32_t wall_clock_diff = 0; ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); @@ -800,7 +806,7 @@ void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object ATTRIBUTE_U } void Trace::ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, - mirror::Throwable* exception_object ATTRIBUTE_UNUSED) + Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED) REQUIRES_SHARED(Locks::mutator_lock_) { LOG(ERROR) << "Unexpected exception caught event in tracing"; } @@ -812,7 +818,7 @@ void Trace::Branch(Thread* /*thread*/, ArtMethod* method, } void Trace::InvokeVirtualOrInterface(Thread*, - mirror::Object*, + Handle<mirror::Object>, ArtMethod* method, uint32_t dex_pc, ArtMethod*) { diff --git a/runtime/trace.h b/runtime/trace.h index 485e9a133a..ad1025045c 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -140,36 +140,54 @@ class Trace FINAL : public instrumentation::InstrumentationListener { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_); // InstrumentationListener implementation. - void MethodEntered(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc) + void MethodEntered(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_) OVERRIDE; - void MethodExited(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, + void MethodExited(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, const JValue& return_value) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_) OVERRIDE; - void MethodUnwind(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc) + void MethodUnwind(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_) OVERRIDE; - void DexPcMoved(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t new_dex_pc) + void DexPcMoved(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t new_dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_) OVERRIDE; - void FieldRead(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, ArtField* field) + void FieldRead(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE; - void FieldWritten(Thread* thread, mirror::Object* this_object, - ArtMethod* method, uint32_t dex_pc, ArtField* field, + void FieldWritten(Thread* thread, + Handle<mirror::Object> this_object, + ArtMethod* method, + uint32_t dex_pc, + ArtField* field, const JValue& field_value) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE; - void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object) + void ExceptionCaught(Thread* thread, + Handle<mirror::Throwable> exception_object) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE; - void Branch(Thread* thread, ArtMethod* method, uint32_t dex_pc, int32_t dex_pc_offset) + void Branch(Thread* thread, + ArtMethod* method, + uint32_t dex_pc, + int32_t dex_pc_offset) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE; void InvokeVirtualOrInterface(Thread* thread, - mirror::Object* this_object, + Handle<mirror::Object> this_object, ArtMethod* caller, uint32_t dex_pc, ArtMethod* callee) diff --git a/test/Instrumentation/Instrumentation.java b/test/Instrumentation/Instrumentation.java index 09d434213b..b44f78fc3b 100644 --- a/test/Instrumentation/Instrumentation.java +++ b/test/Instrumentation/Instrumentation.java @@ -15,8 +15,21 @@ */ public class Instrumentation { + private static int primitiveField; + private static Object referenceField; + // Direct method private void instanceMethod() { System.out.println("instanceMethod"); } + + private Object returnReference() { + System.out.println("returnReference"); + return null; + } + + private int returnPrimitive() { + System.out.println("returnPrimitive"); + return 0; + } } |