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.
diff --git a/dexopt/OptMain.c b/dexopt/OptMain.c
index ef339cd..953db0b 100644
--- a/dexopt/OptMain.c
+++ b/dexopt/OptMain.c
@@ -337,7 +337,7 @@
      */
     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 25ed38b..4895dc3 100644
--- a/tests/003-omnibus-opcodes/expected.txt
+++ b/tests/003-omnibus-opcodes/expected.txt
@@ -23,6 +23,7 @@
 IntMath.divideByZero
 IntMath.bigDivideOverflow
 IntMath.checkConsts
+IntMath.jlmTests
 FloatMath.convTest
 FloatMath.floatOperTest
 FloatMath.doubleOperTest
@@ -39,6 +40,7 @@
  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 0c1fe1b..cf4869c 100644
--- a/tests/003-omnibus-opcodes/src/FloatMath.java
+++ b/tests/003-omnibus-opcodes/src/FloatMath.java
@@ -262,6 +262,50 @@
         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 @@
         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 126bec6..d5ac744 100644
--- a/tests/003-omnibus-opcodes/src/IntMath.java
+++ b/tests/003-omnibus-opcodes/src/IntMath.java
@@ -432,6 +432,25 @@
         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 @@
         checkConsts((byte) 1, (short) -256, -88888, 0x9922334455667788L);
 
         unopCheck(unopTest(38));
+
+        jlmTests(12345, 0x1122334455667788L);
     }
 }
 
diff --git a/vm/Android.mk b/vm/Android.mk
index 8007fd3..5b6e0ed 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -252,7 +252,7 @@
 
 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 ca71939..26b52be 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 49025a6..6364e94 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 @@
 
 /*
  * ===========================================================================
+ *      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 @@
     { 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 @@
         "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" },
 };
 
 
diff --git a/vm/Misc.h b/vm/Misc.h
index 9b50627..1566161 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -52,28 +52,6 @@
     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.