summaryrefslogtreecommitdiff
path: root/runtime/art_method.cc
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2019-08-13 10:50:38 -0700
committer Treehugger Robot <treehugger-gerrit@google.com> 2019-09-17 23:52:12 +0000
commitc971eafeff43e4e26959a6e86b62ab0a8f1a6e1c (patch)
treef8647487e7465712fd73118ceb89e13167a12648 /runtime/art_method.cc
parent1ba7e8c10af4e270864a417044244d63db53ccf5 (diff)
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
Diffstat (limited to 'runtime/art_method.cc')
-rw-r--r--runtime/art_method.cc29
1 files changed, 19 insertions, 10 deletions
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index d8bcb02b3c..646f73d8cc 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -16,12 +16,15 @@
#include "art_method.h"
+#include <algorithm>
#include <cstddef>
#include "android-base/stringprintf.h"
#include "arch/context.h"
#include "art_method-inl.h"
+#include "base/enums.h"
+#include "base/stl_util.h"
#include "class_linker-inl.h"
#include "class_root.h"
#include "debugger.h"
@@ -106,26 +109,32 @@ ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnabl
}
ObjPtr<mirror::DexCache> ArtMethod::GetObsoleteDexCache() {
+ PointerSize pointer_size = kRuntimePointerSize;
DCHECK(!Runtime::Current()->IsAotCompiler()) << PrettyMethod();
DCHECK(IsObsolete());
ObjPtr<mirror::ClassExt> ext(GetDeclaringClass()->GetExtData());
- CHECK(!ext.IsNull());
- ObjPtr<mirror::PointerArray> obsolete_methods(ext->GetObsoleteMethods());
- CHECK(!obsolete_methods.IsNull());
- DCHECK(ext->GetObsoleteDexCaches() != nullptr);
- int32_t len = obsolete_methods->GetLength();
- DCHECK_EQ(len, ext->GetObsoleteDexCaches()->GetLength());
+ ObjPtr<mirror::PointerArray> obsolete_methods(ext.IsNull() ? nullptr : ext->GetObsoleteMethods());
+ int32_t len = (obsolete_methods.IsNull() ? 0 : obsolete_methods->GetLength());
+ DCHECK(len == 0 || len == ext->GetObsoleteDexCaches()->GetLength())
+ << "len=" << len << " ext->GetObsoleteDexCaches()=" << ext->GetObsoleteDexCaches();
// Using kRuntimePointerSize (instead of using the image's pointer size) is fine since images
// should never have obsolete methods in them so they should always be the same.
- PointerSize pointer_size = kRuntimePointerSize;
- DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+ DCHECK_EQ(pointer_size, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
for (int32_t i = 0; i < len; i++) {
if (this == obsolete_methods->GetElementPtrSize<ArtMethod*>(i, pointer_size)) {
return ext->GetObsoleteDexCaches()->Get(i);
}
}
- LOG(FATAL) << "This method does not appear in the obsolete map of its class!";
- UNREACHABLE();
+ CHECK(GetDeclaringClass()->IsObsoleteObject())
+ << "This non-structurally obsolete method does not appear in the obsolete map of its class: "
+ << GetDeclaringClass()->PrettyClass() << " Searched " << len << " caches.";
+ CHECK_EQ(this,
+ std::clamp(this,
+ &(*GetDeclaringClass()->GetMethods(pointer_size).begin()),
+ &(*GetDeclaringClass()->GetMethods(pointer_size).end())))
+ << "class is marked as structurally obsolete method but not found in normal obsolete-map "
+ << "despite not being the original method pointer for " << GetDeclaringClass()->PrettyClass();
+ return GetDeclaringClass()->GetDexCache();
}
uint16_t ArtMethod::FindObsoleteDexClassDefIndex() {