Implemented inline of String indexOf and compareTo on x86.

Change-Id: Ia141d4900e9ab9dd563e718af0d10dcd445794cb
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index f1653aa..d75234e 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -813,7 +813,7 @@
 bool genInlinedIndexOf(CompilationUnit* cUnit, CallInfo* info,
                        bool zeroBased)
 {
-#if defined(TARGET_ARM)
+#if defined(TARGET_ARM) || defined(TARGET_X86)
   oatClobberCalleeSave(cUnit);
   oatLockCallTemps(cUnit);  // Using fixed registers
   int regPtr = rARG0;
@@ -830,13 +830,19 @@
   } else {
     loadValueDirectFixed(cUnit, rlStart, regStart);
   }
+#if !defined(TARGET_X86)
   int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pIndexOf));
+#endif
   genNullCheck(cUnit, rlObj.sRegLow, regPtr, info->optFlags);
   LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info);
   oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads,
               (intptr_t)launchPad);
   opCmpImmBranch(cUnit, kCondGt, regChar, 0xFFFF, launchPad);
+#if !defined(TARGET_X86)
   opReg(cUnit, kOpBlx, rTgt);
+#else
+  opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
+#endif
   LIR* resumeTgt = newLIR0(cUnit, kPseudoTargetLabel);
   launchPad->operands[2] = (uintptr_t)resumeTgt;
   // Record that we've already inlined & null checked
@@ -853,7 +859,7 @@
 /* Fast string.compareTo(Ljava/lang/string;)I. */
 bool genInlinedStringCompareTo(CompilationUnit* cUnit, CallInfo* info)
 {
-#if defined(TARGET_ARM)
+#if defined(TARGET_ARM) || defined(TARGET_X86)
   oatClobberCalleeSave(cUnit);
   oatLockCallTemps(cUnit);  // Using fixed registers
   int regThis = rARG0;
@@ -863,14 +869,20 @@
   RegLocation rlCmp = info->args[1];
   loadValueDirectFixed(cUnit, rlThis, regThis);
   loadValueDirectFixed(cUnit, rlCmp, regCmp);
+#if !defined(TARGET_X86)
   int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pStringCompareTo));
+#endif
   genNullCheck(cUnit, rlThis.sRegLow, regThis, info->optFlags);
   //TUNING: check if rlCmp.sRegLow is already null checked
   LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info);
   oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads,
                         (intptr_t)launchPad);
   opCmpImmBranch(cUnit, kCondEq, regCmp, 0, launchPad);
+#if !defined(TARGET_X86)
   opReg(cUnit, kOpBlx, rTgt);
+#else
+  opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
+#endif
   launchPad->operands[2] = 0;  // No return possible
   // Record that we've already inlined & null checked
   info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 638a7c3..09b26b9 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -856,7 +856,7 @@
      *
      * On entry:
      *    r0:   string object (known non-null)
-     *    r1:   char to match
+     *    r1:   char to match (known <= 0xFFFF)
      *    r2:   Starting offset in string data
      */
 
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 37a023a..d8098b6 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -732,6 +732,100 @@
     addl LITERAL(44), %esp        // pop arguments
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
+    /*
+     * String's indexOf.
+     *
+     * On entry:
+     *    eax:   string object (known non-null)
+     *    ecx:   char to match (known <= 0xFFFF)
+     *    edx:   Starting offset in string data
+     */
+DEFINE_FUNCTION art_indexof
+    pushl %edi                    // push callee save reg
+    mov STRING_COUNT_OFFSET(%eax), %ebx
+    mov STRING_VALUE_OFFSET(%eax), %edi
+    mov STRING_OFFSET_OFFSET(%eax), %eax
+    testl %edx, %edx              // check if start < 0
+    jl   clamp_min
+clamp_done:
+    cmpl %ebx, %edx               // check if start >= count
+    jge  not_found
+    lea  STRING_DATA_OFFSET(%edi, %eax, 2), %edi  // build a pointer to the start of string data
+    mov  %edi, %eax               // save a copy in eax to later compute result
+    lea  (%edi, %edx, 2), %edi    // build pointer to start of data to compare
+    subl  %edx, %ebx              // compute iteration count
+    /*
+     * At this point we have:
+     *   eax: original start of string data
+     *   ecx: char to compare
+     *   ebx: length to compare
+     *   edi: start of data to test
+     */
+    mov  %eax, %edx
+    mov  %ecx, %eax               // put char to match in %eax
+    mov  %ebx, %ecx               // put length to compare in %ecx
+    repne scasw                   // find %ax, starting at [%edi], up to length %ecx
+    jne  not_found
+    subl %edx, %edi
+    sar  LITERAL(1), %edi
+    decl %edi                     // index = ((curr_ptr - orig_ptr) / 2) - 1
+    mov  %edi, %eax
+    popl %edi                     // pop callee save reg
+    ret
+    .balign 16
+not_found:
+    mov  LITERAL(-1), %eax        // return -1 (not found)
+    popl %edi                     // pop callee save reg
+    ret
+clamp_min:
+    xor  %edx, %edx               // clamp start to 0
+    jmp  clamp_done
+
+    /*
+     * String's compareTo.
+     *
+     * On entry:
+     *    eax:   this string object (known non-null)
+     *    ecx:   comp string object (known non-null)
+     */
+DEFINE_FUNCTION art_string_compareto
+    pushl %esi                    // push callee save reg
+    pushl %edi                    // push callee save reg
+    mov STRING_COUNT_OFFSET(%eax), %edx
+    mov STRING_COUNT_OFFSET(%ecx), %ebx
+    mov STRING_VALUE_OFFSET(%eax), %esi
+    mov STRING_VALUE_OFFSET(%ecx), %edi
+    mov STRING_OFFSET_OFFSET(%eax), %eax
+    mov STRING_OFFSET_OFFSET(%ecx), %ecx
+    /* Build pointers to the start of string data */
+    lea  STRING_DATA_OFFSET(%esi, %eax, 2), %esi
+    lea  STRING_DATA_OFFSET(%edi, %ecx, 2), %edi
+    /* Calculate min length and count diff */
+    mov   %edx, %ecx
+    mov   %edx, %eax
+    subl  %ebx, %eax
+    cmovg %ebx, %ecx
+    /*
+     * At this point we have:
+     *   eax: value to return if first part of strings are equal
+     *   ecx: minimum among the lengths of the two strings
+     *   esi: pointer to this string data
+     *   edi: pointer to comp string data
+     */
+    repe cmpsw                    // find nonmatching chars in [%esi] and [%edi], up to length %ecx
+    jne not_equal
+    popl  %edi                    // pop callee save reg
+    popl  %esi                    // pop callee save reg
+    ret
+    .balign 16
+not_equal:
+    movzxw  -2(%esi), %eax        // get last compared char from this string
+    movzxw  -2(%edi), %ecx        // get last compared char from comp string
+    subl  %ecx, %eax              // return the difference
+    popl  %edi                    // pop callee save reg
+    popl  %esi                    // pop callee save reg
+    ret
+
 MACRO1(UNIMPLEMENTED,name)
     .globl VAR(name, 0)
     ALIGN_FUNCTION_ENTRY
@@ -741,6 +835,4 @@
 
     // TODO: implement these!
 UNIMPLEMENTED art_update_debugger
-UNIMPLEMENTED art_indexof
 UNIMPLEMENTED art_memcmp16
-UNIMPLEMENTED art_string_compareto