From: Bill Buzbee Date: Wed, 4 Nov 2009 00:52:53 +0000 (-0800) Subject: Fix for inline string indexof; added regression tests X-Git-Tag: android-x86-2.2~489^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=49024493479b1ab8b5f9b44c24a3b0c33afc796c;p=android-x86%2Fdalvik.git Fix for inline string indexof; added regression tests --- diff --git a/tests/082-inline-execute/expected.txt b/tests/082-inline-execute/expected.txt new file mode 100644 index 000000000..5059fe8b6 --- /dev/null +++ b/tests/082-inline-execute/expected.txt @@ -0,0 +1,8 @@ +Length of : 0 +Length of x : 1 +Length of 01234567890123456789012345678901234567890123456789012345678901234567890123456789 : 80 +Now is the time[0] = "N" +Now is the time[1] = "o" +Now is the time[10] = " " +Now is the time[last] = "e" +Num throws 2000 diff --git a/tests/082-inline-execute/info.txt b/tests/082-inline-execute/info.txt new file mode 100644 index 000000000..ddc31fe7d --- /dev/null +++ b/tests/082-inline-execute/info.txt @@ -0,0 +1,8 @@ +This is a miscellaneous test that was imported into the new-at-the-time +runtime test framework. The test is intended to exercise basic features, +and as such cannot be build on top of junit, since failure of such basic +features might disrupt junit. + +This test covers the string inline-execute tests, and it done in a +looping manner to ensure that the tests are translated when a Jit is +active. diff --git a/tests/082-inline-execute/src/Main.java b/tests/082-inline-execute/src/Main.java new file mode 100644 index 000000000..aed334bf0 --- /dev/null +++ b/tests/082-inline-execute/src/Main.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Test for Jit's handling of string inline-execute. Should be tested + * twice - once using self-cosimulation (if available) and once without. + * The non-self-cosimulation test ensures that the answer computed the first + * time through (via the interpreter) is the same after looping enough + * to trigger translation. + */ + +import junit.framework.Assert; + +public class Main { + public static void main(String args[]) { + stringLengthTest(); + stringCharAtTest(); + stringIndexOfTest(); + } + + public static void stringLengthTest() { + String str0 = ""; + String str1 = "x"; + String str80 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; + int len0 = str0.length(); + int len1 = str1.length(); + int len80 = str80.length(); + int i; + + System.out.println("Length of " + str0 + " : " + len0); + System.out.println("Length of " + str1 + " : " + len1); + System.out.println("Length of " + str80 + " : " + len80); + + for (i = 0; i < 1000; i++) { + assert(str0.length() == len0); + assert(str1.length() == len1); + assert(str80.length() == len80); + } + } + + public static void stringCharAtTest() { + String testStr = "Now is the time"; + int under = -1; + int over = testStr.length(); + int numThrown = 0; + int numNotThrown = 0; + int at0 = testStr.charAt(0); + int at1 = testStr.charAt(1); + int at10 = testStr.charAt(10); + int atLast = testStr.charAt(testStr.length()-1); + int i; + + System.out.println(testStr + "[0] = \"" + (char)at0 + "\""); + System.out.println(testStr + "[1] = \"" + (char)at1 + "\""); + System.out.println(testStr + "[10] = \"" + (char)at10 + "\""); + System.out.println(testStr + "[last] = \"" + (char)atLast + "\""); + + for (i = 0; i < 1000; i++) { + assert(at0 == testStr.charAt(0)); + assert(at1 == testStr.charAt(1)); + assert(at10 == testStr.charAt(10)); + assert(atLast == testStr.charAt(testStr.length()-1)); + } + + for (i = 0; i < 1000; i++) { + try { + testStr.charAt(under); + numNotThrown++; + } catch (StringIndexOutOfBoundsException sioobe) { + numThrown++; + } + try { + testStr.charAt(over); + numNotThrown++; + } catch (StringIndexOutOfBoundsException sioobe) { + numThrown++; + } + } + assert(numNotThrown == 0); + System.out.println("Num throws " + numThrown); + } + + + public static void stringIndexOfTest() { + String str0 = ""; + String str3 = "abc"; + String str10 = "abcdefghij"; + String str40 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabc"; + int i; + + for (i = 0; i < 1000; i++) { + assert(str0.indexOf('a') == -1); + assert(str3.indexOf('a') == 0); + assert(str3.indexOf('b') == 1); + assert(str3.indexOf('c') == 2); + assert(str10.indexOf('j') == 9); + assert(str40.indexOf('a') == 0); + assert(str40.indexOf('b') == 38); + assert(str40.indexOf('c') == 39); + assert(str0.indexOf('a',20) == -1); + assert(str0.indexOf('a',0) == -1); + assert(str0.indexOf('a',-1) == -1); + assert(str3.indexOf('a',0) == 0); + assert(str3.indexOf('a',1) == -1); + assert(str3.indexOf('a',1234) == -1); + assert(str3.indexOf('b',0) == 1); + assert(str3.indexOf('b',1) == 1); + assert(str3.indexOf('c',2) == 2); + assert(str10.indexOf('j',5) == 9); + assert(str10.indexOf('j',9) == 9); + assert(str40.indexOf('a',10) == 10); + assert(str40.indexOf('b',40) == -1); + } + + } + + public static void stringCompareTo() { + String test = "0123456789"; + String test1 = new String("0123456789"); // different object + String test2 = new String("0123456780"); // different value + String offset = new String("xxx0123456789yyy"); + String sub = offset.substring(3, 13); + Object blah = new Object(); + int i; + + for (i = 0; i < 1000; i++) { + + Assert.assertTrue(test.equals(test)); + Assert.assertTrue(test.equals(test1)); + Assert.assertFalse(test.equals(test2)); + + Assert.assertEquals(test.compareTo(test1), 0); + Assert.assertTrue(test1.compareTo(test2) > 0); + Assert.assertTrue(test2.compareTo(test1) < 0); + + /* compare string with a nonzero offset, in left/right side */ + Assert.assertEquals(test.compareTo(sub), 0); + Assert.assertEquals(sub.compareTo(test), 0); + Assert.assertTrue(test.equals(sub)); + Assert.assertTrue(sub.equals(test)); + /* same base, one is a substring */ + Assert.assertFalse(offset.equals(sub)); + Assert.assertFalse(sub.equals(offset)); + /* wrong class */ + Assert.assertFalse(test.equals(blah)); + + /* null ptr - throw */ + try { + test.compareTo(null); + Assert.fail("didn't get expected npe"); + } catch (NullPointerException npe) { + System.out.println("Got expected npe"); + } + /* null ptr - ok */ + Assert.assertFalse(test.equals(null)); + + test = test.substring(1); + Assert.assertTrue(test.equals("123456789")); + Assert.assertFalse(test.equals(test1)); + + test = test.substring(1); + Assert.assertTrue(test.equals("23456789")); + + test = test.substring(1); + Assert.assertTrue(test.equals("3456789")); + + test = test.substring(1); + Assert.assertTrue(test.equals("456789")); + + test = test.substring(3,5); + Assert.assertTrue(test.equals("78")); + + test = "this/is/a/path"; + String[] strings = test.split("/"); + Assert.assertEquals(4, strings.length); + + Assert.assertEquals("this is a path", test.replaceAll("/", " ")); + Assert.assertEquals("this is a path", test.replace("/", " ")); + } + } +} diff --git a/tests/082-inline-execute/src/junit/framework/Assert.java b/tests/082-inline-execute/src/junit/framework/Assert.java new file mode 100644 index 000000000..364e646ff --- /dev/null +++ b/tests/082-inline-execute/src/junit/framework/Assert.java @@ -0,0 +1,291 @@ +package junit.framework; + +/** + * A set of assert methods. Messages are only displayed when an assert fails. + */ + +public class Assert { + /** + * Protect constructor since it is a static only class + */ + protected Assert() { + } + + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError with the given message. + */ + static public void assertTrue(String message, boolean condition) { + if (!condition) + fail(message); + } + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError. + */ + static public void assertTrue(boolean condition) { + assertTrue(null, condition); + } + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError with the given message. + */ + static public void assertFalse(String message, boolean condition) { + assertTrue(message, !condition); + } + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError. + */ + static public void assertFalse(boolean condition) { + assertFalse(null, condition); + } + /** + * Fails a test with the given message. + */ + static public void fail(String message) { + throw new AssertionFailedError(message); + } + /** + * Fails a test with no message. + */ + static public void fail() { + fail(null); + } + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, Object expected, Object actual) { + if (expected == null && actual == null) + return; + if (expected != null && expected.equals(actual)) + return; + failNotEquals(message, expected, actual); + } + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown. + */ + static public void assertEquals(Object expected, Object actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two Strings are equal. + */ + static public void assertEquals(String message, String expected, String actual) { + if (expected == null && actual == null) + return; + if (expected != null && expected.equals(actual)) + return; + throw new ComparisonFailure(message, expected, actual); + } + /** + * Asserts that two Strings are equal. + */ + static public void assertEquals(String expected, String actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two doubles are equal concerning a delta. If they are not + * an AssertionFailedError is thrown with the given message. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(String message, double expected, double actual, double delta) { + // handle infinity specially since subtracting to infinite values gives NaN and the + // the following test fails + if (Double.isInfinite(expected)) { + if (!(expected == actual)) + failNotEquals(message, new Double(expected), new Double(actual)); + } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false + failNotEquals(message, new Double(expected), new Double(actual)); + } + /** + * Asserts that two doubles are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(double expected, double actual, double delta) { + assertEquals(null, expected, actual, delta); + } + /** + * Asserts that two floats are equal concerning a delta. If they are not + * an AssertionFailedError is thrown with the given message. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(String message, float expected, float actual, float delta) { + // handle infinity specially since subtracting to infinite values gives NaN and the + // the following test fails + if (Float.isInfinite(expected)) { + if (!(expected == actual)) + failNotEquals(message, new Float(expected), new Float(actual)); + } else if (!(Math.abs(expected-actual) <= delta)) + failNotEquals(message, new Float(expected), new Float(actual)); + } + /** + * Asserts that two floats are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(float expected, float actual, float delta) { + assertEquals(null, expected, actual, delta); + } + /** + * Asserts that two longs are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, long expected, long actual) { + assertEquals(message, new Long(expected), new Long(actual)); + } + /** + * Asserts that two longs are equal. + */ + static public void assertEquals(long expected, long actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two booleans are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, boolean expected, boolean actual) { + assertEquals(message, new Boolean(expected), new Boolean(actual)); + } + /** + * Asserts that two booleans are equal. + */ + static public void assertEquals(boolean expected, boolean actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two bytes are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, byte expected, byte actual) { + assertEquals(message, new Byte(expected), new Byte(actual)); + } + /** + * Asserts that two bytes are equal. + */ + static public void assertEquals(byte expected, byte actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two chars are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, char expected, char actual) { + assertEquals(message, new Character(expected), new Character(actual)); + } + /** + * Asserts that two chars are equal. + */ + static public void assertEquals(char expected, char actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two shorts are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, short expected, short actual) { + assertEquals(message, new Short(expected), new Short(actual)); + } + /** + * Asserts that two shorts are equal. + */ + static public void assertEquals(short expected, short actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two ints are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, int expected, int actual) { + assertEquals(message, new Integer(expected), new Integer(actual)); + } + /** + * Asserts that two ints are equal. + */ + static public void assertEquals(int expected, int actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that an object isn't null. + */ + static public void assertNotNull(Object object) { + assertNotNull(null, object); + } + /** + * Asserts that an object isn't null. If it is + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNotNull(String message, Object object) { + assertTrue(message, object != null); + } + /** + * Asserts that an object is null. + */ + static public void assertNull(Object object) { + assertNull(null, object); + } + /** + * Asserts that an object is null. If it is not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNull(String message, Object object) { + assertTrue(message, object == null); + } + /** + * Asserts that two objects refer to the same object. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertSame(String message, Object expected, Object actual) { + if (expected == actual) + return; + failNotSame(message, expected, actual); + } + /** + * Asserts that two objects refer to the same object. If they are not + * the same an AssertionFailedError is thrown. + */ + static public void assertSame(Object expected, Object actual) { + assertSame(null, expected, actual); + } + /** + * Asserts that two objects refer to the same object. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNotSame(String message, Object expected, Object actual) { + if (expected == actual) + failSame(message); + } + /** + * Asserts that two objects refer to the same object. If they are not + * the same an AssertionFailedError is thrown. + */ + static public void assertNotSame(Object expected, Object actual) { + assertNotSame(null, expected, actual); + } + + static private void failSame(String message) { + String formatted= ""; + if (message != null) + formatted= message+" "; + fail(formatted+"expected not same"); + } + + static private void failNotSame(String message, Object expected, Object actual) { + String formatted= ""; + if (message != null) + formatted= message+" "; + fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">"); + } + + static private void failNotEquals(String message, Object expected, Object actual) { + fail(format(message, expected, actual)); + } + + static String format(String message, Object expected, Object actual) { + String formatted= ""; + if (message != null) + formatted= message+" "; + return formatted+"expected:<"+expected+"> but was:<"+actual+">"; + } +} diff --git a/tests/082-inline-execute/src/junit/framework/AssertionFailedError.java b/tests/082-inline-execute/src/junit/framework/AssertionFailedError.java new file mode 100644 index 000000000..e9cb3a385 --- /dev/null +++ b/tests/082-inline-execute/src/junit/framework/AssertionFailedError.java @@ -0,0 +1,13 @@ +package junit.framework; + +/** + * Thrown when an assertion failed. + */ +public class AssertionFailedError extends Error { + + public AssertionFailedError () { + } + public AssertionFailedError (String message) { + super (message); + } +} diff --git a/tests/082-inline-execute/src/junit/framework/ComparisonFailure.java b/tests/082-inline-execute/src/junit/framework/ComparisonFailure.java new file mode 100644 index 000000000..0cb2cee91 --- /dev/null +++ b/tests/082-inline-execute/src/junit/framework/ComparisonFailure.java @@ -0,0 +1,68 @@ +package junit.framework; + +/** + * Thrown when an assert equals for Strings failed. + * + * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com + */ +public class ComparisonFailure extends AssertionFailedError { + private String fExpected; + private String fActual; + + /** + * Constructs a comparison failure. + * @param message the identifying message or null + * @param expected the expected string value + * @param actual the actual string value + */ + public ComparisonFailure (String message, String expected, String actual) { + super (message); + fExpected= expected; + fActual= actual; + } + + /** + * Returns "..." in place of common prefix and "..." in + * place of common suffix between expected and actual. + * + * @see java.lang.Throwable#getMessage() + */ + public String getMessage() { + if (fExpected == null || fActual == null) + return Assert.format(super.getMessage(), fExpected, fActual); + + int end= Math.min(fExpected.length(), fActual.length()); + + int i= 0; + for(; i < end; i++) { + if (fExpected.charAt(i) != fActual.charAt(i)) + break; + } + int j= fExpected.length()-1; + int k= fActual.length()-1; + for (; k >= i && j >= i; k--,j--) { + if (fExpected.charAt(j) != fActual.charAt(k)) + break; + } + String actual, expected; + + // equal strings + if (j < i && k < i) { + expected= fExpected; + actual= fActual; + } else { + expected= fExpected.substring(i, j+1); + actual= fActual.substring(i, k+1); + if (i <= end && i > 0) { + expected= "..."+expected; + actual= "..."+actual; + } + + if (j < fExpected.length()-1) + expected= expected+"..."; + if (k < fActual.length()-1) + actual= actual+"..."; + } + return Assert.format(super.getMessage(), expected, actual); + } +} diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c index b37efd2e2..6f28d33df 100644 --- a/vm/compiler/codegen/arm/Codegen.c +++ b/vm/compiler/codegen/arm/Codegen.c @@ -3837,10 +3837,6 @@ static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, */ static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir) { -#if 1 - //Back out temporarily - return false; -#endif #if defined(USE_GLOBAL_STRING_DEFS) return false; #else @@ -3866,10 +3862,6 @@ static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir) static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI) { -#if 1 - //Back out temporarily - return false; -#endif #if defined(USE_GLOBAL_STRING_DEFS) return false; #else diff --git a/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S index 685ccc68b..3eb3e87bd 100644 --- a/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S +++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S @@ -21,80 +21,93 @@ /* * At this point, we have: - * value: r0 - * offset: r7 - * count: r8 + * r0: object pointer + * r1: char to match + * r2: starting offset + * r7: offset + * r8: string length */ + /* Build pointer to start of string data */ + add r0, #16 + add r0, r0, r7, lsl #1 + + /* Save a copy of starting data in r7 */ + mov r7, r0 + /* Clamp start to [0..count] */ cmp r2, #0 movlt r2, #0 cmp r2, r8 - movgt r2, r0 + movgt r2, r8 - /* Fold start & offset, and set data pointer to contents[-1] */ - add r2, r7 + /* Build pointer to start of data to compare and pre-bias */ add r0, r0, r2, lsl #1 - add r0, #16-2 @ offset to contents[-1] - add r2, r0, #2 @ remember true start of data + sub r0, #2 + + /* Compute iteration count */ + sub r8, r2 /* * At this point we have: - * r0: *next[-1] char to test - * r2: *start - * r1: char to compare - * r8: max count - * r3, r4, r7, r9, r12 available for loading string data + * r0: start of data to test + * r1: chat to compare + * r8: iteration count + * r7: original start of string + * r3, r4, r9, r10, r11, r12 available for loading string data */ - /* Unroll x 4 */ + sub r8, #4 + blt indexof_remainder - cmp r8, #4 - blt do_rest -loopback_quad: +indexof_loop4: ldrh r3, [r0, #2]! ldrh r4, [r0, #2]! - ldrh r7, [r0, #2]! - ldrh r9, [r0, #2]! + ldrh r10, [r0, #2]! + ldrh r11, [r0, #2]! cmp r3, r1 beq match_0 cmp r4, r1 beq match_1 - cmp r7, r1 + cmp r10, r1 beq match_2 - cmp r9, r1 + cmp r11, r1 beq match_3 subs r8, #4 - bgt loopback_quad + bge indexof_loop4 -do_rest: - cmp r8, #0 - beq no_match +indexof_remainder: + adds r8, #4 + beq indexof_nomatch -loopback_indexof: +indexof_loop1: ldrh r3, [r0, #2]! cmp r3, r1 beq match_3 subs r8, #1 - bne loopback_indexof + bne indexof_loop1 -no_match: +indexof_nomatch: mov r0, #-1 bx lr match_0: sub r0, #6 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_1: sub r0, #4 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_2: sub r0, #2 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_3: - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S index 9ea4b04da..cc868481b 100644 --- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S +++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S @@ -1205,81 +1205,94 @@ dvmCompiler_TEMPLATE_STRING_INDEXOF: /* * At this point, we have: - * value: r0 - * offset: r7 - * count: r8 + * r0: object pointer + * r1: char to match + * r2: starting offset + * r7: offset + * r8: string length */ + /* Build pointer to start of string data */ + add r0, #16 + add r0, r0, r7, lsl #1 + + /* Save a copy of starting data in r7 */ + mov r7, r0 + /* Clamp start to [0..count] */ cmp r2, #0 movlt r2, #0 cmp r2, r8 - movgt r2, r0 + movgt r2, r8 - /* Fold start & offset, and set data pointer to contents[-1] */ - add r2, r7 + /* Build pointer to start of data to compare and pre-bias */ add r0, r0, r2, lsl #1 - add r0, #16-2 @ offset to contents[-1] - add r2, r0, #2 @ remember true start of data + sub r0, #2 + + /* Compute iteration count */ + sub r8, r2 /* * At this point we have: - * r0: *next[-1] char to test - * r2: *start - * r1: char to compare - * r8: max count - * r3, r4, r7, r9, r12 available for loading string data + * r0: start of data to test + * r1: chat to compare + * r8: iteration count + * r7: original start of string + * r3, r4, r9, r10, r11, r12 available for loading string data */ - /* Unroll x 4 */ + sub r8, #4 + blt indexof_remainder - cmp r8, #4 - blt do_rest -loopback_quad: +indexof_loop4: ldrh r3, [r0, #2]! ldrh r4, [r0, #2]! - ldrh r7, [r0, #2]! - ldrh r9, [r0, #2]! + ldrh r10, [r0, #2]! + ldrh r11, [r0, #2]! cmp r3, r1 beq match_0 cmp r4, r1 beq match_1 - cmp r7, r1 + cmp r10, r1 beq match_2 - cmp r9, r1 + cmp r11, r1 beq match_3 subs r8, #4 - bgt loopback_quad + bge indexof_loop4 -do_rest: - cmp r8, #0 - beq no_match +indexof_remainder: + adds r8, #4 + beq indexof_nomatch -loopback_indexof: +indexof_loop1: ldrh r3, [r0, #2]! cmp r3, r1 beq match_3 subs r8, #1 - bne loopback_indexof + bne indexof_loop1 -no_match: +indexof_nomatch: mov r0, #-1 bx lr match_0: sub r0, #6 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_1: sub r0, #4 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_2: sub r0, #2 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_3: - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S index 75388fb21..fbfaf8682 100644 --- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S +++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S @@ -930,81 +930,94 @@ dvmCompiler_TEMPLATE_STRING_INDEXOF: /* * At this point, we have: - * value: r0 - * offset: r7 - * count: r8 + * r0: object pointer + * r1: char to match + * r2: starting offset + * r7: offset + * r8: string length */ + /* Build pointer to start of string data */ + add r0, #16 + add r0, r0, r7, lsl #1 + + /* Save a copy of starting data in r7 */ + mov r7, r0 + /* Clamp start to [0..count] */ cmp r2, #0 movlt r2, #0 cmp r2, r8 - movgt r2, r0 + movgt r2, r8 - /* Fold start & offset, and set data pointer to contents[-1] */ - add r2, r7 + /* Build pointer to start of data to compare and pre-bias */ add r0, r0, r2, lsl #1 - add r0, #16-2 @ offset to contents[-1] - add r2, r0, #2 @ remember true start of data + sub r0, #2 + + /* Compute iteration count */ + sub r8, r2 /* * At this point we have: - * r0: *next[-1] char to test - * r2: *start - * r1: char to compare - * r8: max count - * r3, r4, r7, r9, r12 available for loading string data + * r0: start of data to test + * r1: chat to compare + * r8: iteration count + * r7: original start of string + * r3, r4, r9, r10, r11, r12 available for loading string data */ - /* Unroll x 4 */ + sub r8, #4 + blt indexof_remainder - cmp r8, #4 - blt do_rest -loopback_quad: +indexof_loop4: ldrh r3, [r0, #2]! ldrh r4, [r0, #2]! - ldrh r7, [r0, #2]! - ldrh r9, [r0, #2]! + ldrh r10, [r0, #2]! + ldrh r11, [r0, #2]! cmp r3, r1 beq match_0 cmp r4, r1 beq match_1 - cmp r7, r1 + cmp r10, r1 beq match_2 - cmp r9, r1 + cmp r11, r1 beq match_3 subs r8, #4 - bgt loopback_quad + bge indexof_loop4 -do_rest: - cmp r8, #0 - beq no_match +indexof_remainder: + adds r8, #4 + beq indexof_nomatch -loopback_indexof: +indexof_loop1: ldrh r3, [r0, #2]! cmp r3, r1 beq match_3 subs r8, #1 - bne loopback_indexof + bne indexof_loop1 -no_match: +indexof_nomatch: mov r0, #-1 bx lr match_0: sub r0, #6 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_1: sub r0, #4 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_2: sub r0, #2 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_3: - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S index c59b9b0c8..4d479da2e 100644 --- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S +++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S @@ -1205,81 +1205,94 @@ dvmCompiler_TEMPLATE_STRING_INDEXOF: /* * At this point, we have: - * value: r0 - * offset: r7 - * count: r8 + * r0: object pointer + * r1: char to match + * r2: starting offset + * r7: offset + * r8: string length */ + /* Build pointer to start of string data */ + add r0, #16 + add r0, r0, r7, lsl #1 + + /* Save a copy of starting data in r7 */ + mov r7, r0 + /* Clamp start to [0..count] */ cmp r2, #0 movlt r2, #0 cmp r2, r8 - movgt r2, r0 + movgt r2, r8 - /* Fold start & offset, and set data pointer to contents[-1] */ - add r2, r7 + /* Build pointer to start of data to compare and pre-bias */ add r0, r0, r2, lsl #1 - add r0, #16-2 @ offset to contents[-1] - add r2, r0, #2 @ remember true start of data + sub r0, #2 + + /* Compute iteration count */ + sub r8, r2 /* * At this point we have: - * r0: *next[-1] char to test - * r2: *start - * r1: char to compare - * r8: max count - * r3, r4, r7, r9, r12 available for loading string data + * r0: start of data to test + * r1: chat to compare + * r8: iteration count + * r7: original start of string + * r3, r4, r9, r10, r11, r12 available for loading string data */ - /* Unroll x 4 */ + sub r8, #4 + blt indexof_remainder - cmp r8, #4 - blt do_rest -loopback_quad: +indexof_loop4: ldrh r3, [r0, #2]! ldrh r4, [r0, #2]! - ldrh r7, [r0, #2]! - ldrh r9, [r0, #2]! + ldrh r10, [r0, #2]! + ldrh r11, [r0, #2]! cmp r3, r1 beq match_0 cmp r4, r1 beq match_1 - cmp r7, r1 + cmp r10, r1 beq match_2 - cmp r9, r1 + cmp r11, r1 beq match_3 subs r8, #4 - bgt loopback_quad + bge indexof_loop4 -do_rest: - cmp r8, #0 - beq no_match +indexof_remainder: + adds r8, #4 + beq indexof_nomatch -loopback_indexof: +indexof_loop1: ldrh r3, [r0, #2]! cmp r3, r1 beq match_3 subs r8, #1 - bne loopback_indexof + bne indexof_loop1 -no_match: +indexof_nomatch: mov r0, #-1 bx lr match_0: sub r0, #6 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_1: sub r0, #4 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_2: sub r0, #2 - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr match_3: - sub r0, r2 + sub r0, r7 + asr r0, r0, #1 bx lr