ART: Add GetSignatureAnnotation to unstarted runtime

Add support for Class.getSignatureAnnotation to the unstarted
runtime. Refactor dex file annotation code to support transactions.

Bug: 34956610
Test: m
Test: m test-art-host-gtest-unstarted_runtime_test
Test: Device boots
Change-Id: I9f4a93e05ad6999c46c3bb1dbabe48a1ad6225b2
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index a95f94c..d39ea35 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -299,6 +299,7 @@
   return result.GetL();
 }
 
+template <bool kTransactionActive>
 bool ProcessAnnotationValue(Handle<mirror::Class> klass,
                             const uint8_t** annotation_ptr,
                             DexFile::AnnotationValue* annotation_value,
@@ -409,22 +410,21 @@
         }
         PointerSize pointer_size = class_linker->GetImagePointerSize();
         set_object = true;
-        DCHECK(!Runtime::Current()->IsActiveTransaction());
         if (method->IsConstructor()) {
           if (pointer_size == PointerSize::k64) {
             element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k64,
-                                                                      false>(self, method);
+                kTransactionActive>(self, method);
           } else {
             element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k32,
-                                                                      false>(self, method);
+                kTransactionActive>(self, method);
           }
         } else {
           if (pointer_size == PointerSize::k64) {
             element_object = mirror::Method::CreateFromArtMethod<PointerSize::k64,
-                                                                 false>(self, method);
+                kTransactionActive>(self, method);
           } else {
             element_object = mirror::Method::CreateFromArtMethod<PointerSize::k32,
-                                                                 false>(self, method);
+                kTransactionActive>(self, method);
           }
         }
         if (element_object == nullptr) {
@@ -449,9 +449,11 @@
         set_object = true;
         PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
         if (pointer_size == PointerSize::k64) {
-          element_object = mirror::Field::CreateFromArtField<PointerSize::k64>(self, field, true);
+          element_object = mirror::Field::CreateFromArtField<PointerSize::k64,
+              kTransactionActive>(self, field, true);
         } else {
-          element_object = mirror::Field::CreateFromArtField<PointerSize::k32>(self, field, true);
+          element_object = mirror::Field::CreateFromArtField<PointerSize::k32,
+              kTransactionActive>(self, field, true);
         }
         if (element_object == nullptr) {
           return false;
@@ -497,45 +499,49 @@
         }
         DexFile::AnnotationValue new_annotation_value;
         for (uint32_t i = 0; i < size; ++i) {
-          if (!ProcessAnnotationValue(klass, &annotation, &new_annotation_value,
-                                      component_type, DexFile::kPrimitivesOrObjects)) {
+          if (!ProcessAnnotationValue<kTransactionActive>(klass,
+                                                          &annotation,
+                                                          &new_annotation_value,
+                                                          component_type,
+                                                          DexFile::kPrimitivesOrObjects)) {
             return false;
           }
           if (!component_type->IsPrimitive()) {
             mirror::Object* obj = new_annotation_value.value_.GetL();
-            new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<false>(i, obj);
+            new_array->AsObjectArray<mirror::Object>()->
+                SetWithoutChecks<kTransactionActive>(i, obj);
           } else {
             switch (new_annotation_value.type_) {
               case DexFile::kDexAnnotationByte:
-                new_array->AsByteArray()->SetWithoutChecks<false>(
+                new_array->AsByteArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetB());
                 break;
               case DexFile::kDexAnnotationShort:
-                new_array->AsShortArray()->SetWithoutChecks<false>(
+                new_array->AsShortArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetS());
                 break;
               case DexFile::kDexAnnotationChar:
-                new_array->AsCharArray()->SetWithoutChecks<false>(
+                new_array->AsCharArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetC());
                 break;
               case DexFile::kDexAnnotationInt:
-                new_array->AsIntArray()->SetWithoutChecks<false>(
+                new_array->AsIntArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetI());
                 break;
               case DexFile::kDexAnnotationLong:
-                new_array->AsLongArray()->SetWithoutChecks<false>(
+                new_array->AsLongArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetJ());
                 break;
               case DexFile::kDexAnnotationFloat:
-                new_array->AsFloatArray()->SetWithoutChecks<false>(
+                new_array->AsFloatArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetF());
                 break;
               case DexFile::kDexAnnotationDouble:
-                new_array->AsDoubleArray()->SetWithoutChecks<false>(
+                new_array->AsDoubleArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetD());
                 break;
               case DexFile::kDexAnnotationBoolean:
-                new_array->AsBooleanArray()->SetWithoutChecks<false>(
+                new_array->AsBooleanArray()->SetWithoutChecks<kTransactionActive>(
                     i, new_annotation_value.value_.GetZ());
                 break;
               default:
@@ -611,8 +617,11 @@
       annotation_method->GetReturnType(true /* resolve */)));
 
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return,
-                              DexFile::kAllObjects)) {
+  if (!ProcessAnnotationValue<false>(klass,
+                                     annotation,
+                                     &annotation_value,
+                                     method_return,
+                                     DexFile::kAllObjects)) {
     return nullptr;
   }
   Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL()));
@@ -716,8 +725,18 @@
     return nullptr;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, array_class,
-                              DexFile::kAllObjects)) {
+  bool result = Runtime::Current()->IsActiveTransaction()
+      ? ProcessAnnotationValue<true>(klass,
+                                     &annotation,
+                                     &annotation_value,
+                                     array_class,
+                                     DexFile::kAllObjects)
+      : ProcessAnnotationValue<false>(klass,
+                                      &annotation,
+                                      &annotation_value,
+                                      array_class,
+                                      DexFile::kAllObjects);
+  if (!result) {
     return nullptr;
   }
   if (annotation_value.type_ != expected_type) {
@@ -949,8 +968,11 @@
   StackHandleScope<2> hs(Thread::Current());
   Handle<mirror::Class> h_klass(hs.NewHandle(klass));
   Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType(true /* resolve */)));
