VarHandle: add StaticFieldVarHandle class
Add StaticFieldVarHandle class to keep a live reference to the
declaring class for the target field of VarHandle's targeting static
fields.
Bug: 191980149
Test: art/test.py --host -r -g
Change-Id: I3a1cada6591d146b8f9fc9066105e3b617290185
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f3f7afd..0563f38 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -969,6 +969,11 @@
CHECK(class_root != nullptr);
SetClassRoot(ClassRoot::kJavaLangInvokeFieldVarHandle, class_root);
+ // Create java.lang.invoke.StaticFieldVarHandle.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/StaticFieldVarHandle;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(ClassRoot::kJavaLangInvokeStaticFieldVarHandle, class_root);
+
// Create java.lang.invoke.ArrayElementVarHandle.class root
class_root = FindSystemClass(self, "Ljava/lang/invoke/ArrayElementVarHandle;");
CHECK(class_root != nullptr);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 5dc194f..691fcf1 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -815,6 +815,13 @@
}
};
+struct StaticFieldVarHandleOffsets : public CheckOffsets<mirror::StaticFieldVarHandle> {
+ StaticFieldVarHandleOffsets() : CheckOffsets<mirror::StaticFieldVarHandle>(
+ false, "Ljava/lang/invoke/StaticFieldVarHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::StaticFieldVarHandle, declaring_class_), "declaringClass");
+ }
+};
+
struct ArrayElementVarHandleOffsets : public CheckOffsets<mirror::ArrayElementVarHandle> {
ArrayElementVarHandleOffsets() : CheckOffsets<mirror::ArrayElementVarHandle>(
false, "Ljava/lang/invoke/ArrayElementVarHandle;") {
diff --git a/runtime/class_root.h b/runtime/class_root.h
index 85e074c..baa2128 100644
--- a/runtime/class_root.h
+++ b/runtime/class_root.h
@@ -50,6 +50,7 @@
template<typename T> class PrimitiveArray;
class Reference;
class StackTraceElement;
+class StaticFieldVarHandle;
class String;
class Throwable;
class VarHandle;
@@ -78,6 +79,7 @@
M(kJavaLangInvokeMethodType, "Ljava/lang/invoke/MethodType;", mirror::MethodType) \
M(kJavaLangInvokeVarHandle, "Ljava/lang/invoke/VarHandle;", mirror::VarHandle) \
M(kJavaLangInvokeFieldVarHandle, "Ljava/lang/invoke/FieldVarHandle;", mirror::FieldVarHandle) \
+ M(kJavaLangInvokeStaticFieldVarHandle, "Ljava/lang/invoke/StaticFieldVarHandle;", mirror::StaticFieldVarHandle) \
M(kJavaLangInvokeArrayElementVarHandle, "Ljava/lang/invoke/ArrayElementVarHandle;", mirror::ArrayElementVarHandle) \
M(kJavaLangInvokeByteArrayViewVarHandle, "Ljava/lang/invoke/ByteArrayViewVarHandle;", mirror::ByteArrayViewVarHandle) \
M(kJavaLangInvokeByteBufferViewVarHandle, "Ljava/lang/invoke/ByteBufferViewVarHandle;", mirror::ByteBufferViewVarHandle) \
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4676ded..21e9c31 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -4507,6 +4507,8 @@
down_cast<mirror::Field*>(ref)->VisitTarget(visit);
} else if (art::GetClassRoot<art::mirror::MethodHandle>()->IsAssignableFrom(klass)) {
down_cast<mirror::MethodHandle*>(ref)->VisitTarget(visit);
+ } else if (art::GetClassRoot<art::mirror::StaticFieldVarHandle>()->IsAssignableFrom(klass)) {
+ down_cast<mirror::StaticFieldVarHandle*>(ref)->VisitTarget(visit);
} else if (art::GetClassRoot<art::mirror::FieldVarHandle>()->IsAssignableFrom(klass)) {
down_cast<mirror::FieldVarHandle*>(ref)->VisitTarget(visit);
} else if (art::GetClassRoot<art::mirror::DexCache>()->IsAssignableFrom(klass)) {
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index adeb29c..386244d 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -58,6 +58,7 @@
vis("Ljava/lang/invoke/ByteBufferViewVarHandle;") \
vis("Ljava/lang/invoke/CallSite;") \
vis("Ljava/lang/invoke/FieldVarHandle;") \
+ vis("Ljava/lang/invoke/StaticFieldVarHandle;") \
vis("Ljava/lang/invoke/MethodHandle;") \
vis("Ljava/lang/invoke/MethodHandleImpl;") \
vis("Ljava/lang/invoke/MethodHandles$Lookup;") \
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index 7970c62..c071e23 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1454,16 +1454,19 @@
ObjPtr<ObjectArray<Class>> class_roots = Runtime::Current()->GetClassLinker()->GetClassRoots();
ObjPtr<Class> klass = GetClass();
if (klass == GetClassRoot<FieldVarHandle>(class_roots)) {
- auto vh = reinterpret_cast<FieldVarHandle*>(this);
+ auto vh = ObjPtr<FieldVarHandle>::DownCast(this);
+ return vh->Access(access_mode, shadow_frame, operands, result);
+ } else if (klass == GetClassRoot<StaticFieldVarHandle>(class_roots)) {
+ auto vh = ObjPtr<StaticFieldVarHandle>::DownCast(this);
return vh->Access(access_mode, shadow_frame, operands, result);
} else if (klass == GetClassRoot<ArrayElementVarHandle>(class_roots)) {
- auto vh = reinterpret_cast<ArrayElementVarHandle*>(this);
+ auto vh = ObjPtr<ArrayElementVarHandle>::DownCast(this);
return vh->Access(access_mode, shadow_frame, operands, result);
} else if (klass == GetClassRoot<ByteArrayViewVarHandle>(class_roots)) {
- auto vh = reinterpret_cast<ByteArrayViewVarHandle*>(this);
+ auto vh = ObjPtr<ByteArrayViewVarHandle>::DownCast(this);
return vh->Access(access_mode, shadow_frame, operands, result);
} else if (klass == GetClassRoot<ByteBufferViewVarHandle>(class_roots)) {
- auto vh = reinterpret_cast<ByteBufferViewVarHandle*>(this);
+ auto vh = ObjPtr<ByteBufferViewVarHandle>::DownCast(this);
return vh->Access(access_mode, shadow_frame, operands, result);
} else {
LOG(FATAL) << "Unknown varhandle kind";
@@ -2004,6 +2007,16 @@
}
}
+void StaticFieldVarHandle::VisitTarget(ReflectiveValueVisitor* v) {
+ ArtField* orig = GetField();
+ ArtField* new_value =
+ v->VisitField(orig, HeapReflectiveSourceInfo(kSourceJavaLangInvokeFieldVarHandle, this));
+ if (orig != new_value) {
+ SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
+ reinterpret_cast<uintptr_t>(new_value));
+ SetFieldObject<false>(DeclaringClassOffset(), new_value->GetDeclaringClass());
+ }
+}
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index fd225e0..3747b3e 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -32,6 +32,7 @@
struct VarHandleOffsets;
struct FieldVarHandleOffsets;
+struct StaticFieldVarHandleOffsets;
struct ArrayElementVarHandleOffsets;
struct ByteArrayViewVarHandleOffsets;
struct ByteBufferViewVarHandleOffsets;
@@ -235,6 +236,26 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(FieldVarHandle);
};
+class MANAGED StaticFieldVarHandle : public FieldVarHandle {
+ public:
+ MIRROR_CLASS("Ljava/lang/invoke/StaticFieldVarHandle;");
+
+ // Used for updating var-handles to obsolete fields.
+ void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_);
+
+ static MemberOffset DeclaringClassOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(StaticFieldVarHandle, declaring_class_));
+ }
+
+ private:
+ HeapReference<mirror::Class> declaring_class_;
+
+ friend class VarHandleTest; // for var_handle_test.
+ friend struct art::StaticFieldVarHandleOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StaticFieldVarHandle);
+};
+
+
// Represents a VarHandle providing accessors to an array.
// The corresponding managed class in libart java.lang.invoke.ArrayElementVarHandle.
class MANAGED ArrayElementVarHandle : public VarHandle {
diff --git a/runtime/oat.h b/runtime/oat.h
index ab45b84..99268c0 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: Apex versions in key/value store.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '5', '\0' } };
+ // Last oat version changed reason: StaticFieldVarHandle introduction.
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '6', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/test/1981-structural-redef-private-method-handles/expected-stdout.txt b/test/1981-structural-redef-private-method-handles/expected-stdout.txt
index 0c0ac6e..33d0833 100644
--- a/test/1981-structural-redef-private-method-handles/expected-stdout.txt
+++ b/test/1981-structural-redef-private-method-handles/expected-stdout.txt
@@ -1,20 +1,20 @@
Initial: class art.Test1981$Transform[FOO: value of <FOO FIELD>, BAR: value of <BAR FIELD>]
Reading field FOO using (ID: 0) MethodHandle()Object = (ID: 1) value of <FOO FIELD>
-Reading field FOO using (ID: 2) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 1) value of <FOO FIELD>
+Reading field FOO using (ID: 2) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 1) value of <FOO FIELD>
Reading field BAR using (ID: 3) MethodHandle()Object = (ID: 4) value of <BAR FIELD>
-Reading field BAR using (ID: 5) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
+Reading field BAR using (ID: 5) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
Redefining Transform class
Post redefinition : class art.Test1981$Transform[FOO: value of <FOO FIELD>, BAR: value of <BAR FIELD>, BAZ: null]
Reading field FOO using (ID: 0) MethodHandle()Object = (ID: 1) value of <FOO FIELD>
-Reading field FOO using (ID: 2) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 1) value of <FOO FIELD>
+Reading field FOO using (ID: 2) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 1) value of <FOO FIELD>
Reading field BAR using (ID: 3) MethodHandle()Object = (ID: 4) value of <BAR FIELD>
-Reading field BAR using (ID: 5) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
+Reading field BAR using (ID: 5) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
Reading new field BAZ using (ID: 6) MethodHandle()Object = (ID: 7) <NULL>
-Reading new field BAZ using (ID: 8) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 7) <NULL>
+Reading new field BAZ using (ID: 8) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 7) <NULL>
Reading new field FOO using (ID: 9) MethodHandle()Object = (ID: 1) value of <FOO FIELD>
-Reading new field FOO using (ID: 10) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 1) value of <FOO FIELD>
+Reading new field FOO using (ID: 10) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 1) value of <FOO FIELD>
Reading new field BAR using (ID: 11) MethodHandle()Object = (ID: 4) value of <BAR FIELD>
-Reading new field BAR using (ID: 12) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
+Reading new field BAR using (ID: 12) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
Setting BAZ to (ID: 13) foo with new mh.
Post set with new mh: class art.Test1981$Transform[FOO: value of <FOO FIELD>, BAR: value of <BAR FIELD>, BAZ: foo]
Setting FOO to (ID: 14) class art.Test1981$Transform with old mh.
@@ -26,12 +26,12 @@
Using mh to call new private method.
Post reinit with mh: class art.Test1981$Transform[FOO: new_value object, BAR: value of <BAR FIELD>, BAZ: 42]
Reading field FOO using (ID: 0) MethodHandle()Object = (ID: 15) new_value object
-Reading field FOO using (ID: 2) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 15) new_value object
+Reading field FOO using (ID: 2) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 15) new_value object
Reading field BAR using (ID: 3) MethodHandle()Object = (ID: 4) value of <BAR FIELD>
-Reading field BAR using (ID: 5) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
+Reading field BAR using (ID: 5) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
Reading new field BAZ using (ID: 6) MethodHandle()Object = (ID: 16) 42
-Reading new field BAZ using (ID: 8) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 16) 42
+Reading new field BAZ using (ID: 8) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 16) 42
Reading new field FOO using (ID: 9) MethodHandle()Object = (ID: 15) new_value object
-Reading new field FOO using (ID: 10) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 15) new_value object
+Reading new field FOO using (ID: 10) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 15) new_value object
Reading new field BAR using (ID: 11) MethodHandle()Object = (ID: 4) value of <BAR FIELD>
-Reading new field BAR using (ID: 12) java.lang.invoke.FieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>
+Reading new field BAR using (ID: 12) java.lang.invoke.StaticFieldVarHandle()->java.lang.Object = (ID: 4) value of <BAR FIELD>