ART: Add constructor support to unstarted runtime

Add support for Constructor.newInstance0.

Bug: 34956610
Test: m
Test: m test-art-host-gtest-unstarted_runtime_test
Test: Device boots
Change-Id: Ifcea33359c30b70262cd2f4f56f59515b06532ce
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 4186c37..db222fa 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -1317,5 +1317,55 @@
   ASSERT_EQ(output_string, "<E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;");
 }
 
+TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  StackHandleScope<4> hs(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  // Get Throwable.
+  Handle<mirror::Class> throw_class = hs.NewHandle(mirror::Throwable::GetJavaLangThrowable());
+  ASSERT_TRUE(class_linker->EnsureInitialized(self, throw_class, true, true));
+
+  // Get an input object.
+  Handle<mirror::String> input = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "abd"));
+
+  // Find the constructor.
+  ArtMethod* throw_cons = throw_class->FindDeclaredDirectMethod(
+      "<init>", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
+  ASSERT_TRUE(throw_cons != nullptr);
+
+  Handle<mirror::Constructor> cons = hs.NewHandle(
+      mirror::Constructor::CreateFromArtMethod<kRuntimePointerSize, false>(self, throw_cons));
+  ASSERT_TRUE(cons != nullptr);
+
+  Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle(
+      class_linker->AllocObjectArray<mirror::Object>(self, 1));
+  ASSERT_TRUE(args != nullptr);
+  args->Set(0, input.Get());
+
+  // OK, we're ready now.
+  JValue result;
+  ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+  shadow_frame->SetVRegReference(0, cons.Get());
+  shadow_frame->SetVRegReference(1, args.Get());
+  UnstartedConstructorNewInstance0(self, shadow_frame, &result, 0);
+
+  ASSERT_TRUE(result.GetL() != nullptr);
+  ASSERT_FALSE(self->IsExceptionPending());
+
+  // Should be a new object.
+  ASSERT_NE(result.GetL(), input.Get());
+  // Should be a String.
+  ASSERT_EQ(mirror::Throwable::GetJavaLangThrowable(), result.GetL()->GetClass());
+  // Should have the right string.
+  ObjPtr<mirror::String> result_msg =
+      reinterpret_cast<mirror::Throwable*>(result.GetL())->GetDetailMessage();
+  EXPECT_EQ(input.Get(), result_msg.Ptr());
+
+  ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+}
+
 }  // namespace interpreter
 }  // namespace art