Intercept JNI invocation of String.<init> methods.

libmono uses JNI AllocObject and CallNonvirtualVoidMethod to create and
initialize a string instead of using the recommended NewObject. This
change adds an intercept to change the String.<init> call to a
StringFactory call instead. Then, it uses the object id of the original
string object referrer and maps it to the result of the StringFactory.

Bug: 21288130

(cherry picked from commit 15e9ad1d028d7f12cb598b075453173532a00d91)

Change-Id: I3421c43722c07397da4a398c2ca9110e1d40bcfa
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 852ba49..0eb7f2b 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3974,7 +3974,8 @@
 
   CHECK_EQ(sizeof(jvalue), sizeof(uint64_t));
 
-  JValue result = InvokeWithJValues(soa, pReq->receiver.Read(), soa.EncodeMethod(m.Get()),
+  ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(pReq->receiver.Read()));
+  JValue result = InvokeWithJValues(soa, ref.get(), soa.EncodeMethod(m.Get()),
                                     reinterpret_cast<jvalue*>(pReq->arg_values));
 
   pReq->result_tag = BasicTagFromDescriptor(m.Get()->GetShorty());
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 639be51..39d850f 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -82,6 +82,15 @@
   return obj;
 }
 
+inline void IndirectReferenceTable::Update(IndirectRef iref, mirror::Object* obj) {
+  if (!GetChecked(iref)) {
+    LOG(WARNING) << "IndirectReferenceTable Update failed to find reference " << iref;
+    return;
+  }
+  uint32_t idx = ExtractIndex(iref);
+  table_[idx].SetReference(obj);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_INDIRECT_REFERENCE_TABLE_INL_H_
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index a0e53af..dea5dfd 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -213,6 +213,10 @@
   uint32_t GetSerial() const {
     return serial_;
   }
+  void SetReference(mirror::Object* obj) {
+    DCHECK_LT(serial_, kIRTPrevCount);
+    references_[serial_] = GcRoot<mirror::Object>(obj);
+  }
 
  private:
   uint32_t serial_;
@@ -294,6 +298,13 @@
   }
 
   /*
+   * Update an existing entry.
+   *
+   * Updates an existing indirect reference to point to a new object.
+   */
+  void Update(IndirectRef iref, mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  /*
    * Remove an existing entry.
    *
    * If the entry is not between the current top index and the bottom index
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index ca45f76..f435467 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -706,8 +706,7 @@
     CHECK_NON_NULL_ARGUMENT(obj);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                                      args));
+    JValue result(InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
@@ -733,8 +732,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetZ();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetZ();
   }
 
   static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -759,8 +757,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetB();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetB();
   }
 
   static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -785,8 +782,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetC();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetC();
   }
 
   static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -811,8 +807,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetD();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetD();
   }
 
   static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -837,8 +832,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetF();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetF();
   }
 
   static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -863,8 +857,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetI();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetI();
   }
 
   static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -889,8 +882,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetJ();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetJ();
   }
 
   static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -915,8 +907,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
-                                               args).GetS();
+    return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetS();
   }
 
   static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -940,7 +931,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
-    InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
+    InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args);
   }
 
   static jobject CallNonvirtualObjectMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -969,7 +960,7 @@
     CHECK_NON_NULL_ARGUMENT(obj);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args));
+    JValue result(InvokeWithJValues(soa, obj, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
@@ -998,7 +989,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetZ();
+    return InvokeWithJValues(soa, obj, mid, args).GetZ();
   }
 
   static jbyte CallNonvirtualByteMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1025,7 +1016,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetB();
+    return InvokeWithJValues(soa, obj, mid, args).GetB();
   }
 
   static jchar CallNonvirtualCharMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1052,7 +1043,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetC();
+    return InvokeWithJValues(soa, obj, mid, args).GetC();
   }
 
   static jshort CallNonvirtualShortMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1079,7 +1070,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetS();
+    return InvokeWithJValues(soa, obj, mid, args).GetS();
   }
 
   static jint CallNonvirtualIntMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1106,7 +1097,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetI();
+    return InvokeWithJValues(soa, obj, mid, args).GetI();
   }
 
   static jlong CallNonvirtualLongMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1133,7 +1124,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetJ();
+    return InvokeWithJValues(soa, obj, mid, args).GetJ();
   }
 
   static jfloat CallNonvirtualFloatMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1160,7 +1151,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetF();
+    return InvokeWithJValues(soa, obj, mid, args).GetF();
   }
 
   static jdouble CallNonvirtualDoubleMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1187,7 +1178,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetD();
+    return InvokeWithJValues(soa, obj, mid, args).GetD();
   }
 
   static void CallNonvirtualVoidMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1213,7 +1204,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
-    InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
+    InvokeWithJValues(soa, obj, mid, args);
   }
 
   static jfieldID GetFieldID(JNIEnv* env, jclass java_class, const char* name, const char* sig) {
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 3d14a4e..581ef0e 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -858,8 +858,7 @@
   jstring s = reinterpret_cast<jstring>(env_->AllocObject(c));
   ASSERT_NE(s, nullptr);
   env_->CallVoidMethod(s, mid2);
-  // With the string change, this should now throw an UnsupportedOperationException.
-  ASSERT_EQ(JNI_TRUE, env_->ExceptionCheck());
+  ASSERT_EQ(JNI_FALSE, env_->ExceptionCheck());
   env_->ExceptionClear();
 
   mid = env_->GetMethodID(c, "length", "()I");
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 49e1b8e..d321d27 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -21,6 +21,7 @@
 #include "common_throws.h"
 #include "dex_file-inl.h"
 #include "entrypoints/entrypoint_utils.h"
+#include "indirect_reference_table-inl.h"
 #include "jni_internal.h"
 #include "mirror/abstract_method.h"
 #include "mirror/art_method-inl.h"
@@ -449,6 +450,11 @@
   }
 
   mirror::ArtMethod* method = soa.DecodeMethod(mid);
+  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  if (is_string_init) {
+    // Replace calls to String.<init> with equivalent StringFactory call.
+    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+  }
   mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
   uint32_t shorty_len = 0;
   const char* shorty = method->GetShorty(&shorty_len);
@@ -456,11 +462,15 @@
   ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
   InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
+  if (is_string_init) {
+    // For string init, remap original receiver to StringFactory result.
+    soa.Self()->GetJniEnv()->locals.Update(obj, result.GetL());
+  }
   return result;
 }
 
-JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver,
-                         jmethodID mid, jvalue* args) {
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+                         jvalue* args) {
   // We want to make sure that the stack is not within a small distance from the
   // protected region in case we are calling into a leaf function whose stack
   // check has been elided.
@@ -470,17 +480,27 @@
   }
 
   mirror::ArtMethod* method = soa.DecodeMethod(mid);
+  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  if (is_string_init) {
+    // Replace calls to String.<init> with equivalent StringFactory call.
+    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+  }
+  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
   uint32_t shorty_len = 0;
   const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
   ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromJValues(soa, receiver, args);
   InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
+  if (is_string_init) {
+    // For string init, remap original receiver to StringFactory result.
+    soa.Self()->GetJniEnv()->locals.Update(obj, result.GetL());
+  }
   return result;
 }
 
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           mirror::Object* receiver, jmethodID mid, jvalue* args) {
+                                           jobject obj, jmethodID mid, jvalue* args) {
   // We want to make sure that the stack is not within a small distance from the
   // protected region in case we are calling into a leaf function whose stack
   // check has been elided.
@@ -489,13 +509,24 @@
     return JValue();
   }
 
+  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
   mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  if (is_string_init) {
+    // Replace calls to String.<init> with equivalent StringFactory call.
+    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+    receiver = nullptr;
+  }
   uint32_t shorty_len = 0;
   const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
   ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromJValues(soa, receiver, args);
   InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
+  if (is_string_init) {
+    // For string init, remap original receiver to StringFactory result.
+    soa.Self()->GetJniEnv()->locals.Update(obj, result.GetL());
+  }
   return result;
 }
 
@@ -511,12 +542,22 @@
 
   mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
   mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  if (is_string_init) {
+    // Replace calls to String.<init> with equivalent StringFactory call.
+    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+    receiver = nullptr;
+  }
   uint32_t shorty_len = 0;
   const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
   ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
   InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
+  if (is_string_init) {
+    // For string init, remap original receiver to StringFactory result.
+    soa.Self()->GetJniEnv()->locals.Update(obj, result.GetL());
+  }
   return result;
 }
 
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 37f8a6a..6b5ffc7 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -49,12 +49,12 @@
                          va_list args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver,
-                         jmethodID mid, jvalue* args)
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+                         jvalue* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           mirror::Object* receiver, jmethodID mid, jvalue* args)
+                                           jobject obj, jmethodID mid, jvalue* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index a62bc5e..36e444a 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -133,7 +133,8 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "nop", "()V");
-    InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), nullptr);
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
+    InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), nullptr);
   }
 
   void InvokeIdentityByteMethod(bool is_static) {
@@ -141,22 +142,23 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "identity", "(B)B");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[1];
 
     args[0].b = 0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(0, result.GetB());
 
     args[0].b = -1;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-1, result.GetB());
 
     args[0].b = SCHAR_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(SCHAR_MAX, result.GetB());
 
     args[0].b = (SCHAR_MIN << 24) >> 24;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(SCHAR_MIN, result.GetB());
   }
 
@@ -165,22 +167,23 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "identity", "(I)I");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[1];
 
     args[0].i = 0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(0, result.GetI());
 
     args[0].i = -1;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-1, result.GetI());
 
     args[0].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(INT_MAX, result.GetI());
 
     args[0].i = INT_MIN;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(INT_MIN, result.GetI());
   }
 
@@ -189,22 +192,23 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "identity", "(D)D");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[1];
 
     args[0].d = 0.0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = -1.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(-1.0, result.GetD());
 
     args[0].d = DBL_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(DBL_MAX, result.GetD());
 
     args[0].d = DBL_MIN;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(DBL_MIN, result.GetD());
   }
 
@@ -213,26 +217,27 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(II)I");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[2];
 
     args[0].i = 1;
     args[1].i = 2;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(3, result.GetI());
 
     args[0].i = -2;
     args[1].i = 5;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(3, result.GetI());
 
     args[0].i = INT_MAX;
     args[1].i = INT_MIN;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-1, result.GetI());
 
     args[0].i = INT_MAX;
     args[1].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-2, result.GetI());
   }
 
@@ -241,36 +246,37 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(III)I");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[3];
 
     args[0].i = 0;
     args[1].i = 0;
     args[2].i = 0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(0, result.GetI());
 
     args[0].i = 1;
     args[1].i = 2;
     args[2].i = 3;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(6, result.GetI());
 
     args[0].i = -1;
     args[1].i = 2;
     args[2].i = -3;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-2, result.GetI());
 
     args[0].i = INT_MAX;
     args[1].i = INT_MIN;
     args[2].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(2147483646, result.GetI());
 
     args[0].i = INT_MAX;
     args[1].i = INT_MAX;
     args[2].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(2147483645, result.GetI());
   }
 
@@ -279,41 +285,42 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(IIII)I");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[4];
 
     args[0].i = 0;
     args[1].i = 0;
     args[2].i = 0;
     args[3].i = 0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(0, result.GetI());
 
     args[0].i = 1;
     args[1].i = 2;
     args[2].i = 3;
     args[3].i = 4;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(10, result.GetI());
 
     args[0].i = -1;
     args[1].i = 2;
     args[2].i = -3;
     args[3].i = 4;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(2, result.GetI());
 
     args[0].i = INT_MAX;
     args[1].i = INT_MIN;
     args[2].i = INT_MAX;
     args[3].i = INT_MIN;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-2, result.GetI());
 
     args[0].i = INT_MAX;
     args[1].i = INT_MAX;
     args[2].i = INT_MAX;
     args[3].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-4, result.GetI());
   }
 
@@ -322,6 +329,7 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(IIIII)I");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[5];
 
     args[0].i = 0;
@@ -329,7 +337,7 @@
     args[2].i = 0;
     args[3].i = 0;
     args[4].i = 0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(0, result.GetI());
 
     args[0].i = 1;
@@ -337,7 +345,7 @@
     args[2].i = 3;
     args[3].i = 4;
     args[4].i = 5;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(15, result.GetI());
 
     args[0].i = -1;
@@ -345,7 +353,7 @@
     args[2].i = -3;
     args[3].i = 4;
     args[4].i = -5;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(-3, result.GetI());
 
     args[0].i = INT_MAX;
@@ -353,7 +361,7 @@
     args[2].i = INT_MAX;
     args[3].i = INT_MIN;
     args[4].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(2147483645, result.GetI());
 
     args[0].i = INT_MAX;
@@ -361,7 +369,7 @@
     args[2].i = INT_MAX;
     args[3].i = INT_MAX;
     args[4].i = INT_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_EQ(2147483643, result.GetI());
   }
 
@@ -370,31 +378,32 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DD)D");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[2];
 
     args[0].d = 0.0;
     args[1].d = 0.0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(3.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(-1.0, result.GetD());
 
     args[0].d = DBL_MAX;
     args[1].d = DBL_MIN;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(1.7976931348623157e308, result.GetD());
 
     args[0].d = DBL_MAX;
     args[1].d = DBL_MAX;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(INFINITY, result.GetD());
   }
 
@@ -403,24 +412,25 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDD)D");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[3];
 
     args[0].d = 0.0;
     args[1].d = 0.0;
     args[2].d = 0.0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
     args[2].d = 3.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(6.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
     args[2].d = 3.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(2.0, result.GetD());
   }
 
@@ -429,27 +439,28 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDDD)D");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[4];
 
     args[0].d = 0.0;
     args[1].d = 0.0;
     args[2].d = 0.0;
     args[3].d = 0.0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
     args[2].d = 3.0;
     args[3].d = 4.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(10.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
     args[2].d = 3.0;
     args[3].d = -4.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(-2.0, result.GetD());
   }
 
@@ -458,6 +469,7 @@
     mirror::ArtMethod* method;
     mirror::Object* receiver;
     ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDDDD)D");
+    ScopedLocalRef<jobject> receiver_ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
     jvalue args[5];
 
     args[0].d = 0.0;
@@ -465,7 +477,7 @@
     args[2].d = 0.0;
     args[3].d = 0.0;
     args[4].d = 0.0;
-    JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    JValue result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
@@ -473,7 +485,7 @@
     args[2].d = 3.0;
     args[3].d = 4.0;
     args[4].d = 5.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(15.0, result.GetD());
 
     args[0].d = 1.0;
@@ -481,7 +493,7 @@
     args[2].d = 3.0;
     args[3].d = -4.0;
     args[4].d = 5.0;
-    result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+    result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
     EXPECT_DOUBLE_EQ(3.0, result.GetD());
   }
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 148bb6d..2145c9c 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -216,7 +216,8 @@
     // Invoke the 'run' method of our java.lang.Thread.
     mirror::Object* receiver = self->tlsPtr_.opeer;
     jmethodID mid = WellKnownClasses::java_lang_Thread_run;
-    InvokeVirtualOrInterfaceWithJValues(soa, receiver, mid, nullptr);
+    ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
+    InvokeVirtualOrInterfaceWithJValues(soa, ref.get(), mid, nullptr);
   }
   // Detach and delete self.
   Runtime::Current()->GetThreadList()->Unregister(self);
@@ -1886,7 +1887,8 @@
       jv_args[i].l = cause.get();
       ++i;
     }
-    InvokeWithJValues(soa, exception.Get(), soa.EncodeMethod(exception_init_method), jv_args);
+    ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(exception.Get()));
+    InvokeWithJValues(soa, ref.get(), soa.EncodeMethod(exception_init_method), jv_args);
     if (LIKELY(!IsExceptionPending())) {
       SetException(exception.Get());
     }
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index cdc5461..1ec0cf2 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -550,21 +550,58 @@
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jclass) {
-  const char* string = "Test";
-  int length = strlen(string);
   jclass c = env->FindClass("java/lang/String");
-  assert(c != NULL);
-  jmethodID method = env->GetMethodID(c, "<init>", "([B)V");
-  assert(method != NULL);
+  assert(c != nullptr);
+
+  jmethodID mid1 = env->GetMethodID(c, "<init>", "()V");
+  assert(mid1 != nullptr);
   assert(!env->ExceptionCheck());
-  jbyteArray array = env->NewByteArray(length);
-  env->SetByteArrayRegion(array, 0, length, reinterpret_cast<const jbyte*>(string));
-  jobject o = env->NewObject(c, method, array);
-  assert(o != NULL);
-  jstring s = reinterpret_cast<jstring>(o);
-  assert(env->GetStringLength(s) == length);
-  assert(env->GetStringUTFLength(s) == length);
+  jmethodID mid2 = env->GetMethodID(c, "<init>", "([B)V");
+  assert(mid2 != nullptr);
+  assert(!env->ExceptionCheck());
+  jmethodID mid3 = env->GetMethodID(c, "<init>", "([C)V");
+  assert(mid3 != nullptr);
+  assert(!env->ExceptionCheck());
+  jmethodID mid4 = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V");
+  assert(mid4 != nullptr);
+  assert(!env->ExceptionCheck());
+
+  const char* test_array = "Test";
+  int byte_array_length = strlen(test_array);
+  jbyteArray byte_array = env->NewByteArray(byte_array_length);
+  env->SetByteArrayRegion(byte_array, 0, byte_array_length, reinterpret_cast<const jbyte*>(test_array));
+
+  // Test NewObject
+  jstring s = reinterpret_cast<jstring>(env->NewObject(c, mid2, byte_array));
+  assert(s != nullptr);
+  assert(env->GetStringLength(s) == byte_array_length);
+  assert(env->GetStringUTFLength(s) == byte_array_length);
   const char* chars = env->GetStringUTFChars(s, nullptr);
-  assert(strcmp(string, chars) == 0);
+  assert(strcmp(test_array, chars) == 0);
   env->ReleaseStringUTFChars(s, chars);
+
+  // Test AllocObject and Call(Nonvirtual)VoidMethod
+  jstring s1 = reinterpret_cast<jstring>(env->AllocObject(c));
+  assert(s1 != nullptr);
+  jstring s2 = reinterpret_cast<jstring>(env->AllocObject(c));
+  assert(s2 != nullptr);
+  jstring s3 = reinterpret_cast<jstring>(env->AllocObject(c));
+  assert(s3 != nullptr);
+  jstring s4 = reinterpret_cast<jstring>(env->AllocObject(c));
+  assert(s4 != nullptr);
+
+  jcharArray char_array = env->NewCharArray(5);
+  jstring string_arg = env->NewStringUTF("helloworld");
+
+  // With Var Args
+  env->CallVoidMethod(s1, mid1);
+  env->CallNonvirtualVoidMethod(s2, c, mid2, byte_array);
+
+  // With JValues
+  jvalue args3[1];
+  args3[0].l = char_array;
+  jvalue args4[1];
+  args4[0].l = string_arg;
+  env->CallVoidMethodA(s3, mid3, args3);
+  env->CallNonvirtualVoidMethodA(s4, c, mid4, args4);
 }
diff --git a/test/020-string/src/Main.java b/test/020-string/src/Main.java
index bb8ce1f..b876e6a 100644
--- a/test/020-string/src/Main.java
+++ b/test/020-string/src/Main.java
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+import java.nio.charset.Charset;
+import java.io.UnsupportedEncodingException;
+
 /**
  * Simple string test.
  */
@@ -21,6 +24,7 @@
     public static void main(String args[]) {
         basicTest();
         indexTest();
+        constructorTest();
     }
 
     public static void basicTest() {
@@ -81,4 +85,36 @@
             subStr.indexOf('&') + ":" +
             baseStr.indexOf(0x12341234));
     }
