changeset 78:6ea46c928791

Adapted parser interface for switch instructions. * Interface changes have been proposed by Remi Forax. * dex/DexMethodVisitor.java (visitInstrPackedSwitch): New interface method. * (visitInstrSparseSwitch): Likewise. * dex/Code.java: Adapted to new interface. * rewriter/DexRewriter.java: Likewise. * rewriter/SwitchTest.java: New test case to test switch instructions.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Fri, 25 Mar 2011 16:04:26 +0100
parents a5ab6534a6a6
children 68531618d334
files src/main/java/org/icedrobot/daneel/dex/Code.java src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java src/test/java/org/icedrobot/daneel/rewriter/SwitchTest.java
diffstat 4 files changed, 142 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/Code.java	Fri Mar 25 09:20:08 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/Code.java	Fri Mar 25 16:04:26 2011 +0100
@@ -459,7 +459,8 @@
                 label = getLabel(pos + i);
                 if (!(label instanceof PackedSwitchLabel))
                     throw new DexParseException("Mistyped branch target.");
-                v.visitInstrSwitch(op, b1, ((PackedSwitchLabel) label).map);
+                PackedSwitchLabel psl = (PackedSwitchLabel) label;
+                v.visitInstrPackedSwitch(op, b1, psl.firstKey, psl.targets);
                 break;
 
             case SPARSE_SWITCH:
@@ -469,7 +470,8 @@
                 label = getLabel(pos + i);
                 if (!(label instanceof SparseSwitchLabel))
                     throw new DexParseException("Mistyped branch target.");
-                v.visitInstrSwitch(op, b1, ((SparseSwitchLabel) label).map);
+                SparseSwitchLabel ssl = (SparseSwitchLabel) label;
+                v.visitInstrSparseSwitch(op, b1, ssl.keys, ssl.targets);
                 break;
 
             case IF_EQZ:
