Minor nterp improvements.

Do not resolve primitive field types for iput*, sput*
before updating the interpreter cache.

Introduce and use `ArtMethod::IsStringConstructor(),
a convenience helper function where we  avoid a read
barrier for checking if the declaring class is the
`String` class.

Change one `CHECK_LE()` to `DCHECK_LE()`.

Test: testrunner.py --host --interpreter
Change-Id: I17b0409cee5321e0ca389f053da1f767d2913d08
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index b7c4ba9..f9a5138 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -985,8 +985,7 @@
     DCHECK_EQ(*imt_or_vtable_index, ImTable::GetImtIndex(resolved_method));
   }
 
-  *is_string_constructor =
-      resolved_method->IsConstructor() && resolved_method->GetDeclaringClass()->IsStringClass();
+  *is_string_constructor = resolved_method->IsStringConstructor();
 
   return resolved_method;
 }
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 1985b8c..277edff 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -63,9 +63,9 @@
     bool for_interface_call,
     CodeGenerator* codegen) {
   if (kIsDebugBuild) {
-    ScopedObjectAccess soa(Thread::Current());  // Required for GetDeclaringClass below.
+    ScopedObjectAccess soa(Thread::Current());  // Required for `IsStringConstructor()` below.
     DCHECK(callee != nullptr);
-    DCHECK(!(callee->IsConstructor() && callee->GetDeclaringClass()->IsStringClass()));
+    DCHECK(!callee->IsStringConstructor());
   }
 
   MethodLoadKind method_load_kind;
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 0057bf9..d105d9e 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -254,6 +254,15 @@
   return type;
 }
 
+inline bool ArtMethod::IsStringConstructor() {
+  uint32_t access_flags = GetAccessFlags();
+  DCHECK(!IsClassInitializer(access_flags));
+  return IsConstructor(access_flags) &&
+         // No read barrier needed for reading a constant reference only to read
+         // a constant string class flag. See `ReadBarrierOption`.
+         GetDeclaringClass<kWithoutReadBarrier>()->IsStringClass();
+}
+
 inline bool ArtMethod::IsOverridableByDefaultMethod() {
   // It is safe to avoid the read barrier here since the constant interface flag
   // in the `Class` object is stored before creating the `ArtMethod` and storing
diff --git a/runtime/art_method.h b/runtime/art_method.h
index f7f900f..308a070 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -584,6 +584,11 @@
     AddAccessFlags(kAccNterpInvokeFastPathFlag);
   }
 
+  // Returns whether the method is a string constructor. The method must not
+  // be a class initializer. (Class initializers are called from a different
+  // context where we do not need to check for string constructors.)
+  bool IsStringConstructor() REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Returns true if this method could be overridden by a default method.
   bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 2498319..a652d62 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -293,7 +293,7 @@
   Instruction::Code opcode = inst->Opcode();
   DCHECK(IsUint<8>(static_cast<std::underlying_type_t<Instruction::Code>>(opcode)));
   uint8_t raw_invoke_type = kOpcodeInvokeTypes[opcode];
-  CHECK_LE(raw_invoke_type, kMaxInvokeType);
+  DCHECK_LE(raw_invoke_type, kMaxInvokeType);
   InvokeType invoke_type = static_cast<InvokeType>(raw_invoke_type);
 
   // In release mode, this is just a simple load.
@@ -341,9 +341,7 @@
     }
     UpdateCache(self, dex_pc_ptr, result);
     return result;
-  } else if (resolved_method->GetDeclaringClass()->IsStringClass()
-             && !resolved_method->IsStatic()
-             && resolved_method->IsConstructor()) {
+  } else if (resolved_method->IsStringConstructor()) {
     CHECK_NE(invoke_type, kSuper);
     resolved_method = WellKnownClasses::StringInitToStringFactory(resolved_method);
     // Or the result with 1 to notify to nterp this is a string init method. We
@@ -369,14 +367,14 @@
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   uint16_t field_index = inst->VRegB_21c();
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  bool is_put = IsInstructionSPut(inst->Opcode());
+  Instruction::Code opcode = inst->Opcode();
   ArtField* resolved_field = ResolveFieldWithAccessChecks(
       self,
       class_linker,
       field_index,
       caller,
-      /* is_static */ true,
-      is_put,
+      /*is_static=*/ true,
+      /*is_put=*/ IsInstructionSPut(opcode),
       resolve_field_type);
 
   if (resolved_field == nullptr) {
@@ -399,11 +397,13 @@
     // check for it.
     return reinterpret_cast<size_t>(resolved_field) | 1;
   } else {
-    // Try to resolve the field type even if we were not requested to. Only if
-    // the field type is successfully resolved can we update the cache. If we
+    // For sput-object, try to resolve the field type even if we were not requested to.
+    // Only if the field type is successfully resolved can we update the cache. If we
     // fail to resolve the type, we clear the exception to keep interpreter
     // semantics of not throwing when null is stored.
-    if (is_put && resolve_field_type == 0 && resolved_field->ResolveType() == nullptr) {
+    if (opcode == Instruction::SPUT_OBJECT &&
+        resolve_field_type == 0 &&
+        resolved_field->ResolveType() == nullptr) {
       DCHECK(self->IsExceptionPending());
       self->ClearException();
     } else {
@@ -422,14 +422,14 @@
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   uint16_t field_index = inst->VRegC_22c();
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  bool is_put = IsInstructionIPut(inst->Opcode());
+  Instruction::Code opcode = inst->Opcode();
   ArtField* resolved_field = ResolveFieldWithAccessChecks(
       self,
       class_linker,
       field_index,
       caller,
-      /* is_static */ false,
-      is_put,
+      /*is_static=*/ false,
+      /*is_put=*/ IsInstructionIPut(opcode),
       resolve_field_type);
   if (resolved_field == nullptr) {
     DCHECK(self->IsExceptionPending());
@@ -440,11 +440,13 @@
     // of volatile.
     return -resolved_field->GetOffset().Uint32Value();
   }
-  // Try to resolve the field type even if we were not requested to. Only if
-  // the field type is successfully resolved can we update the cache. If we
+  // For iput-object, try to resolve the field type even if we were not requested to.
+  // Only if the field type is successfully resolved can we update the cache. If we
   // fail to resolve the type, we clear the exception to keep interpreter
   // semantics of not throwing when null is stored.
-  if (is_put && resolve_field_type == 0 && resolved_field->ResolveType() == nullptr) {
+  if (opcode == Instruction::IPUT_OBJECT &&
+      resolve_field_type == 0 &&
+      resolved_field->ResolveType() == nullptr) {
     DCHECK(self->IsExceptionPending());
     self->ClearException();
   } else {
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 6dad810..73ec31e 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -459,7 +459,7 @@
   } else if (handle_kind == mirror::MethodHandle::Kind::kInvokeDirect) {
     // String constructors are a special case, they are replaced with
     // StringFactory methods.
-    if (target_method->IsConstructor() && target_method->GetDeclaringClass()->IsStringClass()) {
+    if (target_method->IsStringConstructor()) {
       DCHECK(handle_type->GetRType()->IsStringClass());
       return WellKnownClasses::StringInitToStringFactory(target_method);
     }
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 66cda45..8f31e0b 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -535,7 +535,7 @@
     ThrowStackOverflowError(soa.Self());
     return JValue();
   }
-  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  bool is_string_init = method->IsStringConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
@@ -577,7 +577,7 @@
     ThrowStackOverflowError(soa.Self());
     return JValue();
   }
-  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  bool is_string_init = method->IsStringConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
@@ -620,7 +620,7 @@
   }
   ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
   ArtMethod* method = FindVirtualMethod(receiver, interface_method);
-  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  bool is_string_init = method->IsStringConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
@@ -664,7 +664,7 @@
 
   ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
   ArtMethod* method = FindVirtualMethod(receiver, interface_method);
-  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+  bool is_string_init = method->IsStringConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);