+
+    public static void constructorTest() {
+        byte[] byteArray = "byteArray".getBytes();
+        char[] charArray = new char[] { 'c', 'h', 'a', 'r', 'A', 'r', 'r', 'a', 'y' };
+        String charsetName = "US-ASCII";
+        Charset charset = Charset.forName("UTF-8");
+        String string = "string";
+        StringBuffer stringBuffer = new StringBuffer("stringBuffer");
+        int [] codePoints = new int[] { 65, 66, 67, 68, 69 };
+        StringBuilder stringBuilder = new StringBuilder("stringBuilder");
+
+        String s1 = new String();
+        String s2 = new String(byteArray);
+        String s3 = new String(byteArray, 1);
+        String s4 = new String(byteArray, 0, 4);
+        String s5 = new String(byteArray, 2, 4, 5);
+
+        try {
+            String s6 = new String(byteArray, 2, 4, charsetName);
+            String s7 = new String(byteArray, charsetName);
+        } catch (UnsupportedEncodingException e) {
+            System.out.println("Got unexpected UnsupportedEncodingException");
+        }
+        String s8 = new String(byteArray, 3, 3, charset);
+        String s9 = new String(byteArray, charset);
+        String s10 = new String(charArray);
+        String s11 = new String(charArray, 0, 4);
+        String s12 = new String(string);
+        String s13 = new String(stringBuffer);
+        String s14 = new String(codePoints, 1, 3);
+        String s15 = new String(stringBuilder);
+    }
 }