Add static asserts we have a full list of mirror classes
We need to know if a particular object is of a mirrored class type in
order for structural class redefinition to work correctly. For
simplicity and to avoid making class objects larger we do this with a
simple list of mirror-class descriptors. This adds some basic
static_assert checking and a documenting macro to all mirror classes.
This should help to ensure nobody in the future unintentionally breaks
structural class redefinition by adding a new mirror type.
Test: treehugger
Bug: 144349987
Change-Id: I47c7b256655e9ce9bcf21d9670e0511bcbac65c9
diff --git a/runtime/mirror/accessible_object.h b/runtime/mirror/accessible_object.h
index bfd0f35..7c0d91a 100644
--- a/runtime/mirror/accessible_object.h
+++ b/runtime/mirror/accessible_object.h
@@ -27,6 +27,8 @@
// C++ mirror of java.lang.reflect.AccessibleObject
class MANAGED AccessibleObject : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/reflect/AccessibleObject;");
+
static MemberOffset FlagOffset() {
return OFFSET_OF_OBJECT_MEMBER(AccessibleObject, flag_);
}
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 4c172f2..717d1de 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -149,6 +149,15 @@
template<typename T>
class MANAGED PrimitiveArray : public Array {
public:
+ MIRROR_CLASS("[Z");
+ MIRROR_CLASS("[B");
+ MIRROR_CLASS("[C");
+ MIRROR_CLASS("[S");
+ MIRROR_CLASS("[I");
+ MIRROR_CLASS("[J");
+ MIRROR_CLASS("[F");
+ MIRROR_CLASS("[D");
+
typedef T ElementType;
static ObjPtr<PrimitiveArray<T>> Alloc(Thread* self, size_t length)
diff --git a/runtime/mirror/call_site.h b/runtime/mirror/call_site.h
index ca9a9ee..88387a3 100644
--- a/runtime/mirror/call_site.h
+++ b/runtime/mirror/call_site.h
@@ -29,6 +29,8 @@
// C++ mirror of java.lang.invoke.CallSite
class MANAGED CallSite : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/CallSite;");
+
ObjPtr<MethodHandle> GetTarget() REQUIRES_SHARED(Locks::mutator_lock_);
private:
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index c1593a7..3f9d41c 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -72,40 +72,9 @@
if (IsPrimitive() || IsArrayClass() || IsProxyClass()) {
return true;
}
- // TODO Have this list automatically populated.
- std::unordered_set<std::string_view> mirror_types = {
- "Ljava/lang/Class;",
- "Ljava/lang/ClassLoader;",
- "Ljava/lang/ClassNotFoundException;",
- "Ljava/lang/DexCache;",
- "Ljava/lang/Object;",
- "Ljava/lang/StackTraceElement;",
- "Ljava/lang/String;",
- "Ljava/lang/Throwable;",
- "Ljava/lang/invoke/ArrayElementVarHandle;",
- "Ljava/lang/invoke/ByteArrayViewVarHandle;",
- "Ljava/lang/invoke/ByteBufferViewVarHandle;",
- "Ljava/lang/invoke/CallSite;",
- "Ljava/lang/invoke/FieldVarHandle;",
- "Ljava/lang/invoke/MethodHandle;",
- "Ljava/lang/invoke/MethodHandleImpl;",
- "Ljava/lang/invoke/MethodHandles$Lookup;",
- "Ljava/lang/invoke/MethodType;",
- "Ljava/lang/invoke/VarHandle;",
- "Ljava/lang/ref/FinalizerReference;",
- "Ljava/lang/ref/Reference;",
- "Ljava/lang/reflect/AccessibleObject;",
- "Ljava/lang/reflect/Constructor;",
- "Ljava/lang/reflect/Executable;",
- "Ljava/lang/reflect/Field;",
- "Ljava/lang/reflect/Method;",
- "Ljava/lang/reflect/Proxy;",
- "Ldalvik/system/ClassExt;",
- "Ldalvik/system/EmulatedStackFrame;",
- };
std::string name_storage;
- const std::string name(this->GetDescriptor(&name_storage));
- return mirror_types.find(name) != mirror_types.end();
+ const std::string_view name(this->GetDescriptor(&name_storage));
+ return IsMirroredDescriptor(name);
}
ObjPtr<mirror::Class> Class::GetPrimitiveClass(ObjPtr<mirror::String> name) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index fdc1be9..d29dc8c 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -81,6 +81,8 @@
// C++ mirror of java.lang.Class
class MANAGED Class final : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/Class;");
+
// A magic value for reference_instance_offsets_. Ignore the bits and walk the super chain when
// this is the value.
// [This is an unlikely "natural" value, since it would be 30 non-ref instance fields followed by
diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h
index fa4e87a..2fd8c39 100644
--- a/runtime/mirror/class_ext.h
+++ b/runtime/mirror/class_ext.h
@@ -33,6 +33,8 @@
// C++ mirror of dalvik.system.ClassExt
class MANAGED ClassExt : public Object {
public:
+ MIRROR_CLASS("Ldalvik/system/ClassExt;");
+
static uint32_t ClassSize(PointerSize pointer_size);
// Size of an instance of dalvik.system.ClassExt.
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index c90a3da..197172c 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -35,6 +35,8 @@
// C++ mirror of java.lang.ClassLoader
class MANAGED ClassLoader : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/ClassLoader;");
+
// Size of an instance of java.lang.ClassLoader.
static constexpr uint32_t InstanceSize() {
return sizeof(ClassLoader);
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index dd05ddd..ea52785 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -132,6 +132,8 @@
// C++ mirror of java.lang.DexCache.
class MANAGED DexCache final : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/DexCache;");
+
// Size of java.lang.DexCache.class.
static uint32_t ClassSize(PointerSize pointer_size);
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 626215e..b63ccaa 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -34,6 +34,8 @@
// C++ mirror of dalvik.system.EmulatedStackFrame
class MANAGED EmulatedStackFrame : public Object {
public:
+ MIRROR_CLASS("Ldalvik/system/EmulatedStackFrame;");
+
// Creates an emulated stack frame whose type is |frame_type| from
// a shadow frame.
static ObjPtr<mirror::EmulatedStackFrame> CreateFromShadowFrameAndArgs(
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 6f9fc0b..dc4ec95 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -32,6 +32,8 @@
// C++ mirror of java.lang.reflect.Executable.
class MANAGED Executable : public AccessibleObject {
public:
+ MIRROR_CLASS("Ljava/lang/reflect/Executable;");
+
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 6eabd82..bbae8ce 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -39,6 +39,8 @@
// C++ mirror of java.lang.reflect.Field.
class MANAGED Field : public AccessibleObject {
public:
+ MIRROR_CLASS("Ljava/lang/reflect/Field;");
+
ALWAYS_INLINE uint32_t GetArtFieldIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, art_field_index_));
}
diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h
index 93d61b6..4b8dcff 100644
--- a/runtime/mirror/method.h
+++ b/runtime/mirror/method.h
@@ -30,6 +30,8 @@
// C++ mirror of java.lang.reflect.Method.
class MANAGED Method : public Executable {
public:
+ MIRROR_CLASS("Ljava/lang/reflect/Method;");
+
template <PointerSize kPointerSize>
static ObjPtr<Method> CreateFromArtMethod(Thread* self, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
@@ -41,6 +43,8 @@
// C++ mirror of java.lang.reflect.Constructor.
class MANAGED Constructor: public Executable {
public:
+ MIRROR_CLASS("Ljava/lang/reflect/Constructor;");
+
template <PointerSize kPointerSize>
static ObjPtr<Constructor> CreateFromArtMethod(Thread* self, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index a0f02f6..6ba6e25 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -35,6 +35,8 @@
// C++ mirror of java.lang.invoke.MethodHandle
class MANAGED MethodHandle : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/MethodHandle;");
+
// Defines the behaviour of a given method handle. The behaviour
// of a handle of a given kind is identical to the dex bytecode behaviour
// of the equivalent instruction.
@@ -125,6 +127,8 @@
// C++ mirror of java.lang.invoke.MethodHandleImpl
class MANAGED MethodHandleImpl : public MethodHandle {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/MethodHandleImpl;");
+
static ObjPtr<mirror::MethodHandleImpl> Create(Thread* const self,
uintptr_t art_field_or_method,
MethodHandle::Kind kind,
diff --git a/runtime/mirror/method_handles_lookup.h b/runtime/mirror/method_handles_lookup.h
index d4dbf83..3ed150a 100644
--- a/runtime/mirror/method_handles_lookup.h
+++ b/runtime/mirror/method_handles_lookup.h
@@ -35,6 +35,8 @@
// C++ mirror of java.lang.invoke.MethodHandles.Lookup
class MANAGED MethodHandlesLookup : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/MethodHandles$Lookup;");
+
static ObjPtr<mirror::MethodHandlesLookup> Create(Thread* const self, Handle<Class> lookup_class)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
index 13edf29..872c07b 100644
--- a/runtime/mirror/method_type.h
+++ b/runtime/mirror/method_type.h
@@ -30,6 +30,8 @@
// C++ mirror of java.lang.invoke.MethodType
class MANAGED MethodType : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/MethodType;");
+
static ObjPtr<MethodType> Create(Thread* const self,
Handle<Class> return_type,
Handle<ObjectArray<Class>> param_types)
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 2eff560..a3fc552 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -76,6 +76,8 @@
// C++ mirror of java.lang.Object
class MANAGED LOCKABLE Object {
public:
+ MIRROR_CLASS("Ljava/lang/Object;");
+
// The number of vtable entries in java.lang.Object.
static constexpr size_t kVTableLength = 11;
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index e58787c..a20c86b 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -34,6 +34,8 @@
template<class T>
class MANAGED ObjectArray: public Array {
public:
+ MIRROR_CLASS("[Ljava/lang/Object;");
+
// The size of Object[].class.
static uint32_t ClassSize(PointerSize pointer_size) {
return Array::ClassSize(pointer_size);
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index f01bcbd..adeb29c 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -17,6 +17,9 @@
#ifndef ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
#define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
+#include <array>
+#include <string_view>
+
#include "base/atomic.h"
#include "base/locks.h" // For Locks::mutator_lock_.
#include "heap_poisoning.h"
@@ -31,6 +34,59 @@
// Classes shared with the managed side of the world need to be packed so that they don't have
// extra platform specific padding.
#define MANAGED PACKED(4)
+#define MIRROR_CLASS(desc) \
+ static_assert(::art::mirror::IsMirroredDescriptor(desc), \
+ desc " is not a known mirror class. Please update" \
+ " IsMirroredDescriptor to include it!")
+
+constexpr bool IsMirroredDescriptor(std::string_view desc) {
+ if (desc[0] != 'L') {
+ // All primitives and arrays are mirrored
+ return true;
+ }
+#define MIRROR_DESCRIPTORS(vis) \
+ vis("Ljava/lang/Class;") \
+ vis("Ljava/lang/ClassLoader;") \
+ vis("Ljava/lang/ClassNotFoundException;") \
+ vis("Ljava/lang/DexCache;") \
+ vis("Ljava/lang/Object;") \
+ vis("Ljava/lang/StackTraceElement;") \
+ vis("Ljava/lang/String;") \
+ vis("Ljava/lang/Throwable;") \
+ vis("Ljava/lang/invoke/ArrayElementVarHandle;") \
+ vis("Ljava/lang/invoke/ByteArrayViewVarHandle;") \
+ vis("Ljava/lang/invoke/ByteBufferViewVarHandle;") \
+ vis("Ljava/lang/invoke/CallSite;") \
+ vis("Ljava/lang/invoke/FieldVarHandle;") \
+ vis("Ljava/lang/invoke/MethodHandle;") \
+ vis("Ljava/lang/invoke/MethodHandleImpl;") \
+ vis("Ljava/lang/invoke/MethodHandles$Lookup;") \
+ vis("Ljava/lang/invoke/MethodType;") \
+ vis("Ljava/lang/invoke/VarHandle;") \
+ vis("Ljava/lang/ref/FinalizerReference;") \
+ vis("Ljava/lang/ref/Reference;") \
+ vis("Ljava/lang/reflect/AccessibleObject;") \
+ vis("Ljava/lang/reflect/Constructor;") \
+ vis("Ljava/lang/reflect/Executable;") \
+ vis("Ljava/lang/reflect/Field;") \
+ vis("Ljava/lang/reflect/Method;") \
+ vis("Ljava/lang/reflect/Proxy;") \
+ vis("Ldalvik/system/ClassExt;") \
+ vis("Ldalvik/system/EmulatedStackFrame;")
+ // TODO: Once we are C++ 20 we can just have a constexpr array and std::find.
+ // constexpr std::array<std::string_view, 28> kMirrorTypes{
+ // // Fill in
+ // };
+ // return std::find(kMirrorTypes.begin(), kMirrorTypes.end(), desc) != kMirrorTypes.end();
+#define CHECK_DESCRIPTOR(descriptor) \
+ if (std::string_view(descriptor) == desc) { \
+ return true; \
+ }
+ MIRROR_DESCRIPTORS(CHECK_DESCRIPTOR)
+#undef CHECK_DESCRIPTOR
+ return false;
+#undef MIRROR_DESCRIPTORS
+}
template<bool kPoisonReferences, class MirrorType>
class PtrCompression {
diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h
index 7775de3..3291669 100644
--- a/runtime/mirror/proxy.h
+++ b/runtime/mirror/proxy.h
@@ -28,6 +28,8 @@
// C++ mirror of java.lang.reflect.Proxy.
class MANAGED Proxy final : public Object {
private:
+ MIRROR_CLASS("Ljava/lang/reflect/Proxy;");
+
HeapReference<Object> h_;
friend struct art::ProxyOffsets; // for verifying offset information
diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h
index 9ace4f7..ef6d273 100644
--- a/runtime/mirror/reference.h
+++ b/runtime/mirror/reference.h
@@ -41,6 +41,8 @@
// C++ mirror of java.lang.ref.Reference
class MANAGED Reference : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/ref/Reference;");
+
// Size of java.lang.ref.Reference.class.
static uint32_t ClassSize(PointerSize pointer_size);
@@ -117,6 +119,8 @@
// C++ mirror of java.lang.ref.FinalizerReference
class MANAGED FinalizerReference : public Reference {
public:
+ MIRROR_CLASS("Ljava/lang/ref/FinalizerReference;");
+
static MemberOffset ZombieOffset() {
return OFFSET_OF_OBJECT_MEMBER(FinalizerReference, zombie_);
}
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 67eedbc..c07e63d 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -29,6 +29,8 @@
// C++ mirror of java.lang.StackTraceElement
class MANAGED StackTraceElement final : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/StackTraceElement;");
+
ObjPtr<String> GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<String> GetMethodName() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 68a1c06..338a1af 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -46,6 +46,8 @@
// C++ mirror of java.lang.String
class MANAGED String final : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/String;");
+
// Size of java.lang.String.class.
static uint32_t ClassSize(PointerSize pointer_size);
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 68c176a..50db34c 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -31,6 +31,8 @@
// C++ mirror of java.lang.Throwable
class MANAGED Throwable : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/Throwable;");
+
void SetDetailMessage(ObjPtr<String> new_detail_message) REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<String> GetDetailMessage() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index 64da936..fd225e0 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -47,6 +47,8 @@
// C++ mirror of java.lang.invoke.VarHandle
class MANAGED VarHandle : public Object {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/VarHandle;");
+
// The maximum number of parameters a VarHandle accessor method can
// take. The Worst case is equivalent to a compare-and-swap
// operation on an array element which requires four parameters
@@ -207,6 +209,8 @@
// The corresponding managed class in libart java.lang.invoke.FieldVarHandle.
class MANAGED FieldVarHandle : public VarHandle {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/FieldVarHandle;");
+
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
const InstructionOperands* const operands,
@@ -250,6 +254,8 @@
// The corresponding managed class in libart java.lang.invoke.ByteArrayViewVarHandle.
class MANAGED ByteArrayViewVarHandle : public VarHandle {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/ByteArrayViewVarHandle;");
+
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
const InstructionOperands* const operands,
@@ -275,6 +281,8 @@
// The corresponding managed class in libart java.lang.invoke.ByteBufferViewVarHandle.
class MANAGED ByteBufferViewVarHandle : public VarHandle {
public:
+ MIRROR_CLASS("Ljava/lang/invoke/ByteBufferViewVarHandle;");
+
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
const InstructionOperands* const operands,