ART: Update unstarted runtime for changed libcore

Update float conversion to current libcore implementation. Add
tests.

Bug: 34956610
Test: m test-art-host-gtest-unstarted_runtime_test
Change-Id: Ib62c64011e2d5b980fb8fab81f6c343065ce946c
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index ae55f4c..31be587 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -944,5 +944,100 @@
   ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
 }
 
+TEST_F(UnstartedRuntimeTest, ThreadLocalGet) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  JValue result;
+  ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+  StackHandleScope<1> hs(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  // Positive test. See that We get something for float conversion.
+  {
+    Handle<mirror::Class> floating_decimal = hs.NewHandle(
+        class_linker->FindClass(self,
+                                "Lsun/misc/FloatingDecimal;",
+                                ScopedNullHandle<mirror::ClassLoader>()));
+    ASSERT_TRUE(floating_decimal.Get() != nullptr);
+    ASSERT_TRUE(class_linker->EnsureInitialized(self, floating_decimal, true, true));
+
+    ArtMethod* caller_method = floating_decimal->FindDeclaredDirectMethod(
+        "getBinaryToASCIIBuffer",
+        "()Lsun/misc/FloatingDecimal$BinaryToASCIIBuffer;",
+        class_linker->GetImagePointerSize());
+    // floating_decimal->DumpClass(LOG_STREAM(ERROR), mirror::Class::kDumpClassFullDetail);
+    ASSERT_TRUE(caller_method != nullptr);
+    ShadowFrame* caller_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, caller_method, 0);
+    shadow_frame->SetLink(caller_frame);
+
+    UnstartedThreadLocalGet(self, shadow_frame, &result, 0);
+    EXPECT_TRUE(result.GetL() != nullptr);
+    EXPECT_FALSE(self->IsExceptionPending());
+
+    ShadowFrame::DeleteDeoptimizedFrame(caller_frame);
+  }
+
+  // Negative test.
+  PrepareForAborts();
+
+  {
+    // Just use a method in Class.
+    ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
+    ArtMethod* caller_method =
+        &*class_class->GetDeclaredMethods(class_linker->GetImagePointerSize()).begin();
+    ShadowFrame* caller_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, caller_method, 0);
+    shadow_frame->SetLink(caller_frame);
+
+    Transaction transaction;
+    Runtime::Current()->EnterTransactionMode(&transaction);
+    UnstartedThreadLocalGet(self, shadow_frame, &result, 0);
+    Runtime::Current()->ExitTransactionMode();
+    ASSERT_TRUE(self->IsExceptionPending());
+    ASSERT_TRUE(transaction.IsAborted());
+    self->ClearException();
+
+    ShadowFrame::DeleteDeoptimizedFrame(caller_frame);
+  }
+
+  ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+}
+
+TEST_F(UnstartedRuntimeTest, FloatConversion) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  StackHandleScope<1> hs(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Handle<mirror::Class> double_class = hs.NewHandle(
+          class_linker->FindClass(self,
+                                  "Ljava/lang/Double;",
+                                  ScopedNullHandle<mirror::ClassLoader>()));
+  ASSERT_TRUE(double_class.Get() != nullptr);
+  ASSERT_TRUE(class_linker->EnsureInitialized(self, double_class, true, true));
+
+  ArtMethod* method = double_class->FindDeclaredDirectMethod("toString",
+                                                             "(D)Ljava/lang/String;",
+                                                             class_linker->GetImagePointerSize());
+  ASSERT_TRUE(method != nullptr);
+
+  // create instruction data for invoke-direct {v0, v1} of method with fake index
+  uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
+  const Instruction* inst = Instruction::At(inst_data);
+
+  JValue result;
+  ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0);
+  shadow_frame->SetVRegDouble(0, 1.23);
+  interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
+  ObjPtr<mirror::String> string_result = reinterpret_cast<mirror::String*>(result.GetL());
+  ASSERT_TRUE(string_result != nullptr);
+
+  std::string mod_utf = string_result->ToModifiedUtf8();
+  EXPECT_EQ("1.23", mod_utf);
+
+  ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+}
+
 }  // namespace interpreter
 }  // namespace art