Inline String.IndexOf and String.CompareTo.

Change-Id: Ie012ff37f5d0e3ae48ac4c01b9e475628b11e45d
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index cd79dcb..eecace0 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -4029,6 +4029,15 @@
   if (callee_method_name == "int java.lang.String.length()") {
     return EmitInlinedStringLength(args, after_invoke);
   }
+  if (callee_method_name == "int java.lang.String.indexOf(int, int)") {
+    return EmitInlinedStringIndexOf(args, after_invoke, false /* base 0 */);
+  }
+  if (callee_method_name == "int java.lang.String.indexOf(int)") {
+    return EmitInlinedStringIndexOf(args, after_invoke, true /* base 0 */);
+  }
+  if (callee_method_name == "int java.lang.String.compareTo(java.lang.String)") {
+    return EmitInlinedStringCompareTo(args, after_invoke);
+  }
   return true;
 }
 
@@ -4041,26 +4050,23 @@
   llvm::BasicBlock* block_retry = llvm::BasicBlock::Create(*context_, "CharAtRetry", func_);
   llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "CharAtCont", func_);
 
-  // TODO: Can we safely say the String.count is ConstJObject(constant memory)? (there are so many
-  // iput to String.count in the String.<init>(...))
   llvm::Value* string_count = irb_.LoadFromObjectOffset(this_object,
                                                         String::CountOffset().Int32Value(),
                                                         irb_.getJIntTy(),
-                                                        kTBAAHeapInstance, kInt);
+                                                        kTBAAConstJObject);
   // Two's complement, so we can use only one "less than" to check "in bounds"
   llvm::Value* in_bounds = irb_.CreateICmpULT(char_index, string_count);
   irb_.CreateCondBr(in_bounds, block_cont, block_retry, kLikely);
 
   irb_.SetInsertPoint(block_cont);
-  // TODO: Can we safely say the String.offset is ConstJObject(constant memory)?
   llvm::Value* string_offset = irb_.LoadFromObjectOffset(this_object,
                                                          String::OffsetOffset().Int32Value(),
                                                          irb_.getJIntTy(),
-                                                         kTBAAHeapInstance, kInt);
+                                                         kTBAAConstJObject);
   llvm::Value* string_value = irb_.LoadFromObjectOffset(this_object,
                                                         String::ValueOffset().Int32Value(),
                                                         irb_.getJObjectTy(),
-                                                        kTBAAHeapInstance, kObject);
+                                                        kTBAAConstJObject);
 
   // index_value = string.offset + char_index
   llvm::Value* index_value = irb_.CreateAdd(string_offset, char_index);
@@ -4081,16 +4087,79 @@
   DCHECK_EQ(args.size(), 2U) <<
       "int java.lang.String.length() has 2 args: method, this";
   llvm::Value* this_object = args[1];
-  // TODO: Can we safely say the String.count is ConstJObject(constant memory)?
   llvm::Value* string_count = irb_.LoadFromObjectOffset(this_object,
                                                         String::CountOffset().Int32Value(),
                                                         irb_.getJIntTy(),
-                                                        kTBAAHeapInstance, kInt);
+                                                        kTBAAConstJObject);
   EmitStoreDalvikRetValReg(kInt, kAccurate, string_count);
   irb_.CreateBr(after_invoke);
   return false;
 }
 
+bool MethodCompiler::EmitInlinedStringIndexOf(const std::vector<llvm::Value*>& args,
+                                              llvm::BasicBlock* after_invoke,
+                                              bool zero_based) {
+  // TODO: Don't generate target specific bitcode, using intrinsic to delay to codegen.
+  if (compiler_->GetInstructionSet() == kArm || compiler_->GetInstructionSet() == kThumb2) {
+    DCHECK_EQ(args.size(), (zero_based ? 3U : 4U)) <<
+        "int java.lang.String.indexOf(int, int = 0) has 3~4 args: method, this, char, start";
+    llvm::Value* this_object = args[1];
+    llvm::Value* char_target = args[2];
+    llvm::Value* start_index = (zero_based ? irb_.getJInt(0) : args[3]);
+    llvm::BasicBlock* block_retry = llvm::BasicBlock::Create(*context_, "IndexOfRetry", func_);
+    llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "IndexOfCont", func_);
+
+    llvm::Value* slowpath = irb_.CreateICmpSGT(char_target, irb_.getJInt(0xFFFF));
+    irb_.CreateCondBr(slowpath, block_retry, block_cont, kUnlikely);
+
+    irb_.SetInsertPoint(block_cont);
+
+    llvm::Type* args_type[] = { irb_.getJObjectTy(), irb_.getJIntTy(), irb_.getJIntTy() };
+    llvm::FunctionType* func_ty = llvm::FunctionType::get(irb_.getJIntTy(), args_type, false);
+    llvm::Value* func =
+        irb_.Runtime().EmitLoadFromThreadOffset(ENTRYPOINT_OFFSET(pIndexOf),
+                                                func_ty->getPointerTo(),
+                                                kTBAAConstJObject);
+    llvm::Value* result = irb_.CreateCall3(func, this_object, char_target, start_index);
+    EmitStoreDalvikRetValReg(kInt, kAccurate, result);
+    irb_.CreateBr(after_invoke);
+
+    irb_.SetInsertPoint(block_retry);
+  }
+  return true;
+}
+
+bool MethodCompiler::EmitInlinedStringCompareTo(const std::vector<llvm::Value*>& args,
+                                                llvm::BasicBlock* after_invoke) {
+  // TODO: Don't generate target specific bitcode, using intrinsic to delay to codegen.
+  if (compiler_->GetInstructionSet() == kArm || compiler_->GetInstructionSet() == kThumb2) {
+    DCHECK_EQ(args.size(), 3U) <<
+        "int java.lang.String.compareTo(java.lang.String) has 3 args: method, this, cmpto";
+    llvm::Value* this_object = args[1];
+    llvm::Value* cmp_object = args[2];
+    llvm::BasicBlock* block_retry = llvm::BasicBlock::Create(*context_, "CompareToRetry", func_);
+    llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "CompareToCont", func_);
+
+    llvm::Value* is_null = irb_.CreateICmpEQ(cmp_object, irb_.getJNull());
+    irb_.CreateCondBr(is_null, block_retry, block_cont, kUnlikely);
+
+    irb_.SetInsertPoint(block_cont);
+
+    llvm::Type* args_type[] = { irb_.getJObjectTy(), irb_.getJObjectTy() };
+    llvm::FunctionType* func_ty = llvm::FunctionType::get(irb_.getJIntTy(), args_type, false);
+    llvm::Value* func =
+        irb_.Runtime().EmitLoadFromThreadOffset(ENTRYPOINT_OFFSET(pStringCompareTo),
+                                                func_ty->getPointerTo(),
+                                                kTBAAConstJObject);
+    llvm::Value* result = irb_.CreateCall2(func, this_object, cmp_object);
+    EmitStoreDalvikRetValReg(kInt, kAccurate, result);
+    irb_.CreateBr(after_invoke);
+
+    irb_.SetInsertPoint(block_retry);
+  }
+  return true;
+}
+
 
 bool MethodCompiler::IsInstructionDirectToReturn(uint32_t dex_pc) {
   for (int i = 0; i < 8; ++i) {  // Trace at most 8 instructions.