OSDN Git Service

am af140189: Reconcile with ics-mr1-release
authorThe Android Open Source Project <initial-contribution@android.com>
Wed, 1 Feb 2012 18:00:29 +0000 (10:00 -0800)
committerAndroid Git Automerger <android-git-automerger@android.com>
Wed, 1 Feb 2012 18:00:29 +0000 (10:00 -0800)
* commit 'af140189514d64be270439303eb0f0ab26583af5':

44 files changed:
tests/029-assert/src/Main.java
tests/030-bad-finalizer/src/Main.java
tests/031-class-attributes/expected.txt
tests/031-class-attributes/src/ClassAttrs.java
tests/031-class-attributes/src/FancyClass.java [new file with mode: 0644]
tests/033-class-init-deadlock/expected.txt
tests/033-class-init-deadlock/src/Main.java
tests/034-call-null/expected.txt
tests/034-call-null/src/Main.java
tests/038-inner-null/expected.txt
tests/038-inner-null/src/Main.java
tests/042-new-instance/expected.txt
tests/042-new-instance/src/Main.java
tests/042-new-instance/src/otherpackage/PackageAccess.java
tests/045-reflect-array/expected.txt
tests/045-reflect-array/src/Main.java
tests/046-reflect/expected.txt
tests/046-reflect/src/Main.java
tests/046-reflect/src/otherpackage/Other.java [new file with mode: 0644]
tests/050-sync-test/src/Main.java
tests/051-thread/expected.txt
tests/051-thread/src/Main.java
tests/061-out-of-memory/src/Main.java
tests/068-classloader/src/FancyLoader.java
tests/070-nio-buffer/expected.txt
tests/070-nio-buffer/src/Main.java
tests/084-class-init/src/Main.java
tests/084-class-init/src/SlowInit.java
tests/086-null-super/src/Main.java
tests/087-gc-after-link/src/Main.java
tests/091-deep-interface-hierarchy/expected.txt [new file with mode: 0644]
tests/091-deep-interface-hierarchy/info.txt [new file with mode: 0644]
tests/091-deep-interface-hierarchy/src/Main.java [new file with mode: 0644]
tests/092-locale/expected.txt [new file with mode: 0644]
tests/092-locale/info.txt [new file with mode: 0644]
tests/092-locale/src/Main.java [new file with mode: 0644]
tests/093-serialization/expected.txt [new file with mode: 0644]
tests/093-serialization/info.txt [new file with mode: 0644]
tests/093-serialization/src/Main.java [new file with mode: 0644]
tests/094-pattern/expected.txt [new file with mode: 0644]
tests/094-pattern/info.txt [new file with mode: 0644]
tests/094-pattern/src/Main.java [new file with mode: 0644]
vm/Debugger.cpp
vm/oo/Class.cpp

index 1e5cc7c..3b1f8da 100644 (file)
@@ -12,5 +12,8 @@ public class Main {
         } catch (AssertionError ae) {
             System.out.println("caught expected assert exception");
         }
+
+        // exercise this code path
+        ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
     }
 }
