summaryrefslogtreecommitdiff
path: root/runtime/mirror/class.cc
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2019-06-19 12:58:22 -0700
committer Treehugger Robot <treehugger-gerrit@google.com> 2019-06-26 20:22:39 +0000
commit21d5994583c679cd5d8573b5d35dbd659bdca2c7 (patch)
tree521906398a2f04048cc51b4f409b6a3ebc0c6ffa /runtime/mirror/class.cc
parent5dfbe7ae9ed9a1a82446d32118190105a211a2d2 (diff)
Support using opaque JNI ids
Currently JNI ids (jmethodID & jfieldID) are created by simply casting the corresponding ART structure pointer. This is great for simplicity but means we are prevented from performing operations that could change these pointer values. To support these use-cases add support for loading the runtime with a layer of indirection between these ids and the internal art data types. Currently the JNI id type can be toggled only by passing the new '-Xopaque-jni-ids:{true,false}' flag during startup. This changes the --debuggable test configuration to pass '-Xopaque-jni-ids:true' in order to get test coverage of this feature using the 'art-jit' configuration. Test: ./test.py --host --debuggable Test: ./test.py --host --debuggable --jit-on-first-use Test: ./test/testrunnner/run_build_test_target.py art-jit Bug: 134162467 Change-Id: Id8c8cb9a5b8ff18dc2f40892fae2d344a7214f44
Diffstat (limited to 'runtime/mirror/class.cc')
-rw-r--r--runtime/mirror/class.cc126
1 files changed, 125 insertions, 1 deletions
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index a36fe1253c..c0a950d614 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -16,14 +16,17 @@
#include "class.h"
+#include "android-base/macros.h"
#include "android-base/stringprintf.h"
+#include "array-inl.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
+#include "base/enums.h"
#include "base/logging.h" // For VLOG.
#include "base/utils.h"
#include "class-inl.h"
-#include "class_ext.h"
+#include "class_ext-inl.h"
#include "class_linker-inl.h"
#include "class_loader.h"
#include "class_root.h"
@@ -1547,5 +1550,126 @@ void Class::SetAccessFlagsDCheck(uint32_t new_access_flags) {
(new_access_flags & kAccVerificationAttempted) != 0);
}
+ObjPtr<PointerArray> Class::GetMethodIds() {
+ ObjPtr<ClassExt> ext(GetExtData());
+ if (ext.IsNull()) {
+ return nullptr;
+ } else {
+ return ext->GetJMethodIDs();
+ }
+}
+ObjPtr<PointerArray> Class::GetOrCreateMethodIds() {
+ DCHECK(Runtime::Current()->JniIdsAreIndices()) << "JNI Ids are pointers!";
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<Class> h_this(hs.NewHandle(this));
+ ObjPtr<ClassExt> ext(EnsureExtDataPresent(h_this, self));
+ if (ext.IsNull()) {
+ self->AssertPendingOOMException();
+ return nullptr;
+ }
+ return ext->EnsureJMethodIDsArrayPresent(NumMethods());
+}
+
+ObjPtr<PointerArray> Class::GetStaticFieldIds() {
+ ObjPtr<ClassExt> ext(GetExtData());
+ if (ext.IsNull()) {
+ return nullptr;
+ } else {
+ return ext->GetStaticJFieldIDs();
+ }
+}
+ObjPtr<PointerArray> Class::GetOrCreateStaticFieldIds() {
+ DCHECK(Runtime::Current()->JniIdsAreIndices()) << "JNI Ids are pointers!";
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<Class> h_this(hs.NewHandle(this));
+ ObjPtr<ClassExt> ext(EnsureExtDataPresent(h_this, self));
+ if (ext.IsNull()) {
+ self->AssertPendingOOMException();
+ return nullptr;
+ }
+ return ext->EnsureStaticJFieldIDsArrayPresent(NumStaticFields());
+}
+ObjPtr<PointerArray> Class::GetInstanceFieldIds() {
+ ObjPtr<ClassExt> ext(GetExtData());
+ if (ext.IsNull()) {
+ return nullptr;
+ } else {
+ return ext->GetInstanceJFieldIDs();
+ }
+}
+ObjPtr<PointerArray> Class::GetOrCreateInstanceFieldIds() {
+ DCHECK(Runtime::Current()->JniIdsAreIndices()) << "JNI Ids are pointers!";
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<Class> h_this(hs.NewHandle(this));
+ ObjPtr<ClassExt> ext(EnsureExtDataPresent(h_this, self));
+ if (ext.IsNull()) {
+ self->AssertPendingOOMException();
+ return nullptr;
+ }
+ return ext->EnsureInstanceJFieldIDsArrayPresent(NumInstanceFields());
+}
+
+size_t Class::GetStaticFieldIdOffset(ArtField* field) {
+ DCHECK_LT(reinterpret_cast<uintptr_t>(field),
+ reinterpret_cast<uintptr_t>(&*GetSFieldsPtr()->end()))
+ << "field not part of the current class. " << field->PrettyField() << " class is "
+ << PrettyClass();
+ DCHECK_GE(reinterpret_cast<uintptr_t>(field),
+ reinterpret_cast<uintptr_t>(&*GetSFieldsPtr()->begin()))
+ << "field not part of the current class. " << field->PrettyField() << " class is "
+ << PrettyClass();
+ uintptr_t start = reinterpret_cast<uintptr_t>(&GetSFieldsPtr()->At(0));
+ uintptr_t fld = reinterpret_cast<uintptr_t>(field);
+ size_t res = (fld - start) / sizeof(ArtField);
+ DCHECK_EQ(&GetSFieldsPtr()->At(res), field)
+ << "Incorrect field computation expected: " << field->PrettyField()
+ << " got: " << GetSFieldsPtr()->At(res).PrettyField();
+ return res;
+}
+
+size_t Class::GetInstanceFieldIdOffset(ArtField* field) {
+ DCHECK_LT(reinterpret_cast<uintptr_t>(field),
+ reinterpret_cast<uintptr_t>(&*GetIFieldsPtr()->end()))
+ << "field not part of the current class. " << field->PrettyField() << " class is "
+ << PrettyClass();
+ DCHECK_GE(reinterpret_cast<uintptr_t>(field),
+ reinterpret_cast<uintptr_t>(&*GetIFieldsPtr()->begin()))
+ << "field not part of the current class. " << field->PrettyField() << " class is "
+ << PrettyClass();
+ uintptr_t start = reinterpret_cast<uintptr_t>(&GetIFieldsPtr()->At(0));
+ uintptr_t fld = reinterpret_cast<uintptr_t>(field);
+ size_t res = (fld - start) / sizeof(ArtField);
+ DCHECK_EQ(&GetIFieldsPtr()->At(res), field)
+ << "Incorrect field computation expected: " << field->PrettyField()
+ << " got: " << GetIFieldsPtr()->At(res).PrettyField();
+ return res;
+}
+
+size_t Class::GetMethodIdOffset(ArtMethod* method, PointerSize pointer_size) {
+ DCHECK(GetMethodsSlice(kRuntimePointerSize).Contains(method))
+ << "method not part of the current class. " << method->PrettyMethod() << "( " << reinterpret_cast<void*>(method) << ")" << " class is "
+ << PrettyClass() << [&]() REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::ostringstream os;
+ os << " Methods are [";
+ for (ArtMethod& m : GetMethodsSlice(kRuntimePointerSize)) {
+ os << m.PrettyMethod() << "( " << reinterpret_cast<void*>(&m) << "), ";
+ }
+ os << "]";
+ return os.str();
+ }();
+ uintptr_t start = reinterpret_cast<uintptr_t>(&*GetMethodsSlice(pointer_size).begin());
+ uintptr_t fld = reinterpret_cast<uintptr_t>(method);
+ size_t art_method_size = ArtMethod::Size(pointer_size);
+ size_t art_method_align = ArtMethod::Alignment(pointer_size);
+ size_t res = (fld - start) / art_method_size;
+ DCHECK_EQ(&GetMethodsPtr()->At(res, art_method_size, art_method_align), method)
+ << "Incorrect method computation expected: " << method->PrettyMethod()
+ << " got: " << GetMethodsPtr()->At(res, art_method_size, art_method_align).PrettyMethod();
+ return res;
+}
+
} // namespace mirror
} // namespace art