summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/debugger.cc6
-rw-r--r--runtime/jni_internal.cc97
-rw-r--r--runtime/jvalue-inl.h18
-rw-r--r--runtime/jvalue.h2
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.