index c063476..db80a87 100644 (file)
@@ -14,7 +14,7 @@ public class Main {
         System.gc();
 
         for (int i = 0; i < 8; i++) {
-            BadFinalizer.snooze(5000);
+            BadFinalizer.snooze(4000);
             System.out.println("Requesting another GC.");
             System.gc();
         }
index 47eaeee..afa3416 100644 (file)
@@ -4,6 +4,7 @@
   simple: ClassAttrs
   genericSignature: null
   super: class java.lang.Object
+  genericSuperclass: class java.lang.Object
   declaring: null
   enclosing: null
   enclosingCon: null
   isMemberClass: false
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [0]
 ***** class OtherClass:
   name: OtherClass
   canonical: OtherClass
   simple: OtherClass
   genericSignature: null
   super: class java.lang.Object
+  genericSuperclass: class java.lang.Object
   declaring: null
   enclosing: null
   enclosingCon: null
   isMemberClass: false
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [0]
 ***** class otherpackage.OtherPackageClass:
   name: otherpackage.OtherPackageClass
   canonical: otherpackage.OtherPackageClass
   simple: OtherPackageClass
   genericSignature: null
   super: class java.lang.Object
+  genericSuperclass: class java.lang.Object
   declaring: null
   enclosing: null
   enclosingCon: null
   isMemberClass: false
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [0]
 ***** class ClassAttrs$1InnerNamed:
   name: ClassAttrs$1InnerNamed
   canonical: null
   simple: InnerNamed
   genericSignature: null
   super: class java.lang.Object
+  genericSuperclass: class java.lang.Object
   declaring: null
   enclosing: class ClassAttrs
   enclosingCon: null
   isMemberClass: false
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [0]
 ***** class ClassAttrs$1ConsInnerNamed:
   name: ClassAttrs$1ConsInnerNamed
   canonical: null
   simple: ConsInnerNamed
   genericSignature: null
   super: class java.lang.Object
+  genericSuperclass: class java.lang.Object
   declaring: null
   enclosing: class ClassAttrs
   enclosingCon: ClassAttrs()
   isMemberClass: false
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [0]
 ***** class ClassAttrs$1:
   name: ClassAttrs$1
   canonical: null
   simple: 
   genericSignature: null
   super: class OtherClass
+  genericSuperclass: class OtherClass
   declaring: null
   enclosing: class ClassAttrs
   enclosingCon: null
   isMemberClass: false
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [0]
 ***** class ClassAttrs$MemberClass:
   name: ClassAttrs$MemberClass
   canonical: ClassAttrs.MemberClass
   simple: MemberClass
   genericSignature: <XYZ:Ljava/lang/Object;>Ljava/lang/Object;
   super: class java.lang.Object
+  genericSuperclass: class java.lang.Object
   declaring: class ClassAttrs
   enclosing: class ClassAttrs
   enclosingCon: null
   isMemberClass: true
   isPrimitive: false
   isSynthetic: false
+  genericInterfaces: [0]
+  typeParameters: [1] XYZ
+***** class FancyClass:
+  name: FancyClass
+  canonical: FancyClass
+  simple: FancyClass
+  genericSignature: <K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/util/HashMap<TK;TV;>;Ljava/util/Map<TK;TV;>;
+  super: class java.util.HashMap
+  genericSuperclass: java.util.HashMap<K, V>
+  declaring: null
+  enclosing: null
+  enclosingCon: null
+  enclosingMeth: null
+  modifiers: 1
+  package: null
+  declaredClasses: [0]
+  member classes: [2] class java.util.AbstractMap$SimpleEntry, class java.util.AbstractMap$SimpleImmutableEntry
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: false
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+  genericInterfaces: [1] java.util.Map<K, V>
+  typeParameters: [2] K, V
 constructor signature: (LClassAttrs$MemberClass<TXYZ;>;)V
 method signature: ()Ljava/lang/Class<TXYZ;>;
 field signature: LClassAttrs$MemberClass<TXYZ;>;
index c1407bd..d93a925 100644 (file)
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 
 public class ClassAttrs {
     ClassAttrs() {
@@ -42,6 +43,9 @@ public class ClassAttrs {
         /* member, not anonymous, not local */
         printClassAttrs(MemberClass.class);
 
+        /* fancy */
+        printClassAttrs(FancyClass.class);
+
         try {
             Constructor cons;
             cons = MemberClass.class.getConstructor(
@@ -82,8 +86,8 @@ public class ClassAttrs {
             }
             method.setAccessible(true);
         } catch (NoSuchMethodException ex) {
-            System.err.println("getSignatureAttribute() not defined.");
-            ex.printStackTrace();
+            //System.err.println("getSignatureAttribute() not defined.");
+            //ex.printStackTrace();
             return "<unknown>";
         }
 
@@ -118,7 +122,6 @@ public class ClassAttrs {
      * Dump a variety of class attributes.
      */
     public static void printClassAttrs(Class clazz) {
-        final boolean WORKING = false;
         Class clazz2;
 
         System.out.println("***** " + clazz + ":");
@@ -134,7 +137,7 @@ public class ClassAttrs {
 
         System.out.println("  super: "
             + clazz.getSuperclass());
-        if (WORKING) System.out.println("  genericSuperclass: "
+        System.out.println("  genericSuperclass: "
             + clazz.getGenericSuperclass());
         System.out.println("  declaring: "
             + clazz.getDeclaringClass());
@@ -173,8 +176,12 @@ public class ClassAttrs {
         System.out.println("  isSynthetic: "
             + clazz.isSynthetic());
 
-        if (WORKING) System.out.println("  genericInterfaces: "
+        System.out.println("  genericInterfaces: "
             + stringifyTypeArray(clazz.getGenericInterfaces()));
+
+        TypeVariable<Class<?>>[] typeParameters = clazz.getTypeParameters();
+        System.out.println("  typeParameters: "
+            + stringifyTypeArray(typeParameters));
     }
 
     /*
diff --git a/tests/031-class-attributes/src/FancyClass.java b/tests/031-class-attributes/src/FancyClass.java
new file mode 100644 (file)
index 0000000..a58b6a6
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class FancyClass<K,V> extends HashMap<K,V> implements Map<K,V> {
+}
+
index 387a426..182d0da 100644 (file)
@@ -1,7 +1,7 @@
 Deadlock test starting.
 A initializing...
 B initializing...
-Deadlock test interupting threads.
+Deadlock test interrupting threads.
 Deadlock test main thread bailing.
 A initialized: false
 B initialized: false
index 27c4922..1e3f897 100644 (file)
@@ -16,11 +16,13 @@ public class Main {
         thread1 = new Thread() { public void run() { new A(); } };
         thread2 = new Thread() { public void run() { new B(); } };
         thread1.start();
+        // Give thread1 a chance to start before starting thread2.
+        try { Thread.sleep(1000); } catch (InterruptedException ie) { }
         thread2.start();
 
         try { Thread.sleep(6000); } catch (InterruptedException ie) { }
 
-        System.out.println("Deadlock test interupting threads.");
+        System.out.println("Deadlock test interrupting threads.");
         thread1.interrupt();
         thread2.interrupt();
         System.out.println("Deadlock test main thread bailing.");
index 5ffbe05..19f86f4 100644 (file)
@@ -1,3 +1 @@
-java.lang.NullPointerException
-       at Main.main(Main.java:12)
-       at dalvik.system.NativeStart.main(Native Method)
+done
index a0a129e..8fe88bd 100644 (file)
@@ -9,6 +9,11 @@ public class Main {
 
     public static void main(String[] args) {
         Main instance = null;
-        instance.doStuff();
+        try {
+            instance.doStuff();
+            throw new RuntimeException("fail");
+        } catch (NullPointerException npe) { }
+
+        System.out.println("done");
     }
 }
index 0be8ffd..29c1e42 100644 (file)
@@ -1,5 +1,2 @@
 new Special()
-java.lang.NullPointerException
-       at Main$Special.callInner(Main.java:17)
-       at Main.main(Main.java:6)
-       at dalvik.system.NativeStart.main(Native Method)
+done
index acc8764..1239248 100644 (file)
@@ -4,6 +4,7 @@ public class Main {
     public static void main(String[] args) {
         Special special = new Special();
         special.callInner();
+        System.out.println("done");
     }
 
     public static class Special {
@@ -14,7 +15,10 @@ public class Main {
         }
 
         public void callInner() {
-            mBlort.repaint();
+            try {
+                mBlort.repaint();
+                throw new RuntimeException("fail");
+            } catch (NullPointerException npe) {}
         }
     }
 
index 53447db..bb1b80c 100644 (file)
@@ -6,3 +6,4 @@ Cons LocalClass failed as expected
 Cons LocalClass2 succeeded
 Cons got expected PackageAccess complaint
 Cons got expected InstantationException
+Cons got expected PackageAccess2 complaint
index 8faef13..e43c5a5 100644 (file)
 
 import java.lang.reflect.Constructor;
 
-import java.lang.reflect.Constructor;
-
 /**
  * Test instance creation.
  */
 public class Main {
+    private static boolean FULL_ACCESS_CHECKS = false;  // b/5861201
+
     public static void main(String[] args) {
         testClassNewInstance();
         testConstructorNewInstance();
@@ -98,6 +98,7 @@ public class Main {
             Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
             System.err.println("ERROR: Cons PackageAccess succeeded unexpectedly");
         } catch (NoSuchMethodException nsme) {
+            // constructor isn't public
             System.out.println("Cons got expected PackageAccess complaint");
         } catch (Exception ex) {
             System.err.println("Cons got unexpected PackageAccess failure");
@@ -117,6 +118,22 @@ public class Main {
             System.err.println("Cons got unexpected MaybeAbstract failure");
             ex.printStackTrace();
         }
+
+        // should fail
+        try {
+            Class c = Class.forName("otherpackage.PackageAccess2");
+            Constructor cons = c.getConstructor((Class[]) null);
+            if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
+            Object obj = cons.newInstance();
+            System.err.println("ERROR: Cons PackageAccess2 succeeded unexpectedly");
+        } catch (IllegalAccessException iae) {
+            // constructor is public, but class has package scope
+            System.out.println("Cons got expected PackageAccess2 complaint");
+        } catch (Exception ex) {
+            System.err.println("Cons got unexpected PackageAccess2 failure");
+            ex.printStackTrace();
+        }
+
     }
 }
 
index 0749d67..f4541f2 100644 (file)
@@ -1,6 +1,29 @@
+/*
+ * 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.
+ */
+
 package otherpackage;
 
 class PackageAccess {
     /*package*/ PackageAccess() {
+        System.out.println("created PackageAccess");
+    }
+}
+
+class PackageAccess2 {
+    public PackageAccess2() {
+        System.out.println("created PackageAccess2");
     }
 }
index 5c609b5..5990b34 100644 (file)
@@ -1,4 +1,7 @@
 ReflectArrayTest.testSingleInt passed
+ReflectArrayTest.testSingleChar passed
+ReflectArrayTest.testSingleShort passed
+ReflectArrayTest.testSingleLong passed
 ReflectArrayTest.testSingle passed
 ReflectArrayTest.testMultiInt passed
 zero one two ++
index c70e291..36f8ac3 100644 (file)
@@ -10,6 +10,9 @@ import java.lang.reflect.Array;
 public class Main {
     public static void main(String[] args) {
         testSingleInt();
+        testSingleChar();
+        testSingleShort();
+        testSingleLong();
         testSingle();
         testMultiInt();
         testMulti();
@@ -33,22 +36,31 @@ public class Main {
         try {
             array[2] = 27;
             throw new RuntimeException("store should have failed");
-        }
-        catch (ArrayIndexOutOfBoundsException abe) {
-        }
+        } catch (ArrayIndexOutOfBoundsException abe) { }
+        try {
+            Array.setInt(intArray, 2, 27);
+            throw new RuntimeException("store should have failed");
+        } catch (ArrayIndexOutOfBoundsException abe) { }
         if (array.length != Array.getLength(intArray) ||
             array.length != 2)
         {
             throw new RuntimeException("bad len");
         }
 
+        Integer x123 = Integer.valueOf(123);
+        Integer x456 = Integer.valueOf(456);
+
+        Array.set(intArray, 0, x123);
+        Array.set(intArray, 1, x456);
+        if (!Array.get(intArray, 0).equals(x123) || !Array.get(intArray, 1).equals(x456)) {
+            throw new RuntimeException("bad 123 or 456");
+        }
+
         int[][] wrongArray;
         try {
             wrongArray = (int[][]) intArray;
             throw new RuntimeException("cast should have failed");
-        }
-        catch (ClassCastException cce) {
-        }
+        } catch (ClassCastException cce) { }
 
         intArray = Array.newInstance(Integer.TYPE, 0);
         if (Array.getLength(intArray) != 0)
@@ -56,6 +68,96 @@ public class Main {
         System.out.println("ReflectArrayTest.testSingleInt passed");
     }
 
+    static void testSingleChar() {
+        Object charArray = Array.newInstance(Character.TYPE, 7);
+
+        char[] array = (char[]) charArray;
+        array[0] = '0';
+        array[1] = 'W';
+        array[2] = '2';
+        array[3] = '3';
+        array[4] = 'X';
+        array[5] = '5';
+        array[6] = '6';
+        Array.setChar(charArray, 1, '1');
+        Array.setChar(charArray, 4, '4');
+        try {
+            Array.setShort(charArray, 3, (short) 'Y');
+            throw new RuntimeException("shouldn't allow short in char array");
+        } catch (IllegalArgumentException iae) {}
+        try {
+            Array.setInt(charArray, 5, 'Z');
+            throw new RuntimeException("shouldn't allow int in char array");
+        } catch (IllegalArgumentException iae) {}
+
+        try {
+            for (int i = 0; i < array.length; i++) {
+                if (Array.getInt(charArray, i) - '0' != i) {
+                    throw new RuntimeException("mismatch: " + i + " is " + array[i]);
+                }
+            }
+
+            if (Array.getInt(charArray, 4) != '4') {
+                throw new RuntimeException("load should have worked");
+            }
+        } catch (IllegalArgumentException iae) {
+            System.err.println("Couldn't Array.getInt(charArray)");
+        }
+        try {
+            Array.getByte(charArray, 2);
+            throw new RuntimeException("shouldn't allow read of char as byte");
+        } catch (IllegalArgumentException iae) {}
+
+        Array.setChar(charArray, 3, (char) 0xffff);
+        try {
+            if (Array.getInt(charArray, 3) != 0xffff) {
+                throw new RuntimeException("char got sign-extended? "
+                    + Array.getInt(charArray, 3));
+            }
+        } catch (IllegalArgumentException iae) {
+            System.err.println("Couldn't Array.getInt(charArray)");
+        }
+
+        System.out.println("ReflectArrayTest.testSingleChar passed");
+    }
+
+    static void testSingleShort() {
+        Object shortArray = Array.newInstance(Short.TYPE, 1);
+        Array.setShort(shortArray, 0, (short) -1);
+        if (Array.getInt(shortArray, 0) != -1) {
+            throw new RuntimeException("short didn't get sign-extended");
+        }
+
+        Short box = (Short) Array.get(shortArray, 0);
+
+        System.out.println("ReflectArrayTest.testSingleShort passed");
+    }
+
+    static void testSingleLong() {
+        Object longArray = Array.newInstance(Long.TYPE, 2);
+        Array.setInt(longArray, 0, 123);
+        Array.setLong(longArray, 1, 0x1122334455667788L);
+        try {
+            Array.getInt(longArray, 0);
+            throw new RuntimeException("shouldn't allow read of long as int");
+        } catch (IllegalArgumentException iae) {}
+
+        long[] array = (long[]) longArray;
+        if (array[0] != 123 || array[1] != 0x1122334455667788L) {
+            throw new RuntimeException();
+        }
+
+        float f = Array.getFloat(longArray, 0);
+        if (f < 122.9 || f > 123.1) {
+            throw new RuntimeException("long-as-float failed - " + f);
+        }
+        if (Array.getLong(longArray, 1) != 0x1122334455667788L) {
+            throw new RuntimeException("long1 failed");
+        }
+
+        System.out.println("ReflectArrayTest.testSingleLong passed");
+    }
+
     static void testSingle() {
         Object strArray;
 
@@ -64,6 +166,10 @@ public class Main {
         String[] array = (String[]) strArray;
         array[0] = "entry zero";
         Array.set(strArray, 1, "entry one");
+        try {
+            Array.set(strArray, 2, "entry two");
+            throw new RuntimeException("store should have failed");
+        } catch (ArrayIndexOutOfBoundsException abe) { }
 
         //System.out.println("array: " + array);
 
@@ -77,6 +183,11 @@ public class Main {
         {
             throw new RuntimeException("bad len");
         }
+
+        try {
+            Array.set(strArray, 0, new Integer(5));
+            throw new RuntimeException("store of Integer should have failed");
+        } catch (IllegalArgumentException iae) {}
         System.out.println("ReflectArrayTest.testSingle passed");
     }
 
index 55b0eca..309b076 100644 (file)
@@ -90,8 +90,13 @@ Target constructor (IF)V : ii=7 ff=3.3333
 myMethod (I)I
  arg=17 anInt=7
 ReflectTest done!
+public method
 checkType invoking null
 checkType got expected exception
 got methods
 NoisyInitUser is initializing
 NoisyInit is initializing
+
+generic field: java.util.List<java.lang.String>
+generic method fancyMethod params='[1] java.util.ArrayList<java.lang.String>' ret='java.util.Map<java.lang.Integer, java.lang.String>'
+generic ctor Main params='[1] java.util.ArrayList<java.lang.Integer>'
index e604979..e2a3929 100644 (file)
@@ -3,11 +3,18 @@
 import java.lang.reflect.*;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Reflection test.
  */
 public class Main {
+    private static boolean FULL_ACCESS_CHECKS = false;  // b/5861201
+    public Main() {}
+    public Main(ArrayList<Integer> stuff) {}
+
     void printMethodInfo(Method meth) {
         Class[] params, exceptions;
         int i;
@@ -55,6 +62,48 @@ public class Main {
         System.out.println("  ::: " + one + ":" + two + ":" + three);
     }
 
+    public static void checkAccess() {
+        try {
+            Class target = otherpackage.Other.class;
+            Object instance = new otherpackage.Other();
+            Method meth;
+
+            meth = target.getMethod("publicMethod", (Class[]) null);
+            meth.invoke(instance);
+
+            try {
+                meth = target.getMethod("packageMethod", (Class[]) null);
+                System.err.println("succeeded on package-scope method");
+            } catch (NoSuchMethodException nsme) {
+                // good
+            }
+
+
+            instance = otherpackage.Other.getInnerClassInstance();
+            target = instance.getClass();
+            meth = target.getMethod("innerMethod", (Class[]) null);
+            try {
+                if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
+                meth.invoke(instance);
+                System.err.println("inner-method invoke unexpectedly worked");
+            } catch (IllegalAccessException iae) {
+                // good
+            }
+
+            Field field = target.getField("innerField");
+            try {
+                int x = field.getInt(instance);
+                if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
+                System.err.println("field get unexpectedly worked: " + x);
+            } catch (IllegalAccessException iae) {
+                // good
+            }
+        } catch (Exception ex) {
+            System.out.println("----- unexpected exception -----");
+            ex.printStackTrace();
+        }
+    }
+
     public void run() {
         Class target = Target.class;
         Method meth = null;
@@ -295,8 +344,7 @@ public class Main {
             targ = cons.newInstance(args);
             targ.myMethod(17);
 
-        }
-        catch (Exception ex) {
+        } catch (Exception ex) {
             System.out.println("----- unexpected exception -----");
             ex.printStackTrace();
         }
@@ -347,14 +395,80 @@ public class Main {
         /* neither NoisyInit nor NoisyInitUser should be initialized yet */
         NoisyInitUser niu = new NoisyInitUser();
         NoisyInit ni = new NoisyInit();
+
+        System.out.println("");
+    }
+
+
+    /*
+     * Test some generic type stuff.
+     */
+    public List<String> dummy;
+    public Map<Integer,String> fancyMethod(ArrayList<String> blah) { return null; }
+    public static void checkGeneric() {
+        Field field;
+        try {
+            field = Main.class.getField("dummy");
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        }
+        Type listType = field.getGenericType();
+        System.out.println("generic field: " + listType);
+
+        Method method;
+        try {
+            method = Main.class.getMethod("fancyMethod",
+                new Class[] { ArrayList.class });
+        } catch (NoSuchMethodException nsme) {
+            throw new RuntimeException(nsme);
+        }
+        Type[] parmTypes = method.getGenericParameterTypes();
+        Type ret = method.getGenericReturnType();
+        System.out.println("generic method " + method.getName() + " params='"
+            + stringifyTypeArray(parmTypes) + "' ret='" + ret + "'");
+
+        Constructor ctor;
+        try {
+            ctor = Main.class.getConstructor(new Class[] { ArrayList.class });
+        } catch (NoSuchMethodException nsme) {
+            throw new RuntimeException(nsme);
+        }
+        parmTypes = ctor.getGenericParameterTypes();
+        System.out.println("generic ctor " + ctor.getName() + " params='"
+            + stringifyTypeArray(parmTypes) + "'");
+    }
+
+    /*
+     * Convert an array of Type into a string.  Start with an array count.
+     */
+    private static String stringifyTypeArray(Type[] types) {
+        StringBuilder stb = new StringBuilder();
+        boolean first = true;
+
+        stb.append("[" + types.length + "]");
+
+        for (Type t: types) {
+            if (first) {
+                stb.append(" ");
+                first = false;
+            } else {
+                stb.append(", ");
+            }
+            stb.append(t.toString());
+        }
+
+        return stb.toString();
     }
 
+
     public static void main(String[] args) {
         Main test = new Main();
         test.run();
 
+        checkAccess();
         checkType();
         checkInit();
+        checkGeneric();
     }
 }
 
diff --git a/tests/046-reflect/src/otherpackage/Other.java b/tests/046-reflect/src/otherpackage/Other.java
new file mode 100644 (file)
index 0000000..702ab6d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package otherpackage;
+
+public class Other {
+    public void publicMethod() {
+        System.out.println("public method");
+    }
+    void packageMethod() {
+        System.out.println("package method");
+    }
+
+    public static InnerOther getInnerClassInstance() {
+        return new InnerOther();
+    }
+
+    private static class InnerOther {
+        public void innerMethod() {
+            System.out.println("inner method");
+        }
+
+        public int innerField = 7;
+    }
+}
index c2ea192..418f5f4 100644 (file)
@@ -23,8 +23,7 @@ public class Main {
         System.out.println("GOING");
         try {
             Thread.sleep(1000);
-        }
-        catch (InterruptedException ie) {
+        } catch (InterruptedException ie) {
             System.out.println("INTERRUPT!");
             ie.printStackTrace();
         }
@@ -38,23 +37,22 @@ public class Main {
         two = new CpuThread(2);
 
         one.start();
-        two.start();
 
         try {
             Thread.sleep(100);
-        }
-        catch (InterruptedException ie) {
+        } catch (InterruptedException ie) {
             System.out.println("INTERRUPT!");
             ie.printStackTrace();
         }
 
+        two.start();
+
         //System.out.println("main: off and running");
 
         try {
             one.join();
             two.join();
-        }
-        catch (InterruptedException ie) {
+        } catch (InterruptedException ie) {
             System.out.println("INTERRUPT!");
             ie.printStackTrace();
         }
@@ -88,34 +86,29 @@ class CpuThread extends Thread {
         //System.out.print("thread running -- ");
         //System.out.println(Thread.currentThread().getName());
 
-        for (int i = 0; i < 10; i++) {
-            output(mNumber);
-        }
+        synchronized (mSyncable) {
+            for (int i = 0; i < 10; i++) {
+                output(mNumber);
+            }
 
-        System.out.print("Final result: ");
-        System.out.println(mCount);
+            System.out.print("Final result: ");
+            System.out.println(mCount);
+        }
     }
 
     void output(int num) {
-        /*
-         * Delete the next line; last "final result" should != 20.
-         */
-        synchronized (mSyncable)
-        {
-            int i, count;
-
-            count = mCount;
+        int count = mCount;
 
-            System.out.print("going: ");
-            System.out.println(num);
+        System.out.print("going: ");
+        System.out.println(num);
 
-            /* burn CPU; adjust end value so we exceed scheduler quantum */
-            for (int j = 0; j < 5000; j++)
-                ;
-
-            count++;
-            mCount = count;
+        /* burn CPU; adjust end value so we exceed scheduler quantum */
+        for (int j = 0; j < 5000; j++) {
+            ;
         }
+
+        count++;
+        mCount = count;
     }
 }
 
@@ -150,14 +143,12 @@ class SleepyThread extends Thread {
                 synchronized (mWaitOnMe) {
                     mWaitOnMe.wait(9000);
                 }
-            }
-            catch (InterruptedException ie) {
+            } catch (InterruptedException ie) {
                 // Expecting this; interrupted should be false.
                 System.out.println(Thread.currentThread().getName() +
                         " interrupted, flag=" + Thread.interrupted());
                 intr = true;
-            }
-            catch (Exception ex) {
+            } catch (Exception ex) {
                 ex.printStackTrace();
             }
 
@@ -166,8 +157,7 @@ class SleepyThread extends Thread {
         } else {
             try {
                 Thread.sleep(2000);
-            }
-            catch (InterruptedException ie) {
+            } catch (InterruptedException ie) {
                 System.out.println("PESKY INTERRUPTED?");
             }
 
index fbe32f6..8e6b153 100644 (file)
@@ -1,515 +1,5 @@
-running 0
-running 1
-running 2
-running 3
-running 4
-running 5
-running 6
-running 7
-running 8
-running 9
-running 10
-running 11
-running 12
-running 13
-running 14
-running 15
-running 16
-running 17
-running 18
-running 19
-running 20
-running 21
-running 22
-running 23
-running 24
-running 25
-running 26
-running 27
-running 28
-running 29
-running 30
-running 31
-running 32
-running 33
-running 34
-running 35
-running 36
-running 37
-running 38
-running 39
-running 40
-running 41
-running 42
-running 43
-running 44
-running 45
-running 46
-running 47
-running 48
-running 49
-running 50
-running 51
-running 52
-running 53
-running 54
-running 55
-running 56
-running 57
-running 58
-running 59
-running 60
-running 61
-running 62
-running 63
-running 64
-running 65
-running 66
-running 67
-running 68
-running 69
-running 70
-running 71
-running 72
-running 73
-running 74
-running 75
-running 76
-running 77
-running 78
-running 79
-running 80
-running 81
-running 82
-running 83
-running 84
-running 85
-running 86
-running 87
-running 88
-running 89
-running 90
-running 91
-running 92
-running 93
-running 94
-running 95
-running 96
-running 97
-running 98
-running 99
-running 100
-running 101
-running 102
-running 103
-running 104
-running 105
-running 106
-running 107
-running 108
-running 109
-running 110
-running 111
-running 112
-running 113
-running 114
-running 115
-running 116
-running 117
-running 118
-running 119
-running 120
-running 121
-running 122
-running 123
-running 124
-running 125
-running 126
-running 127
-running 128
-running 129
-running 130
-running 131
-running 132
-running 133
-running 134
-running 135
-running 136
-running 137
-running 138
-running 139
-running 140
-running 141
-running 142
-running 143
-running 144
-running 145
-running 146
-running 147
-running 148
-running 149
-running 150
-running 151
-running 152
-running 153
-running 154
-running 155
-running 156
-running 157
-running 158
-running 159
-running 160
-running 161
-running 162
-running 163
-running 164
-running 165
-running 166
-running 167
-running 168
-running 169
-running 170
-running 171
-running 172
-running 173
-running 174
-running 175
-running 176
-running 177
-running 178
-running 179
-running 180
-running 181
-running 182
-running 183
-running 184
-running 185
-running 186
-running 187
-running 188
-running 189
-running 190
-running 191
-running 192
-running 193
-running 194
-running 195
-running 196
-running 197
-running 198
-running 199
-running 200
-running 201
-running 202
-running 203
-running 204
-running 205
-running 206
-running 207
-running 208
-running 209
-running 210
-running 211
-running 212
-running 213
-running 214
-running 215
-running 216
-running 217
-running 218
-running 219
-running 220
-running 221
-running 222
-running 223
-running 224
-running 225
-running 226
-running 227
-running 228
-running 229
-running 230
-running 231
-running 232
-running 233
-running 234
-running 235
-running 236
-running 237
-running 238
-running 239
-running 240
-running 241
-running 242
-running 243
-running 244
-running 245
-running 246
-running 247
-running 248
-running 249
-running 250
-running 251
-running 252
-running 253
-running 254
-running 255
-running 256
-running 257
-running 258
-running 259
-running 260
-running 261
-running 262
-running 263
-running 264
-running 265
-running 266
-running 267
-running 268
-running 269
-running 270
-running 271
-running 272
-running 273
-running 274
-running 275
-running 276
-running 277
-running 278
-running 279
-running 280
-running 281
-running 282
-running 283
-running 284
-running 285
-running 286
-running 287
-running 288
-running 289
-running 290
-running 291
-running 292
-running 293
-running 294
-running 295
-running 296
-running 297
-running 298
-running 299
-running 300
-running 301
-running 302
-running 303
-running 304
-running 305
-running 306
-running 307
-running 308
-running 309
-running 310
-running 311
-running 312
-running 313
-running 314
-running 315
-running 316
-running 317
-running 318
-running 319
-running 320
-running 321
-running 322
-running 323
-running 324
-running 325
-running 326
-running 327
-running 328
-running 329
-running 330
-running 331
-running 332
-running 333
-running 334
-running 335
-running 336
-running 337
-running 338
-running 339
-running 340
-running 341
-running 342
-running 343
-running 344
-running 345
-running 346
-running 347
-running 348
-running 349
-running 350
-running 351
-running 352
-running 353
-running 354
-running 355
-running 356
-running 357
-running 358
-running 359
-running 360
-running 361
-running 362
-running 363
-running 364
-running 365
-running 366
-running 367
-running 368
-running 369
-running 370
-running 371
-running 372
-running 373
-running 374
-running 375
-running 376
-running 377
-running 378
-running 379
-running 380
-running 381
-running 382
-running 383
-running 384
-running 385
-running 386
-running 387
-running 388
-running 389
-running 390
-running 391
-running 392
-running 393
-running 394
-running 395
-running 396
-running 397
-running 398
-running 399
-running 400
-running 401
-running 402
-running 403
-running 404
-running 405
-running 406
-running 407
-running 408
-running 409
-running 410
-running 411
-running 412
-running 413
-running 414
-running 415
-running 416
-running 417
-running 418
-running 419
-running 420
-running 421
-running 422
-running 423
-running 424
-running 425
-running 426
-running 427
-running 428
-running 429
-running 430
-running 431
-running 432
-running 433
-running 434
-running 435
-running 436
-running 437
-running 438
-running 439
-running 440
-running 441
-running 442
-running 443
-running 444
-running 445
-running 446
-running 447
-running 448
-running 449
-running 450
-running 451
-running 452
-running 453
-running 454
-running 455
-running 456
-running 457
-running 458
-running 459
-running 460
-running 461
-running 462
-running 463
-running 464
-running 465
-running 466
-running 467
-running 468
-running 469
-running 470
-running 471
-running 472
-running 473
-running 474
-running 475
-running 476
-running 477
-running 478
-running 479
-running 480
-running 481
-running 482
-running 483
-running 484
-running 485
-running 486
-running 487
-running 488
-running 489
-running 490
-running 491
-running 492
-running 493
-running 494
-running 495
-running 496
-running 497
-running 498
-running 499
-running 500
-running 501
-running 502
-running 503
-running 504
-running 505
-running 506
-running 507
-running 508
-running 509
-running 510
-running 511
+Initializing System.out...
+Thread count: 512
 Starting thread 'Thready'
 @ Thread running
 @ Got expected setDaemon exception
index 9acc89e..ea587af 100644 (file)
@@ -1,20 +1,42 @@
-// Copyright 2006 The Android Open Source Project
+/*
+ * Copyright (C) 2006 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.
+ */
+
+import java.util.ArrayList;
 
 /**
  * Test some basic thread stuff.
  */
 public class Main {
-    public static void main(String[] args) {
+    public static void main(String[] args) throws Exception {
+        System.out.println("Initializing System.out...");
+
+        MyThread[] threads = new MyThread[512];
         for (int i = 0; i < 512; i++) {
-            MyThread myThread = new MyThread();
-            myThread.start();
-            try {
-                Thread.sleep(1);
-            } catch (InterruptedException ie) {
-                ie.printStackTrace();
-            }
+            threads[i] = new MyThread();
         }
 
+        for (MyThread thread : threads) {
+            thread.start();
+        }
+        for (MyThread thread : threads) {
+            thread.join();
+        }
+
+        System.out.println("Thread count: " + MyThread.mCount);
+
         go();
         System.out.println("thread test done");
     }
@@ -40,9 +62,11 @@ public class Main {
      * Simple thread capacity test.
      */
     static class MyThread extends Thread {
-        private static int mCount = 0;
+        static int mCount = 0;
         public void run() {
-            System.out.println("running " + (mCount++));
+            synchronized (MyThread.class) {
+                ++mCount;
+            }
         }
     }
 }
index b5999b3..c812c81 100644 (file)
@@ -43,18 +43,13 @@ public class Main {
     private static void testOomeLarge() {
         System.out.println("testOomeLarge beginning");
 
-        /* Just shy of the typical max heap size so that it will actually
-         * try to allocate it instead of short-circuiting.
-         *
-         * TODO: stop assuming the VM defaults to 16MB max
-         */
-        final int SIXTEEN_MB = (16 * 1024 * 1024 - 32);
-
         Boolean sawEx = false;
-        byte a[];
+        byte[] a;
 
         try {
-            a = new byte[SIXTEEN_MB];
+            // Just shy of the typical max heap size so that it will actually
+            // try to allocate it instead of short-circuiting.
+            a = new byte[(int) Runtime.getRuntime().maxMemory() - 32];
         } catch (OutOfMemoryError oom) {
             //Log.i(TAG, "HeapTest/OomeLarge caught " + oom);
             sawEx = true;
@@ -71,11 +66,8 @@ public class Main {
     /* Do this in another method so that the GC has a chance of freeing the
      * list afterwards.  Even if we null out list when we're done, the conservative
      * GC may see a stale pointer to it in a register.
-     *
-     * TODO: stop assuming the VM defaults to 16MB max
      */
     private static boolean testOomeSmallInternal() {
-        final int SIXTEEN_MB = (16 * 1024 * 1024);
         final int LINK_SIZE = 6 * 4; // estimated size of a LinkedList's node
 
         LinkedList<Object> list = new LinkedList<Object>();
@@ -86,7 +78,7 @@ public class Main {
         while (objSize >= LINK_SIZE) {
             boolean sawEx = false;
             try {
-                for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
+                for (int i = 0; i < Runtime.getRuntime().maxMemory() / objSize; i++) {
                     list.add((Object)new byte[objSize]);
                 }
             } catch (OutOfMemoryError oom) {
index 173b08f..d04083a 100644 (file)
@@ -53,7 +53,7 @@ public class FancyLoader extends ClassLoader {
         super(parent);
 
         try {
-            mDexClass = parent.loadClass("dalvik/system/DexFile");
+            mDexClass = parent.loadClass("dalvik.system.DexFile");
         } catch (ClassNotFoundException cnfe) {
             // ignore -- not running Dalvik
         }
index e271001..ddb45af 100644 (file)
@@ -1,3 +1,6 @@
+Direct byte buffer has array: true
 Got expected buffer overflow exception
 Got expected out-of-bounds exception
 Got expected buffer overflow exception
+00fbfb2ec03000001234567840490fd01122334455667788000000000000000100000000
+ccfb2efb30c0cccc78563412d00f494088776655443322110100000000000000cccccccc
index bfcab3a..a7433b8 100644 (file)
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
 import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
+import java.nio.LongBuffer;
 import java.nio.ShortBuffer;
 
 public class Main {
     public static void main(String[] args) {
-         intFloatTest();
-         basicShortTest();
+        ByteBuffer buf = ByteBuffer.allocateDirect(16);
+        System.out.println("Direct byte buffer has array: " + buf.hasArray());
+
+        intFloatTest();
+        basicShortTest();
+        primTest();
     }
 
     /*
@@ -94,4 +101,77 @@ public class Main {
         int1.put (data);
         int1.position (0);
     }
+
+    /*
+     * Exercise all "view buffer" classes, in both byte orders.
+     */
+    public static void primTest() {
+        ByteBuffer directBuf = ByteBuffer.allocateDirect(36);
+        directBuf.order(ByteOrder.BIG_ENDIAN);
+        storeValues(directBuf);
+
+        for (int i = 0; i < 36; i++) {
+            directBuf.put(i, (byte) 0xcc);
+        }
+
+        directBuf.order(ByteOrder.LITTLE_ENDIAN);
+        storeValues(directBuf);
+    }
+
+    static void storeValues(ByteBuffer directBuf) {
+        directBuf.position(0);
+        ShortBuffer shortBuf = directBuf.asShortBuffer();
+        CharBuffer charBuf = directBuf.asCharBuffer();
+        IntBuffer intBuf = directBuf.asIntBuffer();
+        FloatBuffer floatBuf = directBuf.asFloatBuffer();
+        LongBuffer longBuf = directBuf.asLongBuffer();
+        DoubleBuffer doubleBuf = directBuf.asDoubleBuffer();
+
+        final byte byteValue = -5;
+        final short shortValue = -1234;
+        final char charValue = 49200;
+        final int intValue = 0x12345678;
+        final float floatValue = 3.14159f;
+        final long longValue = 0x1122334455667788L;
+        final double doubleValue = Double.MIN_VALUE;
+
+        if (directBuf.put(1, byteValue).get(1) != byteValue) {
+            throw new RuntimeException("byte get/store failed");
+        }
+        if (shortBuf.put(1, shortValue).get(1) != shortValue) {
+            throw new RuntimeException("short get/store failed");
+        }
+        if (charBuf.put(2, charValue).get(2) != charValue) {
+            throw new RuntimeException("char get/store failed");
+        }
+        if (intBuf.put(2, intValue).get(2) != intValue) {
+            throw new RuntimeException("int get/store failed");
+        }
+        if (floatBuf.put(3, floatValue).get(3) != floatValue) {
+            throw new RuntimeException("float get/store failed");
+        }
+        if (longBuf.put(2, longValue).get(2) != longValue) {
+            throw new RuntimeException("long get/store failed");
+        }
+        if (doubleBuf.put(3, doubleValue).get(3) != doubleValue) {
+            throw new RuntimeException("double get/store failed");
+        }
+
+        directBuf.position(0);
+        char[] outBuf = new char[directBuf.limit() * 2];
+        for (int i = 0; i < directBuf.limit(); i++) {
+            byte b = directBuf.get();
+            outBuf[i*2] = hexChar((byte) ((b >> 4) & 0x0f));
+            outBuf[i*2+1] = hexChar((byte) (b & 0x0f));
+        }
+        System.out.println(new String(outBuf));
+    }
+
+    static char hexChar(byte b) {
+        if (b < 10) {
+            return (char) ('0' + b);
+        } else {
+            return (char) ('a' + b - 10);
+        }
+    }
 }
index f777113..de28ed9 100644 (file)
@@ -76,8 +76,8 @@ public class Main {
 
     static class FieldThread extends Thread {
         public void run() {
-            /* allow class init to start */
-            Main.sleep(200);
+            /* allow SlowInit's <clinit> to start */
+            Main.sleep(1000);
 
             /* collect fields; should delay until class init completes */
             int field0, field1, field2, field3;
@@ -87,7 +87,7 @@ public class Main {
             field3 = SlowInit.FIELD3.getValue();
 
             /* let MethodThread print first */
-            Main.sleep(400);
+            Main.sleep(5000);
             System.out.println("Fields (child thread): " +
                 field0 + field1 + field2 + field3);
         }
@@ -95,8 +95,8 @@ public class Main {
 
     static class MethodThread extends Thread {
         public void run() {
-            /* allow class init to start */
-            Main.sleep(200);
+            /* allow SlowInit's <clinit> to start */
+            Main.sleep(1000);
 
             /* use a method that shouldn't be accessible yet */
             SlowInit.printMsg("MethodThread message");
index 8ac72be..f0c6919 100644 (file)
@@ -32,7 +32,7 @@ public class SlowInit {
         FIELD0.setValue(111);
         FIELD1.setValue(222);
         printMsg("SlowInit static block pre-sleep");
-        Main.sleep(600);
+        Main.sleep(4000);
         printMsg("SlowInit static block post-sleep");
         FIELD2.setValue(333);
         FIELD3.setValue(444);
index 6decb20..82237c5 100644 (file)
@@ -76,7 +76,7 @@ public class Main {
                  * through reflection, then call loadCLass on it.
                  */
                 Class mDexClass = ClassLoader.getSystemClassLoader().
-                        loadClass("dalvik/system/DexFile");
+                        loadClass("dalvik.system.DexFile");
                 Constructor ctor = mDexClass.
                         getConstructor(new Class[] {String.class});
                 Object mDexFile = ctor.newInstance(DEX_FILE);
index dc68f9f..11fb2d3 100644 (file)
@@ -79,7 +79,7 @@ public class Main {
                      * through reflection, then call loadClass on it.
                      */
                     dexClass = ClassLoader.getSystemClassLoader().
-                            loadClass("dalvik/system/DexFile");
+                            loadClass("dalvik.system.DexFile");
                     Constructor ctor = dexClass.
                             getConstructor(new Class[] {String.class});
                     dexFile = ctor.newInstance(DEX_FILE);
diff --git a/tests/091-deep-interface-hierarchy/expected.txt b/tests/091-deep-interface-hierarchy/expected.txt
new file mode 100644 (file)
index 0000000..33bcb02
--- /dev/null
@@ -0,0 +1 @@
+A new instance of Z was created successfully
diff --git a/tests/091-deep-interface-hierarchy/info.txt b/tests/091-deep-interface-hierarchy/info.txt
new file mode 100644 (file)
index 0000000..b62cec6
--- /dev/null
@@ -0,0 +1,4 @@
+Test class loading for deep interface hierarchies. The problem was that in a deep interface
+hierarchy super-interfaces were recursively concatenated without looking for duplicates.
+In cases like this can quickly lead to excessive LinearAlloc consumption due to more than linear
+duplication of iftables.
diff --git a/tests/091-deep-interface-hierarchy/src/Main.java b/tests/091-deep-interface-hierarchy/src/Main.java
new file mode 100644 (file)
index 0000000..8ab47f3
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/**
+ * Create a hierarchy of interfaces to check if that overflows the LinearAlloc
+ * with iftable entries.
+ */
+public class Main {
+    interface A1 {}
+    interface A2 {}
+    interface A3 {}
+    interface A4 {}
+    interface A5 {}
+
+    interface B1 extends A1, A2, A3, A4, A5 {}
+    interface B2 extends A1, A2, A3, A4, A5 {}
+    interface B3 extends A1, A2, A3, A4, A5 {}
+    interface B4 extends A1, A2, A3, A4, A5 {}
+    interface B5 extends A1, A2, A3, A4, A5 {}
+
+    interface C1 extends B1, B2, B3, B4, B5 {}
+    interface C2 extends B1, B2, B3, B4, B5 {}
+    interface C3 extends B1, B2, B3, B4, B5 {}
+    interface C4 extends B1, B2, B3, B4, B5 {}
+    interface C5 extends B1, B2, B3, B4, B5 {}
+
+    interface D1 extends C1, C2, C3, C4, C5 {}
+    interface D2 extends C1, C2, C3, C4, C5 {}
+    interface D3 extends C1, C2, C3, C4, C5 {}
+    interface D4 extends C1, C2, C3, C4, C5 {}
+    interface D5 extends C1, C2, C3, C4, C5 {}
+
+    interface E1 extends D1, D2, D3, D4, D5 {}
+    interface E2 extends D1, D2, D3, D4, D5 {}
+    interface E3 extends D1, D2, D3, D4, D5 {}
+    interface E4 extends D1, D2, D3, D4, D5 {}
+    interface E5 extends D1, D2, D3, D4, D5 {}
+
+    interface F1 extends E1, E2, E3, E4, E5 {}
+    interface F2 extends E1, E2, E3, E4, E5 {}
+    interface F3 extends E1, E2, E3, E4, E5 {}
+    interface F4 extends E1, E2, E3, E4, E5 {}
+    interface F5 extends E1, E2, E3, E4, E5 {}
+
+    interface G1 extends F1, F2, F3, F4, F5 {}
+    interface G2 extends F1, F2, F3, F4, F5 {}
+    interface G3 extends F1, F2, F3, F4, F5 {}
+    interface G4 extends F1, F2, F3, F4, F5 {}
+    interface G5 extends F1, F2, F3, F4, F5 {}
+
+    interface H1 extends G1, G2, G3, G4, G5 {}
+    interface H2 extends G1, G2, G3, G4, G5 {}
+    interface H3 extends G1, G2, G3, G4, G5 {}
+    interface H4 extends G1, G2, G3, G4, G5 {}
+    interface H5 extends G1, G2, G3, G4, G5 {}
+
+    interface Z extends H1, H2, H3, H4, H5 {}
+
+    public static void main(String[] args) {
+        Z instance = new Z() {};
+        System.out.println("A new instance of Z was created successfully");
+    }
+}
diff --git a/tests/092-locale/expected.txt b/tests/092-locale/expected.txt
new file mode 100644 (file)
index 0000000..0a955e7
--- /dev/null
@@ -0,0 +1,12 @@
+USA(GMT): Sunday, January 1, 2012
+USA: first=1, name=Sunday
+France(GMT): Monday, January 2, 2012
+France: first=2, name=lundi
+USA dfs: [AM, PM]
+en_US: USD $2
+jp_JP: JPY Â¥0
+Normalizer passed
+loc: en_US
+ iso3=eng
+loc: eng_USA
+ iso3=eng
diff --git a/tests/092-locale/info.txt b/tests/092-locale/info.txt
new file mode 100644 (file)
index 0000000..e3c3a98
--- /dev/null
@@ -0,0 +1 @@
+Exercise some locale-specific classes.
diff --git a/tests/092-locale/src/Main.java b/tests/092-locale/src/Main.java
new file mode 100644 (file)
index 0000000..8916a29
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.Normalizer;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Currency;
+import java.util.Date;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.TimeZone;
+
+/**
+ * Exercise some locale-table-driven stuff.
+ */
+public class Main {
+
+    public static void main(String[] args) {
+        try {
+            testCalendar();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        try {
+            testDateFormatSymbols();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        try {
+            testCurrency();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        try {
+            testNormalizer();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        try {
+            testIso3();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    static void testCalendar() {
+        TimeZone tz = TimeZone.getTimeZone("GMT");
+
+        Locale usa = new Locale("en", "US");
+        Calendar usaCal = Calendar.getInstance(tz, usa);
+        usaCal.clear();     // don't want current date/time
+        usaCal.set(2012, Calendar.JANUARY, 1);
+
+        Date when = usaCal.getTime();
+        DateFormat fmt = DateFormat.getDateInstance(DateFormat.FULL, usa);
+        fmt.setTimeZone(tz);    // defaults to local TZ; force GMT
+        System.out.println("USA(" + fmt.getTimeZone().getID() + "): "
+            + fmt.format(when));
+
+        System.out.println("USA: first="
+            + usaCal.getFirstDayOfWeek() + ", name="
+            + usaCal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, usa));
+
+
+        Locale france = new Locale("fr", "FR");
+        Calendar franceCal = Calendar.getInstance(tz, france);
+        franceCal.clear();
+        franceCal.set(2012, Calendar.JANUARY, 2);
+
+        when = franceCal.getTime();
+        fmt = DateFormat.getDateInstance(DateFormat.FULL, usa);
+        fmt.setTimeZone(tz);    // defaults to local TZ; force GMT
+        System.out.println("France(" + fmt.getTimeZone().getID() + "): "
+            + fmt.format(when));
+
+        System.out.println("France: first="
+            + franceCal.getFirstDayOfWeek() + ", name="
+            + franceCal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, france));
+    }
+
+    static void testDateFormatSymbols() {
+        Locale usa = new Locale("en", "US");
+        DateFormatSymbols syms = DateFormatSymbols.getInstance(usa);
+        String[] list = syms.getAmPmStrings();
+        System.out.println("USA dfs: " + Arrays.deepToString(list));
+    }
+
+    static void testCurrency() {
+        Locale usa = new Locale("en", "US");
+        Currency dollars = Currency.getInstance(usa);
+
+        System.out.println(usa.toString() + ": " + dollars.toString()
+            + " " + dollars.getSymbol() + dollars.getDefaultFractionDigits());
+
+        Locale japan = new Locale("jp", "JP");
+        Currency yen = Currency.getInstance(japan);
+
+        System.out.println(japan.toString() + ": " + yen.toString()
+            + " " + yen.getSymbol() + yen.getDefaultFractionDigits());
+    }
+
+    static void testNormalizer() {
+        String composed = "Bl\u00c1ah";
+        String decomposed = "Bl\u0041\u0301ah";
+        String res;
+
+        res = Normalizer.normalize(composed, Normalizer.Form.NFD);
+        if (!decomposed.equals(res)) {
+            System.err.println("Bad decompose: '" + composed + "' --> '"
+                + res + "'");
+        }
+
+        res = Normalizer.normalize(decomposed, Normalizer.Form.NFC);
+        if (!composed.equals(res)) {
+            System.err.println("Bad compose: '" + decomposed + "' --> '"
+                + res + "'");
+        }
+
+        System.out.println("Normalizer passed");
+    }
+
+    /*
+     * Test that we can set and get an ISO3 language code.  Support for this
+     * is expected by the Android framework.
+     */
+    static void testIso3() {
+        Locale loc;
+        loc = new Locale("en", "US");
+        System.out.println("loc: " + loc);
+        System.out.println(" iso3=" + loc.getISO3Language());
+
+        loc = new Locale("eng", "USA");
+        System.out.println("loc: " + loc);
+        try {
+            System.out.println(" iso3=" + loc.getISO3Language());
+        } catch (MissingResourceException mre) {
+            System.err.println("couldn't get iso3 language");
+        }
+    }
+}
diff --git a/tests/093-serialization/expected.txt b/tests/093-serialization/expected.txt
new file mode 100644 (file)
index 0000000..60c64f8
--- /dev/null
@@ -0,0 +1 @@
+one=true two=2 three=three four=4.0 five=5.0 six=6 seven=7 eight=8 nine=9 thing=X
diff --git a/tests/093-serialization/info.txt b/tests/093-serialization/info.txt
new file mode 100644 (file)
index 0000000..effe3d8
--- /dev/null
@@ -0,0 +1 @@
+Tests object serialization.
diff --git a/tests/093-serialization/src/Main.java b/tests/093-serialization/src/Main.java
new file mode 100644 (file)
index 0000000..ca3dc9f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/**
+ * Exercise serialization.
+ */
+public class Main {
+
+    public static void main(String[] args) {
+        testObjectSerialization();
+    }
+
+    static void testObjectSerialization() {
+        byte[] serialData;
+
+        try {
+            serialData = createStream();
+            checkStream(serialData);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    static byte[] createStream() throws IOException {
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        ObjectOutputStream objStream = new ObjectOutputStream(byteStream);
+
+        Sub sub = new Sub('X');
+        objStream.writeObject(sub);
+        byte[] bytes = byteStream.toByteArray();
+
+        objStream.close();
+        byteStream.close();
+        return bytes;
+    }
+
+    static void checkStream(byte[] input) throws IOException {
+        ByteArrayInputStream byteStream = new ByteArrayInputStream(input);
+        ObjectInputStream objStream = new ObjectInputStream(byteStream);
+
+        Sub sub;
+        try {
+            sub = (Sub) objStream.readObject();
+        } catch (ClassNotFoundException cnfe) {
+            throw new RuntimeException(cnfe);
+        }
+
+        objStream.close();
+        byteStream.close();
+
+        sub.check();
+    }
+}
+
+class Base implements Serializable {
+    private static final long serialVersionUID = 12345;
+
+    Boolean one;
+    Integer two;
+    String three;
+
+    public Base() {
+        one = true;
+        two = Integer.valueOf(2);
+        three = "three";
+    }
+}
+
+class Sub extends Base {
+    private static final long serialVersionUID = 54321;
+
+    Double four;
+    Float five;
+    private Byte six = 26;
+    Character seven = '7';
+    Short eight;
+    long nine;
+    public Character thing;
+
+    public Sub(char thing) {
+        four = 4.0;
+        five = 5.0f;
+        six = 6;
+        eight = 8;
+        nine = 9;
+        this.thing = thing;
+    }
+
+    public void check() {
+        System.out.println("one=" + one + " two=" + two + " three=" + three
+            + " four=" + four + " five=" + five + " six=" + six
+            + " seven=" + seven + " eight=" + eight + " nine=" + nine
+            + " thing=" + thing);
+    }
+}
+
diff --git a/tests/094-pattern/expected.txt b/tests/094-pattern/expected.txt
new file mode 100644 (file)
index 0000000..4af0c66
--- /dev/null
@@ -0,0 +1,3 @@
+str1 matches: true
+str2 matches: false
+str3 matches: true
diff --git a/tests/094-pattern/info.txt b/tests/094-pattern/info.txt
new file mode 100644 (file)
index 0000000..c1ade33
--- /dev/null
@@ -0,0 +1,4 @@
+A simple test to exercise pattern matching.
+
+The test may throw a StackOverflowError if the stack size is too small.  With
+some regex libs, -Xss65k is the minimum allowable size.
diff --git a/tests/094-pattern/src/Main.java b/tests/094-pattern/src/Main.java
new file mode 100644 (file)
index 0000000..4d7e1a3
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Main {
+    // from android.util.Patterns
+    public static final String GOOD_IRI_CHAR =
+        "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
+
+    public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL =
+        "(?:"
+        + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+        + "|(?:biz|b[abdefghijmnorstvwyz])"
+        + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
+        + "|d[ejkmoz]"
+        + "|(?:edu|e[cegrstu])"
+        + "|f[ijkmor]"
+        + "|(?:gov|g[abdefghilmnpqrstuwy])"
+        + "|h[kmnrtu]"
+        + "|(?:info|int|i[delmnoqrst])"
+        + "|(?:jobs|j[emop])"
+        + "|k[eghimnprwyz]"
+        + "|l[abcikrstuvy]"
+        + "|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])"
+        + "|(?:name|net|n[acefgilopruz])"
+        + "|(?:org|om)"
+        + "|(?:pro|p[aefghklmnrstwy])"
+        + "|qa"
+        + "|r[eosuw]"
+        + "|s[abcdeghijklmnortuvyz]"
+        + "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
+        + "|u[agksyz]"
+        + "|v[aceginu]"
+        + "|w[fs]"
+        + "|(?:\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)"
+        + "|y[et]"
+        + "|z[amw]))";
+
+    public static final String WEB_URL_STR =
+        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+        + "((?:(?:[" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]{0,64}\\.)+"   // named host
+        + TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL
+        + "|(?:(?:25[0-5]|2[0-4]" // or ip address
+        + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+        + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+        + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+        + "|[1-9][0-9]|[0-9])))"
+        + "(?:\\:\\d{1,5})?)" // plus option port number
+        + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
+        + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+        + "(?:\\b|$)"; // and finally, a word boundary or end of
+                        // input.  This is to stop foo.sure from
+                        // matching as foo.su
+
+    public static final Pattern WEB_URL = Pattern.compile(WEB_URL_STR);
+
+    public static final String testStr1 =
+        "http://www.google.com/blah?client=tablet-android&source=android-home";
+    public static final String testStr2 = "http:///www.google.com/";
+    public static final String testStr3 =
+        "http://www.google.com/search?hl=en&redir_esc=&client=tablet-android-verizon&source=android-browser-type&v=141000000&qsubts=1327020479959&action=devloc&q=cnn";
+
+    public static void main(String[] args) {
+        System.out.println("str1 matches: " + WEB_URL.matcher(testStr1).matches());
+        System.out.println("str2 matches: " + WEB_URL.matcher(testStr2).matches());
+        System.out.println("str3 matches: " + WEB_URL.matcher(testStr3).matches());
+    }
+
+    static String getStringAsHex(String text) {
+        StringBuilder sb = new StringBuilder(text.length() * 4);
+
+        for (int i = 0; i < text.length(); i++) {
+            sb.append(Integer.toHexString((int) text.charAt(i)));
+        }
+
+        return sb.toString();
+    }
+}
index 5a4e0e5..b54facd 100644 (file)
@@ -1264,20 +1264,15 @@ void dvmDbgOutputAllMethods(RefTypeId refTypeId, bool withGeneric,
 void dvmDbgOutputAllInterfaces(RefTypeId refTypeId, ExpandBuf* pReply)
 {
     ClassObject* clazz;
-    int i, start, count;
+    int i, count;
 
     clazz = refTypeIdToClassObject(refTypeId);
     assert(clazz != NULL);
 
-    if (clazz->super == NULL)
-        start = 0;
-    else
-        start = clazz->super->iftableCount;
-
-    count = clazz->iftableCount - start;
+    count = clazz->interfaceCount;
     expandBufAdd4BE(pReply, count);
-    for (i = start; i < clazz->iftableCount; i++) {
-        ClassObject* iface = clazz->iftable[i].clazz;
+    for (i = 0; i < count; i++) {
+        ClassObject* iface = clazz->interfaces[i];
         expandBufAddRefTypeId(pReply, classObjectToRefTypeId(iface));
     }
 }
index 85a3bbd..51600c9 100644 (file)
@@ -3071,53 +3071,48 @@ static bool createIftable(ClassObject* clazz)
 
         /* add entries for the interface's superinterfaces */
         for (int j = 0; j < interf->iftableCount; j++) {
-            clazz->iftable[idx++].clazz = interf->iftable[j].clazz;
+            int k;
+            ClassObject *cand;
+
+            cand = interf->iftable[j].clazz;
+
+            /*
+             * Check if this interface was already added and add only if new.
+             * This is to avoid a potential blowup in the number of
+             * interfaces for sufficiently complicated interface hierarchies.
+             * This has quadratic runtime in the number of interfaces.
+             * However, in common cases with little interface inheritance, this
+             * doesn't make much of a difference.
+             */
+            for (k = 0; k < idx; k++)
+                if (clazz->iftable[k].clazz == cand)
+                    break;
+
+            if (k == idx)
+                clazz->iftable[idx++].clazz = cand;
         }
     }
 
-    assert(idx == ifCount);
+    assert(idx <= ifCount);
 
+    /*
+     * Adjust the ifCount. We could reallocate the interface memory here,
+     * but it's probably not worth the effort, the important thing here
+     * is to avoid the interface blowup and keep the ifCount low.
+     */
     if (false) {
-        /*
-         * Remove anything redundant from our recent additions.  Note we have
-         * to traverse the recent adds when looking for duplicates, because
-         * it's possible the recent additions are self-redundant.  This
-         * reduces the memory footprint of classes with lots of inherited
-         * interfaces.
-         *
-         * (I don't know if this will cause problems later on when we're trying
-         * to find a static field.  It looks like the proper search order is
-         * (1) current class, (2) interfaces implemented by current class,
-         * (3) repeat with superclass.  A field implemented by an interface
-         * and by a superclass might come out wrong if the superclass also
-         * implements the interface.  The javac compiler will reject the
-         * situation as ambiguous, so the concern is somewhat artificial.)
-         *
-         * UPDATE: this makes ReferenceType.Interfaces difficult to implement,
-         * because it wants to return just the interfaces declared to be
-         * implemented directly by the class.  I'm excluding this code for now.
-         */
-        for (int i = superIfCount; i < ifCount; i++) {
-            for (int j = 0; j < ifCount; j++) {
-                if (i == j)
-                    continue;
-                if (clazz->iftable[i].clazz == clazz->iftable[j].clazz) {
-                    LOGVV("INTF: redundant interface %s in %s",
-                        clazz->iftable[i].clazz->descriptor,
-                        clazz->descriptor);
-
-                    if (i != ifCount-1)
-                        memmove(&clazz->iftable[i], &clazz->iftable[i+1],
-                            (ifCount - i -1) * sizeof(InterfaceEntry));
-                    ifCount--;
-                    i--;        // adjust for i++ above
-                    break;
-                }
-            }
+        if (idx != ifCount) {
+            int newIfCount = idx;
+            InterfaceEntry* oldmem = clazz->iftable;
+
+            clazz->iftable = (InterfaceEntry*) dvmLinearAlloc(clazz->classLoader,
+                            sizeof(InterfaceEntry) * newIfCount);
+            memcpy(clazz->iftable, oldmem, sizeof(InterfaceEntry) * newIfCount);
+            dvmLinearFree(clazz->classLoader, oldmem);
         }
-        LOGVV("INTF: class '%s' nodupes=%d", clazz->descriptor, ifCount);
-    } // if (false)
+    }
 
+    ifCount = idx;
     clazz->iftableCount = ifCount;
 
     /*