From c971eafeff43e4e26959a6e86b62ab0a8f1a6e1c Mon Sep 17 00:00:00 2001 From: Alex Light Date: Tue, 13 Aug 2019 10:50:38 -0700 Subject: Basic structural redefinition support This adds basic support for adding methods and fields to already loaded classes using redefinition. This 'structural class redefinition' is currently limited to classes without any virtual methods or instance fields. One cannot currently structurally redefine multiple classes at once nor will structural redefinition trigger the standard redefinition events. After structural redefinition all references to the old class, and its fields and methods are atomically updated. Any memory associated with the static fields of the old class is zeroed. Offsets for field access might change. If there are any active stack frames for methods from the redefined class the original (obsolete method) code will continue to execute. The identity hash code of the redefined class will not change. Any locks being held, waited or blocked on by the old class will be transferred to the new class. To use this feature the process must be debuggable and running with -Xopaque-jni-ids:true. For device testing use a wrap.sh that adds the following flags: '-Xopaque-jni-ids:true -Xcompiler-option --debuggable -XjdwpProvider:adbconnection' Structural redefinition only available using the "com.android.art.UNSAFE.class.structurally_redefine_class_direct" extension. This will not trigger the normal class-redefinition events. Only one class may be redefined at a time. NB There are still some holes in this potentially allowing obsolete methods/fields to be visible. Most notably during jni-id, MethodHandle and VarHandle creation as well as potentially other places in the runtime. These holes will be closed by later CLs. Until then the extension to access structural class redefinition will remain tagged as UNSAFE. Test: ./test.py --host --all-compiler Bug: 134162467 Change-Id: I825d3a4bdb9594c0147223ae69f433ce9bbfc307 --- runtime/mirror/class_ext.h | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'runtime/mirror/class_ext.h') diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h index 6fb225fd69..eb4047be24 100644 --- a/runtime/mirror/class_ext.h +++ b/runtime/mirror/class_ext.h @@ -106,8 +106,26 @@ class MANAGED ClassExt : public Object { inline void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); + template + inline void VisitMethods(Visitor visitor, PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_); + static ObjPtr Alloc(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); + // TODO Save the obsolete class, if we have one. + // TODO We need this so jit-cleanup can work. the obsolete class might get cleaned up early + // otherwise. We should remove the need for this. + template + ObjPtr GetObsoleteClass() REQUIRES_SHARED(Locks::mutator_lock_); + void SetObsoleteClass(ObjPtr classes) REQUIRES_SHARED(Locks::mutator_lock_); + + template + inline void VisitJFieldIDs(Visitor v) REQUIRES_SHARED(Locks::mutator_lock_); + + template + inline void VisitJMethodIDs(Visitor v) REQUIRES_SHARED(Locks::mutator_lock_); + private: template @@ -123,6 +141,9 @@ class MANAGED ClassExt : public Object { // the classes methods_ array or '0' if no id has been assigned to that method yet. HeapReference jmethod_ids_; + // If set this is the Class object that was being used before a structural redefinition occurred. + HeapReference obsolete_class_; + HeapReference> obsolete_dex_caches_; HeapReference obsolete_methods_; @@ -137,8 +158,8 @@ class MANAGED ClassExt : public Object { HeapReference verify_error_; // Native pointer to DexFile and ClassDef index of this class before it was JVMTI-redefined. - int32_t pre_redefine_class_def_index_; int64_t pre_redefine_dex_file_ptr_; + int32_t pre_redefine_class_def_index_; friend struct art::ClassExtOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassExt); -- cgit v1.2.3-59-g8ed1b