changeset 118:56844aab0e5c

Fixed parsing of encoded float and double values. * dex/EncodedValue.java (parse): Implemented for float and double values. * (readS64, readU64): Fixed casting bug. * (readL64): Added new helper method. * dex/EncodedValueTest.java: Fixed broken test, never trust the implementation. * rewriter/FieldConstantTest.java: New regression test for above changes.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Mon, 04 Apr 2011 23:11:15 +0200
parents b375045a6197
children 8c0170381072
files src/main/java/org/icedrobot/daneel/dex/EncodedValue.java src/test/java/org/icedrobot/daneel/dex/EncodedValueTest.java src/test/java/org/icedrobot/daneel/rewriter/FieldConstantTest.java
diffstat 3 files changed, 113 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java	Mon Apr 04 18:59:04 2011 +0200
+++ b/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java	Mon Apr 04 23:11:15 2011 +0200
@@ -96,6 +96,12 @@
         case VALUE_LONG:
             assertValueArg(arg, 7);
             return Long.valueOf(readS64(buffer, arg));
+        case VALUE_FLOAT:
+            assertValueArg(arg, 3);
+            return Float.intBitsToFloat((int) readL64(buffer, arg, 32));
+        case VALUE_DOUBLE:
+            assertValueArg(arg, 7);
+            return Double.longBitsToDouble(readL64(buffer, arg, 64));
         case VALUE_STRING:
             assertValueArg(arg, 3);
             return dex.getString((int) readU64(buffer, arg));
@@ -181,8 +187,8 @@
     private static long readS64(ByteBuffer buffer, int size) {
         long result = 0;
         for (int i = 0; i < size; i++)
-            result |= (buffer.get() & 0xff) << (i * 8);
-        result |= buffer.get() << (size * 8);
+            result |= ((long) buffer.get() & 0xff) << (i * 8);
+        result |= ((long) buffer.get()) << (size * 8);
         return result;
     }
 
@@ -196,7 +202,22 @@
     private static long readU64(ByteBuffer buffer, int size) {
         long result = 0;
         for (int i = 0; i <= size; i++)
-            result |= (buffer.get() & 0xff) << (i * 8);
+            result |= ((long) buffer.get() & 0xff) << (i * 8);
+        return result;
+    }
+
+    /**
+     * Helper method decoding a left-aligned (zero-extended to the right)
+     * {@code value} array. Used to encode floating point values.
+     * 
+     * @param buffer The buffer positioned at the {@code value} array.
+     * @param size The number of bytes in the array minus 1.
+     * @param bits The expected number of bits in the decoded value.
+     * @return The decoded value.
+     */
+    private static long readL64(ByteBuffer buffer, int size, int bits) {
+        long result = readU64(buffer, size);
+        result <<= (bits - (size + 1) * 8);
         return result;
     }
 
--- a/src/test/java/org/icedrobot/daneel/dex/EncodedValueTest.java	Mon Apr 04 18:59:04 2011 +0200
+++ b/src/test/java/org/icedrobot/daneel/dex/EncodedValueTest.java	Mon Apr 04 23:11:15 2011 +0200
@@ -71,8 +71,8 @@
         assertEquals(Short.valueOf((short) 511), parse(SEQ_SHORT2));
         assertEquals(Short.valueOf((short) 256), parse(SEQ_SHORT3));
         assertEquals(Short.valueOf(Short.MAX_VALUE), parse(SEQ_SHORT4));
-        assertEquals(Integer.valueOf((byte) -5), parse(SEQ_INT));
-        assertEquals(Long.valueOf((byte) -1), parse(SEQ_LONG));
+        assertEquals(Integer.valueOf(-5), parse(SEQ_INT));
+        assertEquals(Long.valueOf(-129l), parse(SEQ_LONG));
         assertEquals(Character.valueOf((char) 255), parse(SEQ_CHAR1));
         assertEquals(Character.valueOf((char) 511), parse(SEQ_CHAR2));
         assertEquals(Character.valueOf((char) 256), parse(SEQ_CHAR3));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/java/org/icedrobot/daneel/rewriter/FieldConstantTest.java	Mon Apr 04 23:11:15 2011 +0200
@@ -0,0 +1,87 @@
+/*
+ * Daneel - Dalvik to Java bytecode compiler
+ * Copyright (C) 2011  IcedRobot team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file is subject to the "Classpath" exception:
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library.  Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent
+ * modules, and to copy and distribute the resulting executable under terms
+ * of your choice, provided that you also meet, for each linked independent
+ * module, the terms and conditions of the license of that module.  An
+ * independent module is a module which is not derived from or based on
+ * this library.  If you modify this library, you may extend this exception
+ * to your version of the library, but you are not obligated to do so.  If
+ * you do not wish to do so, delete this exception statement from your
+ * version.
+ */
+
+package org.icedrobot.daneel.rewriter;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import java.lang.reflect.Field;
+
+import org.icedrobot.daneel.DexifyingRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DexifyingRunner.class)
+public class FieldConstantTest {
+
+    @Test
+    public void testConstLong() throws Exception {
+        Field f = DEXCode.class.getField("CONST_LONG");
+        assertSame(long.class, f.getType());
+        assertEquals(Long.MAX_VALUE, f.getLong(null));
+    }
+
+    @Test
+    public void testConstFloat1() throws Exception {
+        Field f = DEXCode.class.getField("CONST_FLOAT1");
+        assertSame(float.class, f.getType());
+        assertEquals(0.5f, f.getFloat(null), 0);
+    }
+
+    @Test
+    public void testConstFloat2() throws Exception {
+        Field f = DEXCode.class.getField("CONST_FLOAT2");
+        assertSame(float.class, f.getType());
+        assertEquals(0.23f, f.getFloat(null), 0);
+    }
+
+    @Test
+    public void testConstDouble() throws Exception {
+        Field f = DEXCode.class.getField("CONST_DOUBLE");
+        assertSame(double.class, f.getType());
+        assertEquals(0.42, f.getDouble(null), 0);
+    }
+
+    // Keep this class named "DEXCode" to push it through Daneel.
+    public static class DEXCode {
+        public static final long CONST_LONG = Long.MAX_VALUE;
+        public static final float CONST_FLOAT1 = 0.5f;
+        public static final float CONST_FLOAT2 = 0.23f;
+        public static final double CONST_DOUBLE = 0.42;
+    };
+}