diff options
| author | Andy McFadden <fadden@android.com> | 2009-06-29 17:04:04 -0700 |
|---|---|---|
| committer | Andy McFadden <fadden@android.com> | 2009-06-30 11:22:29 -0700 |
| commit | 87cf7312247b341b54be26904e3600e98967d695 (patch) | |
| tree | 6efc33ac43398472e7e7ed0c4b36f06b8deab1e7 | |
| parent | 44d7864f79a22fe110b8e6187ac21e908f41fb1d (diff) | |
| download | android_dalvik-87cf7312247b341b54be26904e3600e98967d695.tar.gz android_dalvik-87cf7312247b341b54be26904e3600e98967d695.tar.bz2 android_dalvik-87cf7312247b341b54be26904e3600e98967d695.zip | |
Inline some java.lang.Math functions.
For a first pass, I inlined the various flavors of abs(), min()/max() on
integers, sqrt(), cos(), and sin(). These were selected based on a
static analysis of a few of our jar files.
A test of repeated sin/cos/sqrt calls on a G1-class device showed an
improvement of 28%. This would improve more on devices with VFP
support if the VM is compiled with -mfpu=vfp.
Also: clarified a warning and removed some "#if 0" stuff.
| -rw-r--r-- | dexopt/OptMain.c | 2 | ||||
| -rw-r--r-- | tests/003-omnibus-opcodes/expected.txt | 2 | ||||
| -rw-r--r-- | tests/003-omnibus-opcodes/src/FloatMath.java | 46 | ||||
| -rw-r--r-- | tests/003-omnibus-opcodes/src/IntMath.java | 21 | ||||
| -rw-r--r-- | vm/Android.mk | 2 | ||||
| -rw-r--r-- | vm/DalvikVersion.h | 2 | ||||
| -rw-r--r-- | vm/InlineNative.c | 170 | ||||
| -rw-r--r-- | vm/Misc.h | 22 |
8 files changed, 242 insertions, 25 deletions
diff --git a/dexopt/OptMain.c b/dexopt/OptMain.c index ef339cdd1..953db0b00 100644 --- a/dexopt/OptMain.c +++ b/dexopt/OptMain.c @@ -337,7 +337,7 @@ static int fromDex(int argc, char* const argv[]) */ GET_ARG(vmBuildVersion, strtol, "bad vm build"); if (vmBuildVersion != DALVIK_VM_BUILD) { - LOGE("Inconsistent build rev: %d vs %d\n", + LOGE("DexOpt: build rev does not match VM: %d vs %d\n", vmBuildVersion, DALVIK_VM_BUILD); goto bail; } diff --git a/tests/003-omnibus-opcodes/expected.txt b/tests/003-omnibus-opcodes/expected.txt index 25ed38ba8..4895dc3e0 100644 --- a/tests/003-omnibus-opcodes/expected.txt +++ b/tests/003-omnibus-opcodes/expected.txt @@ -23,6 +23,7 @@ IntMath.truncateTest IntMath.divideByZero IntMath.bigDivideOverflow IntMath.checkConsts +IntMath.jlmTests FloatMath.convTest FloatMath.floatOperTest FloatMath.doubleOperTest @@ -39,6 +40,7 @@ FloatMath.checkConvD 2: 123.45600128173828 -2.005440939E9, -8.6133032459203287E18, 123.4560012817382 FloatMath.checkConsts +FloatMath.jlmTests IntMath.testIntCompare IntMath.testLongCompare IntMath.testFloatCompare diff --git a/tests/003-omnibus-opcodes/src/FloatMath.java b/tests/003-omnibus-opcodes/src/FloatMath.java index 0c1fe1ba7..cf4869c26 100644 --- a/tests/003-omnibus-opcodes/src/FloatMath.java +++ b/tests/003-omnibus-opcodes/src/FloatMath.java @@ -262,6 +262,50 @@ public class FloatMath { assert(d > 9.9 && d < 10.1); } + /* + * Determine if two floating point numbers are approximately equal. + * + * (Assumes that floating point is generally working, so we can't use + * this for the first set of tests.) + */ + static boolean approxEqual(float a, float b, float maxDelta) { + if (a > b) + return (a - b) < maxDelta; + else + return (b - a) < maxDelta; + } + static boolean approxEqual(double a, double b, double maxDelta) { + if (a > b) + return (a - b) < maxDelta; + else + return (b - a) < maxDelta; + } + + /* + * Test some java.lang.Math functions. + * + * The method arguments are positive values. + */ + static void jlmTests(float ff, double dd) { + System.out.println("FloatMath.jlmTests"); + + assert(approxEqual(Math.abs(ff), ff, 0.001f)); + assert(approxEqual(Math.abs(-ff), ff, 0.001f)); + assert(approxEqual(Math.min(ff, -5.0f), -5.0f, 0.001f)); + assert(approxEqual(Math.max(ff, -5.0f), ff, 0.001f)); + + assert(approxEqual(Math.abs(dd), dd, 0.001)); + assert(approxEqual(Math.abs(-dd), dd, 0.001)); + assert(approxEqual(Math.min(dd, -5.0), -5.0, 0.001)); + assert(approxEqual(Math.max(dd, -5.0), dd, 0.001)); + + double sq = Math.sqrt(dd); + assert(approxEqual(sq*sq, dd, 0.001)); + + assert(approxEqual(0.5403023058681398, Math.cos(1.0), 0.00000001)); + assert(approxEqual(0.8414709848078965, Math.sin(1.0), 0.00000001)); + } + public static void run() { convTest(); @@ -287,6 +331,8 @@ public class FloatMath { unopTest(123.456f); checkConsts(); + + jlmTests(3.14159f, 123456.78987654321); } } diff --git a/tests/003-omnibus-opcodes/src/IntMath.java b/tests/003-omnibus-opcodes/src/IntMath.java index 126bec6cd..d5ac744b8 100644 --- a/tests/003-omnibus-opcodes/src/IntMath.java +++ b/tests/003-omnibus-opcodes/src/IntMath.java @@ -432,6 +432,25 @@ public class IntMath { assert(huge == 0x9922334455667788L); // const-wide } + /* + * Test some java.lang.Math functions. + * + * The method arguments are positive values. + */ + static void jlmTests(int ii, long ll) { + System.out.println("IntMath.jlmTests"); + + assert(Math.abs(ii) == ii); + assert(Math.abs(-ii) == ii); + assert(Math.min(ii, -5) == -5); + assert(Math.max(ii, -5) == ii); + + assert(Math.abs(ll) == ll); + assert(Math.abs(-ll) == ll); + assert(Math.min(ll, -5L) == -5L); + assert(Math.max(ll, -5L) == ll); + } + public static void run() { shiftTest1(); shiftTest2(); @@ -467,6 +486,8 @@ public class IntMath { checkConsts((byte) 1, (short) -256, -88888, 0x9922334455667788L); unopCheck(unopTest(38)); + + jlmTests(12345, 0x1122334455667788L); } } diff --git a/vm/Android.mk b/vm/Android.mk index 8007fd301..5b6e0ed0c 100644 --- a/vm/Android.mk +++ b/vm/Android.mk @@ -252,7 +252,7 @@ MTERP_ARCH_KNOWN := false ifeq ($(TARGET_ARCH),arm) #TARGET_ARCH_VARIANT := armv7-a - #LOCAL_CFLAGS += -march=armv7-a + #LOCAL_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp MTERP_ARCH_KNOWN := true # Select architecture-specific sources (armv4t, armv5te etc.) LOCAL_SRC_FILES += \ diff --git a/vm/DalvikVersion.h b/vm/DalvikVersion.h index ca7193900..26b52beb8 100644 --- a/vm/DalvikVersion.h +++ b/vm/DalvikVersion.h @@ -32,6 +32,6 @@ * way classes load changes, e.g. field ordering or vtable layout. Changing * this guarantees that the optimized form of the DEX file is regenerated. */ -#define DALVIK_VM_BUILD 15 +#define DALVIK_VM_BUILD 16 #endif /*_DALVIK_VERSION*/ diff --git a/vm/InlineNative.c b/vm/InlineNative.c index 49025a6f2..6364e9493 100644 --- a/vm/InlineNative.c +++ b/vm/InlineNative.c @@ -20,6 +20,8 @@ */ #include "Dalvik.h" +#include <math.h> + #ifdef HAVE__MEMCMP16 /* hand-coded assembly implementation, available on some platforms */ //#warning "trying memcmp16" @@ -388,6 +390,154 @@ static bool javaLangString_length(u4 arg0, u4 arg1, u4 arg2, u4 arg3, /* * =========================================================================== + * java.lang.Math + * =========================================================================== + */ + +/* + * public static int abs(int) + */ +static bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + s4 val = (s4) arg0; + pResult->i = (val >= 0) ? val : -val; + return true; +} + +/* + * public static long abs(long) + */ +static bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + union { + u4 arg[2]; + s8 ll; + } convert; + + convert.arg[0] = arg0; + convert.arg[1] = arg1; + s8 val = convert.ll; + pResult->j = (val >= 0) ? val : -val; + return true; +} + +/* + * public static float abs(float) + */ +static bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + union { + u4 arg; + float ff; + } convert; + + /* clear the sign bit; assumes a fairly common fp representation */ + convert.arg = arg0 & 0x7fffffff; + pResult->f = convert.ff; + return true; +} + +/* + * public static float abs(float) + */ +static bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + union { + u4 arg[2]; + s8 ll; + double dd; + } convert; + + /* clear the sign bit in the (endian-dependent) high word */ + convert.arg[0] = arg0; + convert.arg[1] = arg1; + convert.ll &= 0x7fffffffffffffffULL; + pResult->d = convert.dd; + return true; +} + +/* + * public static int min(int) + */ +static bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + pResult->i = ((s4) arg0 < (s4) arg1) ? arg0 : arg1; + return true; +} + +/* + * public static int max(int) + */ +static bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + pResult->i = ((s4) arg0 > (s4) arg1) ? arg0 : arg1; + return true; +} + +/* + * public static double sqrt(double) + * + * With ARM VFP enabled, gcc turns this into an fsqrtd instruction, followed + * by an fcmpd of the result against itself. If it doesn't match (i.e. + * it's NaN), the libm sqrt() is invoked. + */ +static bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + union { + u4 arg[2]; + double dd; + } convert; + + convert.arg[0] = arg0; + convert.arg[1] = arg1; + pResult->d = sqrt(convert.dd); + return true; +} + +/* + * public static double cos(double) + */ +static bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + union { + u4 arg[2]; + double dd; + } convert; + + convert.arg[0] = arg0; + convert.arg[1] = arg1; + pResult->d = cos(convert.dd); + return true; +} + +/* + * public static double sin(double) + */ +static bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3, + JValue* pResult) +{ + union { + u4 arg[2]; + double dd; + } convert; + + convert.arg[0] = arg0; + convert.arg[1] = arg1; + pResult->d = sin(convert.dd); + return true; +} + + +/* + * =========================================================================== * Infrastructure * =========================================================================== */ @@ -406,6 +556,7 @@ const InlineOperation gDvmInlineOpsTable[] = { { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "()V" }, + { javaLangString_charAt, "Ljava/lang/String;", "charAt", "(I)C" }, { javaLangString_compareTo, @@ -414,6 +565,25 @@ const InlineOperation gDvmInlineOpsTable[] = { "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" }, { javaLangString_length, "Ljava/lang/String;", "length", "()I" }, + + { javaLangMath_abs_int, + "Ljava/lang/Math;", "abs", "(I)I" }, + { javaLangMath_abs_long, + "Ljava/lang/Math;", "abs", "(J)J" }, + { javaLangMath_abs_float, + "Ljava/lang/Math;", "abs", "(F)F" }, + { javaLangMath_abs_double, + "Ljava/lang/Math;", "abs", "(D)D" }, + { javaLangMath_min_int, + "Ljava/lang/Math;", "min", "(II)I" }, + { javaLangMath_max_int, + "Ljava/lang/Math;", "max", "(II)I" }, + { javaLangMath_sqrt, + "Ljava/lang/Math;", "sqrt", "(D)D" }, + { javaLangMath_cos, + "Ljava/lang/Math;", "cos", "(D)D" }, + { javaLangMath_sin, + "Ljava/lang/Math;", "sin", "(D)D" }, }; @@ -52,28 +52,6 @@ INLINE u4 dvmFloatToU4(float val) { conv.in = val; return conv.out; } -#if 0 -INLINE float dvmU8ToFloat(u8 val) { - union { u8 in; float out; } conv; - conv.in = val; - return conv.out; -} -INLINE u8 dvmFloatToU8(float val) { - union { float in; u8 out; } conv; - conv.in = val; - return conv.out; -} -INLINE double dvmU8ToDouble(u8 val) { - union { u8 in; double out; } conv; - conv.in = val; - return conv.out; -} -INLINE u8 dvmDoubleToU8(double val) { - union { double in; u8 out; } conv; - conv.in = val; - return conv.out; -} -#endif /* * Print a hex dump to the log file. |
