summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
author Victor Chang <vichang@google.com> 2023-03-21 17:00:46 +0000
committer Victor Chang <vichang@google.com> 2023-03-27 08:59:07 +0000
commit4efc53d64dd5a04fcb9203bee756ae462c6da9f9 (patch)
tree2d07b8b73d81664213dec5d36acb58a99be8d171 /runtime/class_linker.cc
parent456ea95d710b05659a87b5f348f523493a7718c6 (diff)
Set Record flag during class linking
It's needed for adding new record-specific behavior in ART. For example, fields are still immutable and un-modifiable via java.lang.reflect.Field#set*() API. See http://b/272698028 Bug: 272698028 Test: atest CtsLibcoreTestCases:RecordTest Change-Id: I6805fc4a8b8966b913eaba9f7c4dfdd1ab5886c4
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc59
1 files changed, 59 insertions, 0 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 314ba40c6b..da7b845d67 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -70,6 +70,7 @@
#include "dex/class_accessor-inl.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
#include "dex/dex_file_exception_helpers.h"
#include "dex/dex_file_loader.h"
#include "dex/signature-inl.h"
@@ -6121,6 +6122,7 @@ bool ClassLinker::LinkClass(Thread* self,
if (!LinkStaticFields(self, klass, &class_size)) {
return false;
}
+ SetRecordClassFlagIfNeeded(klass);
CreateReferenceInstanceOffsets(klass);
CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());
@@ -9350,6 +9352,63 @@ bool ClassLinker::LinkStaticFields(Thread* self, Handle<mirror::Class> klass, si
return LinkFieldsHelper::LinkFields(this, self, klass, true, class_size);
}
+// Set kClassFlagRecord if all conditions are fulfilled.
+void ClassLinker::SetRecordClassFlagIfNeeded(Handle<mirror::Class> klass) {
+ CHECK(klass != nullptr);
+ // First, we check the conditions specified in java.lang.Class#isRecord().
+ // If any of the following check fails, ART will treat it as a normal class,
+ // but still inherited from java.lang.Record.
+ if (!klass->IsFinal()) {
+ return;
+ }
+
+ ObjPtr<mirror::Class> super = klass->GetSuperClass();
+ if (super == nullptr) {
+ return;
+ }
+
+ // Compare the string directly when this ClassLinker is initializing before
+ // WellKnownClasses initializes
+ if (WellKnownClasses::java_lang_Record == nullptr) {
+ if (!super->DescriptorEquals("Ljava/lang/Record;")) {
+ return;
+ }
+ } else {
+ ObjPtr<mirror::Class> java_lang_Record =
+ WellKnownClasses::ToClass(WellKnownClasses::java_lang_Record);
+ if (super.Ptr() != java_lang_Record.Ptr()) {
+ return;
+ }
+ }
+
+ // Record class should have record attributes specifying various things,
+ // including component type, name and the order of record components. The dexer
+ // should emit @dalvik.annotation.Record annotation. But before the annotation is
+ // emitted correctly b/272698028, we workaround by reading @MethodParameters annotation
+ // as a temporary replacement.
+ uint32_t num_of_fields = klass->NumInstanceFields();
+ for (ArtMethod& method : klass->GetDirectMethods(image_pointer_size_)) {
+ // JLS 8.10.2 Record body can't declare instance fields.
+ // JLS 8.10.4 Record class has only one canonical constructor.
+ // Dexer should emit @MethodParameters method annotation along with
+ // the canonical constructor.
+ if (method.IsConstructor() && method.GetNumberOfParameters() == num_of_fields) {
+ if (num_of_fields == 0 ||
+ annotations::IsMethodAnnotationPresent(
+ &method, "Ldalvik/annotation/MethodParameters;", DexFile::kDexVisibilitySystem)) {
+ // JLS 8.10.4 / 8.10.4.1 We should check if the constructor
+ // doesn't invoke other constructor in this class or invoke the super
+ // class constructor to confirm that it's the canonical constructor.
+
+ // But it's good enough until @dalvik.annotation.Record is emitted
+ // from the dexer.
+ klass->SetRecordClass();
+ return;
+ }
+ }
+ }
+}
+
// Set the bitmap of reference instance field offsets.
void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) {
uint32_t reference_offsets = 0;