diff options
-rw-r--r-- | runtime/debugger.cc | 6 | ||||
-rw-r--r-- | runtime/jni_internal.cc | 97 | ||||
-rw-r--r-- | runtime/jvalue-inl.h | 18 | ||||
-rw-r--r-- | runtime/jvalue.h | 2 |
4 files changed, 116 insertions, 7 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 7e70b7564c..12bdb32fec 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -2927,7 +2927,8 @@ void Dbg::PostLocationEvent(ArtMethod* m, int dex_pc, mirror::Object* this_objec void Dbg::PostFieldAccessEvent(ArtMethod* m, int dex_pc, mirror::Object* this_object, ArtField* f) { - if (!IsDebuggerActive()) { + // TODO We should send events for native methods. + if (!IsDebuggerActive() || m->IsNative()) { return; } DCHECK(m != nullptr); @@ -2941,7 +2942,8 @@ void Dbg::PostFieldAccessEvent(ArtMethod* m, int dex_pc, void Dbg::PostFieldModificationEvent(ArtMethod* m, int dex_pc, mirror::Object* this_object, ArtField* f, const JValue* field_value) { - if (!IsDebuggerActive()) { + // TODO We should send events for native methods. + if (!IsDebuggerActive() || m->IsNative()) { return; } DCHECK(m != nullptr); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 6be0953727..0aabbea2c0 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -40,6 +40,7 @@ #include "interpreter/interpreter.h" #include "jni_env_ext.h" #include "java_vm_ext.h" +#include "jvalue-inl.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/field-inl.h" @@ -64,6 +65,84 @@ namespace art { // things not rendering correctly. E.g. b/16858794 static constexpr bool kWarnJniAbort = false; +// Helpers to call instrumentation functions for fields. These take jobjects so we don't need to set +// up handles for the rare case where these actually do something. Once these functions return it is +// possible there will be a pending exception if the instrumentation happens to throw one. +static void NotifySetObjectField(ArtField* field, jobject obj, jobject jval) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK_EQ(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldWriteListeners())) { + Thread* self = Thread::Current(); + ArtMethod* cur_method = self->GetCurrentMethod(/*dex_pc*/ nullptr, + /*check_suspended*/ true, + /*abort_on_error*/ false); + + if (cur_method == nullptr) { + // Set/Get Fields can be issued without a method during runtime startup/teardown. Ignore all + // of these changes. + return; + } + DCHECK(cur_method->IsNative()); + JValue val; + val.SetL(self->DecodeJObject(jval)); + instrumentation->FieldWriteEvent(self, + self->DecodeJObject(obj).Ptr(), + cur_method, + 0, // dex_pc is always 0 since this is a native method. + field, + val); + } +} + +static void NotifySetPrimitiveField(ArtField* field, jobject obj, JValue val) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldWriteListeners())) { + Thread* self = Thread::Current(); + ArtMethod* cur_method = self->GetCurrentMethod(/*dex_pc*/ nullptr, + /*check_suspended*/ true, + /*abort_on_error*/ false); + + if (cur_method == nullptr) { + // Set/Get Fields can be issued without a method during runtime startup/teardown. Ignore all + // of these changes. + return; + } + DCHECK(cur_method->IsNative()); + instrumentation->FieldWriteEvent(self, + self->DecodeJObject(obj).Ptr(), + cur_method, + 0, // dex_pc is always 0 since this is a native method. + field, + val); + } +} + +static void NotifyGetField(ArtField* field, jobject obj) + REQUIRES_SHARED(Locks::mutator_lock_) { + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldReadListeners())) { + Thread* self = Thread::Current(); + ArtMethod* cur_method = self->GetCurrentMethod(/*dex_pc*/ nullptr, + /*check_suspended*/ true, + /*abort_on_error*/ false); + + if (cur_method == nullptr) { + // Set/Get Fields can be issued without a method during runtime startup/teardown. Ignore all + // of these changes. + return; + } + DCHECK(cur_method->IsNative()); + instrumentation->FieldReadEvent(self, + self->DecodeJObject(obj).Ptr(), + cur_method, + 0, // dex_pc is always 0 since this is a native method. + field); + } +} + // Section 12.3.2 of the JNI spec describes JNI class descriptors. They're // separated with slashes but aren't wrapped with "L;" like regular descriptors // (i.e. "a/b/C" rather than "La/b/C;"). Arrays of reference types are an @@ -1235,8 +1314,9 @@ class JNI { CHECK_NON_NULL_ARGUMENT(obj); CHECK_NON_NULL_ARGUMENT(fid); ScopedObjectAccess soa(env); - ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj); ArtField* f = jni::DecodeArtField(fid); + NotifyGetField(f, obj); + ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj); return soa.AddLocalReference<jobject>(f->GetObject(o)); } @@ -1244,6 +1324,7 @@ class JNI { CHECK_NON_NULL_ARGUMENT(fid); ScopedObjectAccess soa(env); ArtField* f = jni::DecodeArtField(fid); + NotifyGetField(f, nullptr); return soa.AddLocalReference<jobject>(f->GetObject(f->GetDeclaringClass())); } @@ -1251,17 +1332,19 @@ class JNI { CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_object); CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); ScopedObjectAccess soa(env); + ArtField* f = jni::DecodeArtField(fid); + NotifySetObjectField(f, java_object, java_value); ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object); ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value); - ArtField* f = jni::DecodeArtField(fid); f->SetObject<false>(o, v); } static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) { CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); ScopedObjectAccess soa(env); - ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value); ArtField* f = jni::DecodeArtField(fid); + NotifySetObjectField(f, nullptr, java_value); + ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value); f->SetObject<false>(f->GetDeclaringClass(), v); } @@ -1269,28 +1352,32 @@ class JNI { CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(instance); \ CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \ ScopedObjectAccess soa(env); \ - ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \ ArtField* f = jni::DecodeArtField(fid); \ + NotifyGetField(f, instance); \ + ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \ return f->Get ##fn (o) #define GET_STATIC_PRIMITIVE_FIELD(fn) \ CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \ ScopedObjectAccess soa(env); \ ArtField* f = jni::DecodeArtField(fid); \ + NotifyGetField(f, nullptr); \ return f->Get ##fn (f->GetDeclaringClass()) #define SET_PRIMITIVE_FIELD(fn, instance, value) \ CHECK_NON_NULL_ARGUMENT_RETURN_VOID(instance); \ CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \ ScopedObjectAccess soa(env); \ - ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \ ArtField* f = jni::DecodeArtField(fid); \ + NotifySetPrimitiveField(f, instance, JValue::FromPrimitive<decltype(value)>(value)); \ + ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \ f->Set ##fn <false>(o, value) #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \ CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \ ScopedObjectAccess soa(env); \ ArtField* f = jni::DecodeArtField(fid); \ + NotifySetPrimitiveField(f, nullptr, JValue::FromPrimitive<decltype(value)>(value)); \ f->Set ##fn <false>(f->GetDeclaringClass(), value) static jboolean GetBooleanField(JNIEnv* env, jobject obj, jfieldID fid) { diff --git a/runtime/jvalue-inl.h b/runtime/jvalue-inl.h index b33686c6c5..25e34b2a74 100644 --- a/runtime/jvalue-inl.h +++ b/runtime/jvalue-inl.h @@ -27,6 +27,24 @@ inline void JValue::SetL(ObjPtr<mirror::Object> new_l) { l = new_l.Ptr(); } +#define DEFINE_FROM(type, chr) \ + template <> inline JValue JValue::FromPrimitive(type v) { \ + JValue res; \ + res.Set ## chr(v); \ + return res; \ + } + +DEFINE_FROM(uint8_t, Z); +DEFINE_FROM(int8_t, B); +DEFINE_FROM(uint16_t, C); +DEFINE_FROM(int16_t, S); +DEFINE_FROM(int32_t, I); +DEFINE_FROM(int64_t, J); +DEFINE_FROM(float, F); +DEFINE_FROM(double, D); + +#undef DEFINE_FROM + } // namespace art #endif // ART_RUNTIME_JVALUE_INL_H_ diff --git a/runtime/jvalue.h b/runtime/jvalue.h index f61a07c0c0..266abcf399 100644 --- a/runtime/jvalue.h +++ b/runtime/jvalue.h @@ -33,6 +33,8 @@ union PACKED(alignof(mirror::Object*)) JValue { // We default initialize JValue instances to all-zeros. JValue() : j(0) {} + template<typename T> static JValue FromPrimitive(T v); + int8_t GetB() const { return b; } void SetB(int8_t new_b) { j = ((static_cast<int64_t>(new_b) << 56) >> 56); // Sign-extend to 64 bits. |