ART: Add integer & long parsing cutout to unstarted runtime

Add a cutout for Integer.parseInt and Long.parseLong. Only handle
(some) successful cases, and abort the transaction in the rest.
Add tests.

Allows to compile-time initialize:
* com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
* com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers
* sun.security.x509.InhibitAnyPolicyExtension

Bug: 27265238

(cherry picked from commit 9c62dab16e4be0c19a2e6c6c0cc2b24c2814c6f2)

Change-Id: I14c0836fd9ec7c9bf49d8186ff14a3c6830ff711
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 239b825..0e18945 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -16,7 +16,11 @@
 
 #include "unstarted_runtime.h"
 
+#include <errno.h>
+#include <stdlib.h>
+
 #include <cmath>
+#include <limits>
 #include <unordered_map>
 
 #include "ScopedLocalRef.h"
@@ -1069,6 +1073,93 @@
   }
 }
 
+// A cutout for Integer.parseInt(String). Note: this code is conservative and will bail instead
+// of correctly handling the corner cases.
+void UnstartedRuntime::UnstartedIntegerParseInt(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset);
+  if (obj == nullptr) {
+    AbortTransactionOrFail(self, "Cannot parse null string, retry at runtime.");
+    return;
+  }
+
+  std::string string_value = obj->AsString()->ToModifiedUtf8();
+  if (string_value.empty()) {
+    AbortTransactionOrFail(self, "Cannot parse empty string, retry at runtime.");
+    return;
+  }
+
+  const char* c_str = string_value.c_str();
+  char *end;
+  // Can we set errno to 0? Is this always a variable, and not a macro?
+  // Worst case, we'll incorrectly fail a transaction. Seems OK.
+  int64_t l = strtol(c_str, &end, 10);
+
+  if ((errno == ERANGE && l == LONG_MAX) || l > std::numeric_limits<int32_t>::max() ||
+      (errno == ERANGE && l == LONG_MIN) || l < std::numeric_limits<int32_t>::min()) {
+    AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str);
+    return;
+  }
+  if (l == 0) {
+    // Check whether the string wasn't exactly zero.
+    if (string_value != "0") {
+      AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str);
+      return;
+    }
+  } else if (*end != '\0') {
+    AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str);
+    return;
+  }
+
+  result->SetI(static_cast<int32_t>(l));
+}
+
+// A cutout for Long.parseLong.
+//
+// Note: for now use code equivalent to Integer.parseInt, as the full range may not be supported
+//       well.
+void UnstartedRuntime::UnstartedLongParseLong(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset);
+  if (obj == nullptr) {
+    AbortTransactionOrFail(self, "Cannot parse null string, retry at runtime.");
+    return;
+  }
+
+  std::string string_value = obj->AsString()->ToModifiedUtf8();
+  if (string_value.empty()) {
+    AbortTransactionOrFail(self, "Cannot parse empty string, retry at runtime.");
+    return;
+  }
+
+  const char* c_str = string_value.c_str();
+  char *end;
+  // Can we set errno to 0? Is this always a variable, and not a macro?
+  // Worst case, we'll incorrectly fail a transaction. Seems OK.
+  int64_t l = strtol(c_str, &end, 10);
+
+  // Note: comparing against int32_t min/max is intentional here.
+  if ((errno == ERANGE && l == LONG_MAX) || l > std::numeric_limits<int32_t>::max() ||
+      (errno == ERANGE && l == LONG_MIN) || l < std::numeric_limits<int32_t>::min()) {
+    AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str);
+    return;
+  }
+  if (l == 0) {
+    // Check whether the string wasn't exactly zero.
+    if (string_value != "0") {
+      AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str);
+      return;
+    }
+  } else if (*end != '\0') {
+    AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str);
+    return;
+  }
+
+  result->SetJ(l);
+}
+
 
 void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray(
     Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index 7aeec61..dc7bcfe 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -57,7 +57,9 @@
   V(UnsafeCompareAndSwapLong, "boolean sun.misc.Unsafe.compareAndSwapLong(java.lang.Object, long, long, long)") \
   V(UnsafeCompareAndSwapObject, "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") \
   V(UnsafeGetObjectVolatile, "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") \
-  V(UnsafePutOrderedObject, "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)")
+  V(UnsafePutOrderedObject, "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") \
+  V(IntegerParseInt, "int java.lang.Integer.parseInt(java.lang.String)") \
+  V(LongParseLong, "long java.lang.Long.parseLong(java.lang.String)")
 
 // Methods that are native.
 #define UNSTARTED_RUNTIME_JNI_LIST(V)           \
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index fb53b1d..f40e4e3 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -508,5 +508,100 @@
   ShadowFrame::DeleteDeoptimizedFrame(tmp);
 }
 
+TEST_F(UnstartedRuntimeTest, IntegerParseIntTest) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+  // Test string. Should be valid, and between minimal values of LONG_MIN and LONG_MAX (for all
+  // suffixes).
+  constexpr const char* test_string = "-2147483646";
+  constexpr int32_t test_values[] = {
+                6,
+               46,
+              646,
+             3646,
+            83646,
+           483646,
+          7483646,
+         47483646,
+        147483646,
+       2147483646,
+      -2147483646
+  };
+
+  static_assert(arraysize(test_values) == 11U, "test_values");
+  CHECK_EQ(strlen(test_string), 11U);
+
+  for (size_t i = 0; i <= 10; ++i) {
+    const char* test_value = &test_string[10 - i];
+
+    StackHandleScope<1> hs_str(self);
+    Handle<mirror::String> h_str(
+        hs_str.NewHandle(mirror::String::AllocFromModifiedUtf8(self, test_value)));
+    ASSERT_NE(h_str.Get(), nullptr);
+    ASSERT_FALSE(self->IsExceptionPending());
+
+    tmp->SetVRegReference(0, h_str.Get());
+
+    JValue result;
+    UnstartedIntegerParseInt(self, tmp, &result, 0);
+
+    ASSERT_FALSE(self->IsExceptionPending());
+    EXPECT_EQ(result.GetI(), test_values[i]);
+  }
+
+  ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+// Right now the same as Integer.Parse
+TEST_F(UnstartedRuntimeTest, LongParseLongTest) {
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+  // Test string. Should be valid, and between minimal values of LONG_MIN and LONG_MAX (for all
+  // suffixes).
+  constexpr const char* test_string = "-2147483646";
+  constexpr int64_t test_values[] = {
+                6,
+               46,
+              646,
+             3646,
+            83646,
+           483646,
+          7483646,
+         47483646,
+        147483646,
+       2147483646,
+      -2147483646
+  };
+
+  static_assert(arraysize(test_values) == 11U, "test_values");
+  CHECK_EQ(strlen(test_string), 11U);
+
+  for (size_t i = 0; i <= 10; ++i) {
+    const char* test_value = &test_string[10 - i];
+
+    StackHandleScope<1> hs_str(self);
+    Handle<mirror::String> h_str(
+        hs_str.NewHandle(mirror::String::AllocFromModifiedUtf8(self, test_value)));
+    ASSERT_NE(h_str.Get(), nullptr);
+    ASSERT_FALSE(self->IsExceptionPending());
+
+    tmp->SetVRegReference(0, h_str.Get());
+
+    JValue result;
+    UnstartedLongParseLong(self, tmp, &result, 0);
+
+    ASSERT_FALSE(self->IsExceptionPending());
+    EXPECT_EQ(result.GetJ(), test_values[i]);
+  }
+
+  ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
 }  // namespace interpreter
 }  // namespace art