-  if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type,
-                              DexFile::kAllObjects)) {
+  if (!ProcessAnnotationValue<false>(h_klass,
+                                     &annotation,
+                                     &annotation_value,
+                                     return_type,
+                                     DexFile::kAllObjects)) {
     return nullptr;
   }
   return annotation_value.value_.GetL();
@@ -1201,8 +1223,11 @@
     return nullptr;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
-                              ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) {
+  if (!ProcessAnnotationValue<false>(klass,
+                                     &annotation,
+                                     &annotation_value,
+                                     ScopedNullHandle<mirror::Class>(),
+                                     DexFile::kAllRaw)) {
     return nullptr;
   }
   if (annotation_value.type_ != DexFile::kDexAnnotationMethod) {
@@ -1252,9 +1277,11 @@
     return false;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
-                              ScopedNullHandle<mirror::Class>(),
-                                           DexFile::kAllObjects)) {
+  if (!ProcessAnnotationValue<false>(klass,
+                                     &annotation,
+                                     &annotation_value,
+                                     ScopedNullHandle<mirror::Class>(),
+                                     DexFile::kAllObjects)) {
     return false;
   }
   if (annotation_value.type_ != DexFile::kDexAnnotationNull &&
@@ -1283,8 +1310,11 @@
     return false;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
-                              ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) {
+  if (!ProcessAnnotationValue<false>(klass,
+                                     &annotation,
+                                     &annotation_value,
+                                     ScopedNullHandle<mirror::Class>(),
+                                     DexFile::kAllRaw)) {
     return false;
   }
   if (annotation_value.type_ != DexFile::kDexAnnotationInt) {
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index fc21945..4a321e6 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -445,6 +445,20 @@
   result->SetI(mirror::Class::GetInnerClassFlags(klass, default_value));
 }
 
+void UnstartedRuntime::UnstartedClassGetSignatureAnnotation(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> klass(hs.NewHandle(
+      reinterpret_cast<mirror::Class*>(shadow_frame->GetVRegReference(arg_offset))));
+
+  if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
+    result->SetL(nullptr);
+    return;
+  }
+
+  result->SetL(annotations::GetSignatureAnnotationForClass(klass));
+}
+
 void UnstartedRuntime::UnstartedClassIsAnonymousClass(
     Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
   StackHandleScope<1> hs(self);
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index 929b747..c6114da 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -31,6 +31,7 @@
   V(ClassGetDeclaringClass, "java.lang.Class java.lang.Class.getDeclaringClass()") \
   V(ClassGetEnclosingClass, "java.lang.Class java.lang.Class.getEnclosingClass()") \
   V(ClassGetInnerClassFlags, "int java.lang.Class.getInnerClassFlags(int)") \
+  V(ClassGetSignatureAnnotation, "java.lang.String[] java.lang.Class.getSignatureAnnotation()") \
   V(ClassIsAnonymousClass, "boolean java.lang.Class.isAnonymousClass()") \
   V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \
   V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 3a0d0e7..4186c37 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -29,6 +29,8 @@
 #include "handle_scope-inl.h"
 #include "interpreter/interpreter_common.h"
 #include "mirror/class_loader.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
 #include "mirror/string-inl.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
@@ -1077,9 +1079,9 @@
   StackHandleScope<1> hs(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::Class> log_manager_class = hs.NewHandle(
-          class_linker->FindClass(self,
-                                  "Ljava/util/logging/LogManager;",
-                                  ScopedNullHandle<mirror::ClassLoader>()));
+      class_linker->FindClass(self,
+                              "Ljava/util/logging/LogManager;",
+                              ScopedNullHandle<mirror::ClassLoader>()));
   ASSERT_TRUE(log_manager_class.Get() != nullptr);
   ASSERT_TRUE(class_linker->EnsureInitialized(self, log_manager_class, true, true));
 }
@@ -1278,5 +1280,42 @@
   RunTest(runner, true, false);
 }
 
+TEST_F(UnstartedRuntimeTest, ClassGetSignatureAnnotation) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  StackHandleScope<1> hs(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Handle<mirror::Class> list_class = hs.NewHandle(
+      class_linker->FindClass(self,
+                              "Ljava/util/List;",
+                              ScopedNullHandle<mirror::ClassLoader>()));
+  ASSERT_TRUE(list_class.Get() != nullptr);
+  ASSERT_TRUE(class_linker->EnsureInitialized(self, list_class, true, true));
+
+  JValue result;
+  ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+  shadow_frame->SetVRegReference(0, list_class.Get());
+  UnstartedClassGetSignatureAnnotation(self, shadow_frame, &result, 0);
+  ASSERT_TRUE(result.GetL() != nullptr);
+  ASSERT_FALSE(self->IsExceptionPending());
+
+  ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+
+  ASSERT_TRUE(result.GetL()->IsObjectArray());
+  ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+      result.GetL()->AsObjectArray<mirror::Object>();
+  std::ostringstream oss;
+  for (int32_t i = 0; i != array->GetLength(); ++i) {
+    ObjPtr<mirror::Object> elem = array->Get(i);
+    ASSERT_TRUE(elem != nullptr);
+    ASSERT_TRUE(elem->IsString());
+    oss << elem->AsString()->ToModifiedUtf8();
+  }
+  std::string output_string = oss.str();
+  ASSERT_EQ(output_string, "<E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;");
+}
+
 }  // namespace interpreter
 }  // namespace art