@@ -963,17 +965,17 @@
      */
     private class PackedSwitchLabel extends Label {
         private final int size;
-        final Map<Integer, Label> map;
+        final int firstKey;
+        final Label[] targets;
 
         public PackedSwitchLabel(ByteBuffer buffer, int pos) {
             if (buffer.getShort() != 0x0100)
                 throw new DexParseException("Unidentified in-code data.");
             size = buffer.getShort();
-            map = new HashMap<Integer, Label>(size);
-            int firstKey = buffer.getInt();
-            int[] targets = BufferUtil.getInts(buffer, size);
+            firstKey = buffer.getInt();
+            targets = new Label[size];
             for (int i = 0; i < size; i++)
-                map.put(firstKey + i, putLabel(pos + targets[i], true));
+                targets[i] = putLabel(pos + buffer.getInt(), true);
         }
 
         public int length() {
@@ -991,17 +993,17 @@
      */
     private class SparseSwitchLabel extends Label {
         private final int size;
-        final Map<Integer, Label> map;
+        final int[] keys;
+        final Label[] targets;
 
         public SparseSwitchLabel(ByteBuffer buffer, int pos) {
             if (buffer.getShort() != 0x0200)
                 throw new DexParseException("Unidentified in-code data.");
             size = buffer.getShort();
-            map = new HashMap<Integer, Label>(size);
-            int[] keys = BufferUtil.getInts(buffer, size);
-            int[] targets = BufferUtil.getInts(buffer, size);
+            keys = BufferUtil.getInts(buffer, size);
+            targets = new Label[size];
             for (int i = 0; i < size; i++)
-                map.put(keys[i], putLabel(pos + targets[i], true));
+                targets[i] = putLabel(pos + buffer.getInt(), true);
         }
 
         public int length() {
--- a/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java	Fri Mar 25 09:20:08 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java	Fri Mar 25 16:04:26 2011 +0100
@@ -36,8 +36,6 @@
  */
 package org.icedrobot.daneel.dex;
 
-import java.util.Map;
-
 /**
  * A visitor for methods contained in DEX files.
  */
@@ -268,12 +266,25 @@
 
     /**
      * Visits an instruction with a {@code 31t} format id.
-     * 
-     * @param opcode An opcode among PACKED_SWITCH, SPARSE_SWITCH.
+     *
+     * @param opcode The opcode PACKED_SWITCH.
      * @param vsrc Source register (no register pair).
-     * @param labels The target of the branch.
+     * @param firstKey The first (and lowest) key value
+     * @param targets The targets of the switch.
      */
-    void visitInstrSwitch(Opcode opcode, int vsrc, Map<Integer, Label> labels);
+    void visitInstrPackedSwitch(Opcode opcode, int vsrc, int firstKey,
+            Label[] targets);
+
+    /**
+     * Visits an instruction with a {@code 31t} format id.
+     *
+     * @param opcode The opcode SPARSE_SWITCH.
+     * @param vsrc Source register (no register pair).
+     * @param keys The key values of the switch (sorted low to high).
+     * @param targets The targets of the switch.
+     */
+    void visitInstrSparseSwitch(Opcode opcode, int vsrc, int[] keys,
+            Label[] targets);
 
     /**
      * Visits an instruction with a {@code 23x} format id.
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Fri Mar 25 09:20:08 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Fri Mar 25 16:04:26 2011 +0100
@@ -921,9 +921,16 @@
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
+        public void visitInstrPackedSwitch(Opcode opcode, int vsrc,
+                int firstKey, Label[] targets) {
+            fixStackAfterAMethodCallOrAnExceptionHandler();
+            vsrc = registerToSlot(vsrc);
+            throw new UnsupportedOperationException("NYI " + opcode);
+        }
+
         @Override
-        public void visitInstrSwitch(Opcode opcode, int vsrc,
-                Map<Integer, Label> labels) {
+        public void visitInstrSparseSwitch(Opcode opcode, int vsrc, int[] keys,
+                Label[] targets) {
             fixStackAfterAMethodCallOrAnExceptionHandler();
             vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/java/org/icedrobot/daneel/rewriter/SwitchTest.java	Fri Mar 25 16:04:26 2011 +0100
@@ -0,0 +1,102 @@
+/*
+ * 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.assertNull;
+
+import org.icedrobot.daneel.DexifyingRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@org.junit.Ignore("Switches not yet implemented")
+@RunWith(DexifyingRunner.class)
+public class SwitchTest {
+
+    @Test
+    public void testSwitchPacked() {
+        assertEquals("A", DEXCode.switchPacked(7));
+        assertEquals("B", DEXCode.switchPacked(8));
+        assertEquals("B", DEXCode.switchPacked(9));
+        assertEquals("C", DEXCode.switchPacked(10));
+        assertEquals("C", DEXCode.switchPacked(11));
+        assertNull(DEXCode.switchPacked(23));
+    }
+
+    @Test
+    public void testSwitchSparse() {
+        assertEquals("A", DEXCode.switchSparse(7));
+        assertEquals("B", DEXCode.switchSparse(23));
+        assertEquals("B", DEXCode.switchSparse(42));
+        assertEquals("C", DEXCode.switchSparse(127));
+        assertEquals("C", DEXCode.switchSparse(128));
+        assertNull(DEXCode.switchSparse(129));
+    }
+
+    // Keep this class named "DEXCode" to push it through Daneel.
+    private static class DEXCode {
+
+        public static String switchPacked(int key) {
+            switch (key) {
+            case 7:
+                return "A";
+            case 8:
+            case 9:
+                return "B";
+            case 10:
+            case 11:
+                return "C";
+            }
+            return null;
+        }
+
+        public static String switchSparse(int key) {
+            switch (key) {
+            case 7:
+                return "A";
+            case 23:
+            case 42:
+                return "B";
+            case 127:
+            case 128:
+                return "C";
+            }
+            return null;
+        }
+    };
+}