Merge "Add new style String operations during compilation init, part 2"
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 9006257..317106b 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -767,8 +767,12 @@
     AbortTransactionOrFail(self, "String.getCharsNoCheck with null object");
     return;
   }
+  DCHECK_GE(start, 0);
+  DCHECK_GE(end, string->GetLength());
   StackHandleScope<1> hs(self);
   Handle<mirror::CharArray> h_char_array(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset + 3)->AsCharArray()));
+  DCHECK_LE(index, h_char_array->GetLength());
+  DCHECK_LE(end - start, h_char_array->GetLength() - index);
   string->GetChars(start, end, h_char_array, index);
 }
 
@@ -785,6 +789,20 @@
   result->SetC(string->CharAt(index));
 }
 
+// This allows setting chars from the new style of String objects during compilation.
+static void UnstartedStringSetCharAt(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  jint index = shadow_frame->GetVReg(arg_offset + 1);
+  jchar c = shadow_frame->GetVReg(arg_offset + 2);
+  mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString();
+  if (string == nullptr) {
+    AbortTransactionOrFail(self, "String.setCharAt with null object");
+    return;
+  }
+  string->SetCharAt(index, c);
+}
+
 // This allows creating the new style of String objects during compilation.
 static void UnstartedStringFactoryNewStringFromChars(
     Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
@@ -800,19 +818,51 @@
 }
 
 // This allows creating the new style of String objects during compilation.
+static void UnstartedStringFactoryNewStringFromString(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::String* to_copy = shadow_frame->GetVRegReference(arg_offset)->AsString();
+  if (to_copy == nullptr) {
+    AbortTransactionOrFail(self, "StringFactory.newStringFromString with null object");
+    return;
+  }
+  StackHandleScope<1> hs(self);
+  Handle<mirror::String> h_string(hs.NewHandle(to_copy));
+  Runtime* runtime = Runtime::Current();
+  gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
+  result->SetL(mirror::String::AllocFromString<true>(self, h_string->GetLength(), h_string, 0,
+                                                     allocator));
+}
+
+// This allows creating the new style of String objects during compilation.
 static void UnstartedStringFastSubstring(
     Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   jint start = shadow_frame->GetVReg(arg_offset + 1);
   jint length = shadow_frame->GetVReg(arg_offset + 2);
+  DCHECK_GE(start, 0);
   DCHECK_GE(length, 0);
   StackHandleScope<1> hs(self);
   Handle<mirror::String> h_string(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset)->AsString()));
+  DCHECK_LE(start, h_string->GetLength());
+  DCHECK_LE(start + length, h_string->GetLength());
   Runtime* runtime = Runtime::Current();
   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
   result->SetL(mirror::String::AllocFromString<true>(self, length, h_string, start, allocator));
 }
 
+// This allows getting the char array for new style of String objects during compilation.
+static void UnstartedStringToCharArray(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString();
+  if (string == nullptr) {
+    AbortTransactionOrFail(self, "String.charAt with null object");
+    return;
+  }
+  result->SetL(string->ToCharArray(self));
+}
+
 static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self,
                                                   mirror::ArtMethod* method ATTRIBUTE_UNUSED,
                                                   mirror::Object* receiver ATTRIBUTE_UNUSED,
@@ -1141,10 +1191,16 @@
           &UnstartedStringGetCharsNoCheck },
       { "char java.lang.String.charAt(int)",
           &UnstartedStringCharAt },
+      { "void java.lang.String.setCharAt(int, char)",
+          &UnstartedStringSetCharAt },
       { "java.lang.String java.lang.StringFactory.newStringFromChars(int, int, char[])",
           &UnstartedStringFactoryNewStringFromChars },
+      { "java.lang.String java.lang.StringFactory.newStringFromString(java.lang.String)",
+          &UnstartedStringFactoryNewStringFromString },
       { "java.lang.String java.lang.String.fastSubstring(int, int)",
           &UnstartedStringFastSubstring },
+      { "char[] java.lang.String.toCharArray()",
+          &UnstartedStringToCharArray },
   };
 
   for (auto& def : defs) {
@@ -1228,6 +1284,8 @@
   std::string name(PrettyMethod(shadow_frame->GetMethod()));
   const auto& iter = invoke_handlers_.find(name);
   if (iter != invoke_handlers_.end()) {
+    // Clear out the result in case it's not zeroed out.
+    result->SetL(0);
     (*iter->second)(self, shadow_frame, result, arg_offset);
   } else {
     // Not special, continue with regular interpreter execution.
@@ -1241,6 +1299,8 @@
   std::string name(PrettyMethod(method));
   const auto& iter = jni_handlers_.find(name);
   if (iter != jni_handlers_.end()) {
+    // Clear out the result in case it's not zeroed out.
+    result->SetL(0);
     (*iter->second)(self, method, receiver, args, result);
   } else if (Runtime::Current()->IsActiveTransaction()) {
     AbortTransactionF(self, "Attempt to invoke native method in non-started runtime: %s",