Revert "Revert "Basic structural redefinition support""
This reverts commit 5a2301d897294ff4ee6de71f459dc2566dc3fa1a.
Bug: 134162467
Reason for revert: Relanding as unclear if issue is due to topic.
Change-Id: Ib1d1cf2e9132e30c9649b760ae9ae2d8ceacf843
diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h
index 263b774..8c85387 100644
--- a/runtime/mirror/class-refvisitor-inl.h
+++ b/runtime/mirror/class-refvisitor-inl.h
@@ -53,20 +53,14 @@
template<ReadBarrierOption kReadBarrierOption, class Visitor>
void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) {
- for (ArtField& field : GetSFieldsUnchecked()) {
- // Visit roots first in case the declaring class gets moved.
- field.VisitRoots(visitor);
+ VisitFields<kReadBarrierOption>([&](ArtField* field) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ field->VisitRoots(visitor);
if (kIsDebugBuild && IsResolved()) {
- CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus();
+ CHECK_EQ(field->GetDeclaringClass<kReadBarrierOption>(), this)
+ << GetStatus() << field->GetDeclaringClass()->PrettyClass() << " != " << PrettyClass();
}
- }
- for (ArtField& field : GetIFieldsUnchecked()) {
- // Visit roots first in case the declaring class gets moved.
- field.VisitRoots(visitor);
- if (kIsDebugBuild && IsResolved()) {
- CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus();
- }
- }
+ });
+ // Don't use VisitMethods because we don't want to hit the class-ext methods twice.
for (ArtMethod& method : GetMethods(pointer_size)) {
method.VisitRoots<kReadBarrierOption>(visitor, pointer_size);
}
@@ -76,6 +70,27 @@
}
}
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void Class::VisitMethods(Visitor visitor, PointerSize pointer_size) {
+ for (ArtMethod& method : GetMethods(pointer_size)) {
+ visitor(&method);
+ }
+ ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>());
+ if (!ext.IsNull()) {
+ ext->VisitMethods<kReadBarrierOption, Visitor>(visitor, pointer_size);
+ }
+}
+
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void Class::VisitFields(Visitor visitor) {
+ for (ArtField& sfield : GetSFieldsUnchecked()) {
+ visitor(&sfield);
+ }
+ for (ArtField& ifield : GetIFieldsUnchecked()) {
+ visitor(&ifield);
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 7dff9df..455f98d 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -1539,6 +1539,12 @@
std::string Class::PrettyClass() {
std::string result;
+ if (IsObsoleteObject()) {
+ result += "(Obsolete)";
+ }
+ if (IsRetired()) {
+ result += "(Retired)";
+ }
result += "java.lang.Class<";
result += PrettyDescriptor();
result += ">";
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 960f49c..6ed20ed 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -313,6 +313,17 @@
}
}
+ bool IsObsoleteObject() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return (GetAccessFlags() & kAccObsoleteObject) != 0;
+ }
+
+ void SetObsoleteObject() REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+ if ((flags & kAccObsoleteObject) == 0) {
+ SetAccessFlags(flags | kAccObsoleteObject);
+ }
+ }
+
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsTypeOfReferenceClass() REQUIRES_SHARED(Locks::mutator_lock_) {
return (GetClassFlags<kVerifyFlags>() & kClassFlagReference) != 0;
@@ -1110,6 +1121,15 @@
void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Visit ArtMethods directly owned by this class.
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
+ void VisitMethods(Visitor visitor, PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Visit ArtFields directly owned by this class.
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
+ void VisitFields(Visitor visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
// Get one of the primitive classes.
static ObjPtr<mirror::Class> GetPrimitiveClass(ObjPtr<mirror::String> name)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/class_ext-inl.h b/runtime/mirror/class_ext-inl.h
index ead02ee..fd81a2a 100644
--- a/runtime/mirror/class_ext-inl.h
+++ b/runtime/mirror/class_ext-inl.h
@@ -21,8 +21,11 @@
#include "array-inl.h"
#include "art_method-inl.h"
+#include "base/enums.h"
#include "handle_scope.h"
+#include "mirror/object.h"
#include "object-inl.h"
+#include "verify_object.h"
namespace art {
namespace mirror {
@@ -89,6 +92,12 @@
}
template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+inline ObjPtr<Class> ClassExt::GetObsoleteClass() {
+ return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(
+ OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_class_));
+}
+
+template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline ObjPtr<PointerArray> ClassExt::GetJMethodIDs() {
return GetFieldObject<PointerArray, kVerifyFlags, kReadBarrierOption>(
OFFSET_OF_OBJECT_MEMBER(ClassExt, jmethod_ids_));
@@ -116,15 +125,58 @@
template<ReadBarrierOption kReadBarrierOption, class Visitor>
void ClassExt::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) {
+ VisitMethods<kReadBarrierOption>([&](ArtMethod* method) {
+ method->VisitRoots<kReadBarrierOption>(visitor, pointer_size);
+ }, pointer_size);
+}
+
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void ClassExt::VisitMethods(Visitor visitor, PointerSize pointer_size) {
ObjPtr<PointerArray> arr(GetObsoleteMethods<kDefaultVerifyFlags, kReadBarrierOption>());
- if (arr.IsNull()) {
- return;
+ if (!arr.IsNull()) {
+ int32_t len = arr->GetLength();
+ for (int32_t i = 0; i < len; i++) {
+ ArtMethod* method = arr->GetElementPtrSize<ArtMethod*>(i, pointer_size);
+ if (method != nullptr) {
+ visitor(method);
+ }
+ }
}
- int32_t len = arr->GetLength();
- for (int32_t i = 0; i < len; i++) {
- ArtMethod* method = arr->GetElementPtrSize<ArtMethod*, kDefaultVerifyFlags>(i, pointer_size);
- if (method != nullptr) {
- method->VisitRoots<kReadBarrierOption>(visitor, pointer_size);
+}
+
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void ClassExt::VisitJMethodIDs(Visitor v) {
+ ObjPtr<PointerArray> marr(GetJMethodIDs<kDefaultVerifyFlags, kReadBarrierOption>());
+ if (!marr.IsNull()) {
+ int32_t len = marr->GetLength();
+ for (int32_t i = 0; i < len; i++) {
+ jmethodID id = marr->GetElementPtrSize<jmethodID>(i, kRuntimePointerSize);
+ if (id != nullptr) {
+ v(id, i);
+ }
+ }
+ }
+}
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void ClassExt::VisitJFieldIDs(Visitor v) {
+ ObjPtr<PointerArray> sarr(GetStaticJFieldIDs<kDefaultVerifyFlags, kReadBarrierOption>());
+ if (!sarr.IsNull()) {
+ int32_t len = sarr->GetLength();
+ for (int32_t i = 0; i < len; i++) {
+ jfieldID id = sarr->GetElementPtrSize<jfieldID>(i, kRuntimePointerSize);
+ if (id != nullptr) {
+ v(id, i, true);
+ }
+ }
+ }
+ ObjPtr<PointerArray> iarr(GetInstanceJFieldIDs<kDefaultVerifyFlags, kReadBarrierOption>());
+ if (!iarr.IsNull()) {
+ int32_t len = iarr->GetLength();
+ for (int32_t i = 0; i < len; i++) {
+ jfieldID id = iarr->GetElementPtrSize<jfieldID>(i, kRuntimePointerSize);
+ if (id != nullptr) {
+ v(id, i, false);
+ }
}
}
}
diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc
index 4c6cb4d..27dcea8 100644
--- a/runtime/mirror/class_ext.cc
+++ b/runtime/mirror/class_ext.cc
@@ -25,6 +25,8 @@
#include "class_root.h"
#include "dex/dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
+#include "mirror/object.h"
+#include "mirror/object_array.h"
#include "object-inl.h"
#include "object_array-alloc-inl.h"
#include "object_array-inl.h"
@@ -101,6 +103,10 @@
return true;
}
+void ClassExt::SetObsoleteClass(ObjPtr<Class> klass) {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_class_), klass);
+}
+
ObjPtr<ClassExt> ClassExt::Alloc(Thread* self) {
return ObjPtr<ClassExt>::DownCast(GetClassRoot<ClassExt>()->AllocObject(self));
}
diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h
index 6fb225f..eb4047b 100644
--- a/runtime/mirror/class_ext.h
+++ b/runtime/mirror/class_ext.h
@@ -106,8 +106,26 @@
inline void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
+ inline void VisitMethods(Visitor visitor, PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
static ObjPtr<ClassExt> 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<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ ObjPtr<Class> GetObsoleteClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ void SetObsoleteClass(ObjPtr<Class> classes) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
+ inline void VisitJFieldIDs(Visitor v) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
+ inline void VisitJMethodIDs(Visitor v) REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
@@ -123,6 +141,9 @@
// the classes methods_ array or '0' if no id has been assigned to that method yet.
HeapReference<PointerArray> jmethod_ids_;
+ // If set this is the Class object that was being used before a structural redefinition occurred.
+ HeapReference<Class> obsolete_class_;
+
HeapReference<ObjectArray<DexCache>> obsolete_dex_caches_;
HeapReference<PointerArray> obsolete_methods_;
@@ -137,8 +158,8 @@
HeapReference<Object> 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);
diff --git a/runtime/mirror/executable-inl.h b/runtime/mirror/executable-inl.h
index 6d4b46a..ce35d6e 100644
--- a/runtime/mirror/executable-inl.h
+++ b/runtime/mirror/executable-inl.h
@@ -20,6 +20,7 @@
#include "executable.h"
#include "object-inl.h"
+#include "verify_object.h"
namespace art {
namespace mirror {
@@ -36,6 +37,17 @@
return GetFieldObject<mirror::Class>(DeclaringClassOffset());
}
+template<typename Visitor, VerifyObjectFlags kVerifiyFlags>
+inline void Executable::VisitTarget(Visitor&& v) {
+ ArtMethod* orig = GetArtMethod<kVerifiyFlags>();
+ ArtMethod* new_target = v(orig);
+ if (orig != new_target) {
+ SetArtMethod(new_target);
+ SetDexMethodIndex(new_target->GetDexMethodIndex());
+ SetDeclaringClass(new_target->GetDeclaringClass());
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index a99c3ec..8eca206 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -41,6 +41,10 @@
return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
}
+ template <typename Visitor,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
template <bool kTransactionActive = false,
bool kCheckTransaction = true,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -61,6 +65,21 @@
uint32_t access_flags_;
uint32_t dex_method_index_;
+ template<bool kTransactionActive = false>
+ void SetDeclaringClass(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+ SetFieldObject<kTransactionActive>(DeclaringClassOffset(), klass);
+ }
+
+ template<bool kTransactionActive = false>
+ void SetAccessFlags(uint32_t flags) REQUIRES_SHARED(Locks::mutator_lock_) {
+ SetField32<kTransactionActive>(AccessFlagsOffset(), flags);
+ }
+
+ template<bool kTransactionActive = false>
+ void SetDexMethodIndex(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_) {
+ SetField32<kTransactionActive>(DexMethodIndexOffset(), idx);
+ }
+
static MemberOffset DeclaringClassOffset() {
return MemberOffset(OFFSETOF_MEMBER(Executable, declaring_class_));
}
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index ac11be1..6e82d6d 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -104,6 +104,18 @@
SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, type_), type);
}
+template<typename Visitor>
+inline void Field::VisitTarget(Visitor&& v) {
+ ArtField* orig = GetArtField(/*use_dex_cache*/false);
+ ArtField* new_value = v(orig);
+ if (orig != new_value) {
+ SetDexFieldIndex<false>(new_value->GetDexFieldIndex());
+ SetOffset<false>(new_value->GetOffset().Int32Value());
+ SetDeclaringClass<false>(new_value->GetDeclaringClass());
+ }
+ DCHECK_EQ(new_value, GetArtField(/*use_dex_cache*/false));
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc
index f4d1e73..9a40006 100644
--- a/runtime/mirror/field.cc
+++ b/runtime/mirror/field.cc
@@ -24,7 +24,7 @@
namespace art {
namespace mirror {
-ArtField* Field::GetArtField() {
+ArtField* Field::GetArtField(bool use_dex_cache) {
ObjPtr<mirror::Class> declaring_class = GetDeclaringClass();
if (UNLIKELY(declaring_class->IsProxyClass())) {
DCHECK(IsStatic());
@@ -38,7 +38,9 @@
}
}
const ObjPtr<mirror::DexCache> dex_cache = declaring_class->GetDexCache();
- ArtField* art_field = dex_cache->GetResolvedField(GetDexFieldIndex(), kRuntimePointerSize);
+ ArtField* art_field = use_dex_cache
+ ? dex_cache->GetResolvedField(GetDexFieldIndex(), kRuntimePointerSize)
+ : nullptr;
if (UNLIKELY(art_field == nullptr)) {
if (IsStatic()) {
art_field = declaring_class->FindDeclaredStaticField(dex_cache, GetDexFieldIndex());
@@ -46,7 +48,9 @@
art_field = declaring_class->FindInstanceField(dex_cache, GetDexFieldIndex());
}
CHECK(art_field != nullptr);
- dex_cache->SetResolvedField(GetDexFieldIndex(), art_field, kRuntimePointerSize);
+ if (use_dex_cache) {
+ dex_cache->SetResolvedField(GetDexFieldIndex(), art_field, kRuntimePointerSize);
+ }
}
CHECK_EQ(declaring_class, art_field->GetDeclaringClass());
return art_field;
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 6ba8dc6..89c86e3 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -68,8 +68,10 @@
return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_));
}
- // Slow, try to use only for PrettyField and such.
- ArtField* GetArtField() REQUIRES_SHARED(Locks::mutator_lock_);
+ // Slow, try to use only for PrettyField and such. Set use-dex-cache to false to not utilize the
+ // dex-cache when finding the art-field. This is useful for cases where the dex-cache might be
+ // temporarally invalid.
+ ArtField* GetArtField(bool use_dex_cache = true) REQUIRES_SHARED(Locks::mutator_lock_);
template <PointerSize kPointerSize, bool kTransactionActive = false>
static ObjPtr<mirror::Field> CreateFromArtField(Thread* self,
@@ -77,6 +79,12 @@
bool force_resolve)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ // Used to modify the target of this Field object, if required for structural redefinition or some
+ // other purpose.
+ template<typename Visitor>
+ inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
private:
// Padding required for matching alignment with the Java peer.
uint8_t padding_[2];
diff --git a/runtime/mirror/method_handle_impl-inl.h b/runtime/mirror/method_handle_impl-inl.h
index 932b434..0085642 100644
--- a/runtime/mirror/method_handle_impl-inl.h
+++ b/runtime/mirror/method_handle_impl-inl.h
@@ -39,6 +39,20 @@
GetTargetMethod()->GetDeclaringClass() : GetTargetField()->GetDeclaringClass();
}
+template<typename Visitor>
+inline void MethodHandle::VisitTarget(Visitor&& v) {
+ void* target = GetTargetField();
+ void* result;
+ if (GetHandleKind() < kFirstAccessorKind) {
+ result = v(GetTargetMethod());
+ } else {
+ result = v(GetTargetField());
+ }
+ if (result != target) {
+ SetField64<false>(ArtFieldOrMethodOffset(), reinterpret_cast<uintptr_t>(result));
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index c973a24..357ec9d 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -87,6 +87,11 @@
// supported.
static const char* GetReturnTypeDescriptor(const char* invoke_method_name);
+ // Used when classes become structurally obsolete to change the MethodHandle to refer to the new
+ // method or field.
+ template<typename Visitor>
+ void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
protected:
void Initialize(uintptr_t art_field_or_method, Kind kind, Handle<MethodType> method_type)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle-inl.h b/runtime/mirror/var_handle-inl.h
new file mode 100644
index 0000000..d3f582d
--- /dev/null
+++ b/runtime/mirror/var_handle-inl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
+#define ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
+
+#include "var_handle.h"
+
+namespace art {
+class ArtField;
+
+namespace mirror {
+
+template<typename Visitor>
+inline void FieldVarHandle::VisitTarget(Visitor&& v) {
+ ArtField* orig = GetField();
+ ArtField* new_value = v(orig);
+ if (orig != new_value) {
+ SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
+ reinterpret_cast<uintptr_t>(new_value));
+ }
+}
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index a46b466..ac78d98 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -197,6 +197,10 @@
ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_);
+ // Used for updating var-handles to obsolete fields.
+ template<typename Visitor>
+ inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
private:
static MemberOffset ArtFieldOffset() {
return MemberOffset(OFFSETOF_MEMBER(FieldVarHandle, art_field_));