OSDN Git Service

Merge change I909ce240
authorAndroid (Google) Code Review <android-gerrit@google.com>
Fri, 11 Dec 2009 15:27:44 +0000 (07:27 -0800)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Fri, 11 Dec 2009 15:27:44 +0000 (07:27 -0800)
* changes:
  Iterate in JNI thread exit check.

27 files changed:
dx/src/com/android/dx/Version.java
dx/src/com/android/dx/cf/code/Ropper.java
dx/tests/062-dex-synch-method/Blort.java
dx/tests/062-dex-synch-method/expected.txt
libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
libcore/luni/src/main/java/java/io/File.java
libcore/luni/src/main/java/java/util/Formatter.java
libcore/luni/src/main/native/java_io_File.cpp
libcore/text/src/main/java/java/text/NumberFormat.java
libcore/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java
libcore/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java
libcore/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
libcore/xml/src/test/java/org/apache/harmony/xml/ExpatParserTest.java
tests/063-process-manager/src/Main.java
vm/alloc/MarkSweep.c
vm/compiler/template/armv5te-vfp/platform.S [new file with mode: 0644]
vm/compiler/template/armv5te/platform.S
vm/compiler/template/config-armv5te-vfp
vm/compiler/template/config-armv7-a
vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
vm/interp/Interp.c
vm/interp/InterpDefs.h
vm/mterp/common/asm-constants.h
vm/oo/Array.c
vm/oo/Object.h

index 4950d39..e0427a8 100644 (file)
@@ -21,5 +21,5 @@ package com.android.dx;
  */
 public class Version {
     /** {@code non-null;} version string */
-    public static final String VERSION = "1.3";
+    public static final String VERSION = "1.4";
 }
index 6e8c328..8217166 100644 (file)
@@ -53,13 +53,13 @@ public final class Ropper {
 
     /**
      * label offset for the first synchronized method exception
-     * handler block 
+     * handler block
      */
     private static final int SYNCH_CATCH_1 = -6;
 
     /**
      * label offset for the second synchronized method exception
-     * handler block 
+     * handler block
      */
     private static final int SYNCH_CATCH_2 = -7;
 
@@ -85,8 +85,8 @@ public final class Ropper {
     private final Simulator sim;
 
     /**
-     * {@code non-null;} sparse array mapping block labels to initial frame contents,
-     * if known 
+     * {@code non-null;} sparse array mapping block labels to initial frame
+     * contents, if known
      */
     private final Frame[] startFrames;
 
@@ -96,24 +96,26 @@ public final class Ropper {
     /**
      * {@code non-null;} list of subroutine-nest labels
      * (See {@link Frame#getSubroutines} associated with each result block.
-     * Parallel to {@link Ropper#result}. 
+     * Parallel to {@link Ropper#result}.
      */
     private final ArrayList<IntList> resultSubroutines;
 
     /**
      * {@code non-null;} for each block (by label) that is used as an exception
-     * handler, the type of exception it catches 
+     * handler, the type of exception it catches
      */
     private final Type[] catchTypes;
 
     /**
      * whether an exception-handler block for a synchronized method was
-     * ever required 
+     * ever required
      */
     private boolean synchNeedsExceptionHandler;
 
-    /** {@code non-null;} list of subroutines indexed by label of start address */
-    private final Subroutine subroutines[];
+    /**
+     * {@code non-null;} list of subroutines indexed by label of start
+     * address */
+    private final Subroutine[] subroutines;
 
     /** true if {@code subroutines} is non-empty */
     private boolean hasSubroutines;
@@ -164,7 +166,7 @@ public final class Ropper {
         /**
          * Adds a label to the list of ret blocks (final blocks) for this
          * subroutine.
-         * 
+         *
          * @param retBlock ret block label
          */
         void addRetBlock(int retBlock) {
@@ -186,7 +188,7 @@ public final class Ropper {
          * list (and the block it's associated with) will be copied and inlined
          * before we leave the ropper. Redundent successors will result in
          * redundent (no-op) merges.
-         * 
+         *
          * @return all currently known successors
          * (return destinations) for that subroutine
          */
@@ -206,7 +208,7 @@ public final class Ropper {
             }
 
             successors.setImmutable();
-           
+
             return successors;
         }
 
@@ -238,7 +240,7 @@ public final class Ropper {
 
     /**
      * Converts a {@link ConcreteMethod} to a {@link RopMethod}.
-     * 
+     *
      * @param method {@code non-null;} method to convert
      * @param advice {@code non-null;} translation advice to use
      * @return {@code non-null;} the converted instance
@@ -259,7 +261,7 @@ public final class Ropper {
     /**
      * Constructs an instance. This class is not publicly instantiable; use
      * {@link #convert}.
-     * 
+     *
      * @param method {@code non-null;} method to convert
      * @param advice {@code non-null;} translation advice to use
      */
@@ -288,7 +290,8 @@ public final class Ropper {
          * the underlying array is unlikely to need resizing.
          */
         this.result = new ArrayList<BasicBlock>(blocks.size() * 2 + 10);
-        this.resultSubroutines = new ArrayList<IntList>(blocks.size() * 2 + 10);
+        this.resultSubroutines =
+            new ArrayList<IntList>(blocks.size() * 2 + 10);
 
         this.catchTypes = new Type[maxLabel];
         this.synchNeedsExceptionHandler = false;
@@ -303,7 +306,7 @@ public final class Ropper {
     /**
      * Gets the first (lowest) register number to use as the temporary
      * area when unwinding stack manipulation ops.
-     * 
+     *
      * @return {@code >= 0;} the first register to use
      */
     /*package*/ int getFirstTempStackReg() {
@@ -322,7 +325,7 @@ public final class Ropper {
     /**
      * Gets the label for the exception handler setup block corresponding
      * to the given label.
-     * 
+     *
      * @param label {@code >= 0;} the original label
      * @return {@code >= 0;} the corresponding exception handler setup label
      */
@@ -333,7 +336,7 @@ public final class Ropper {
     /**
      * Gets the label for the given special-purpose block. The given label
      * should be one of the static constants defined by this class.
-     * 
+     *
      * @param label {@code < 0;} the special label constant
      * @return {@code >= 0;} the actual label value to use
      */
@@ -352,7 +355,7 @@ public final class Ropper {
 
     /**
      * Gets the minimum label for unreserved use.
-     * 
+     *
      * @return {@code >= 0;} the minimum label
      */
     private int getMinimumUnreservedLabel() {
@@ -366,7 +369,7 @@ public final class Ropper {
 
     /**
      * Gets an arbitrary unreserved and available label.
-     * 
+     *
      * @return {@code >= 0;} the label
      */
     private int getAvailableLabel() {
@@ -384,7 +387,7 @@ public final class Ropper {
 
     /**
      * Gets whether the method being translated is synchronized.
-     * 
+     *
      * @return whether the method being translated is synchronized
      */
     private boolean isSynchronized() {
@@ -394,7 +397,7 @@ public final class Ropper {
 
     /**
      * Gets whether the method being translated is static.
-     * 
+     *
      * @return whether the method being translated is static
      */
     private boolean isStatic() {
@@ -405,7 +408,7 @@ public final class Ropper {
     /**
      * Gets the total number of registers used for "normal" purposes (i.e.,
      * for the straightforward translation from the original Java).
-     * 
+     *
      * @return {@code >= 0;} the total number of registers used
      */
     private int getNormalRegCount() {
@@ -415,23 +418,26 @@ public final class Ropper {
     /**
      * Gets the register spec to use to hold the object to synchronize on,
      * for a synchronized method.
-     * 
+     *
      * @return {@code non-null;} the register spec
      */
     private RegisterSpec getSynchReg() {
         /*
          * We use the register that is just past the deepest possible
-         * stack element. We don't need to do anything else special at
-         * this level, since later passes will merely notice the
-         * highest register used by explicit inspection.
+         * stack element, with a minimum of v1 since v0 is what's
+         * always used to hold the caught exception when unwinding. We
+         * don't need to do anything else special at this level, since
+         * later passes will merely notice the highest register used
+         * by explicit inspection.
          */
-        return RegisterSpec.make(getNormalRegCount(), Type.OBJECT);
+        int reg = getNormalRegCount();
+        return RegisterSpec.make((reg < 1) ? 1 : reg, Type.OBJECT);
     }
 
     /**
-     * Searches {@link #result} for a block with the given label. Return its
-     * index if found, or return {@code -1} if there is no such block.
-     * 
+     * Searches {@link #result} for a block with the given label. Returns its
+     * index if found, or returns {@code -1} if there is no such block.
+     *
      * @param label the label to look for
      * @return {@code >= -1;} the index for the block with the given label or
      * {@code -1} if there is no such block
@@ -446,12 +452,12 @@ public final class Ropper {
         }
 
         return -1;
-    }        
+    }
 
     /**
-     * Searches {@link #result} for a block with the given label. Return it if
-     * found, or throw an exception if there is no such block.
-     * 
+     * Searches {@link #result} for a block with the given label. Returns it if
+     * found, or throws an exception if there is no such block.
+     *
      * @param label the label to look for
      * @return {@code non-null;} the block with the given label
      */
@@ -468,10 +474,10 @@ public final class Ropper {
 
     /**
      * Adds a block to the output result.
-     * 
+     *
      * @param block {@code non-null;} the block to add
-     * @param subroutines {@code non-null;} subroutine label list as described in
-     * {@link Frame#getSubroutines}
+     * @param subroutines {@code non-null;} subroutine label list
+     * as described in {@link Frame#getSubroutines}
      */
     private void addBlock(BasicBlock block, IntList subroutines) {
         if (block == null) {
@@ -487,10 +493,10 @@ public final class Ropper {
      * Adds or replace a block in the output result. If this is a
      * replacement, then any extra blocks that got added with the
      * original get removed as a result of calling this method.
-     * 
+     *
      * @param block {@code non-null;} the block to add or replace
-     * @param subroutines {@code non-null;} subroutine label list as described in
-     * {@link Frame#getSubroutines}
+     * @param subroutines {@code non-null;} subroutine label list
+     * as described in {@link Frame#getSubroutines}
      * @return {@code true} if the block was replaced or
      * {@code false} if it was added for the first time
      */
@@ -527,8 +533,8 @@ public final class Ropper {
      * any successors.
      *
      * @param block {@code non-null;} the block to add or replace
-     * @param subroutines {@code non-null;} subroutine label list as described in
-     * {@link Frame#getSubroutines}
+     * @param subroutines {@code non-null;} subroutine label list
+     * as described in {@link Frame#getSubroutines}
      * @return {@code true} if the block was replaced or
      * {@code false} if it was added for the first time
      */
@@ -560,7 +566,7 @@ public final class Ropper {
      * the given block and all blocks that are (direct and indirect)
      * successors of it whose labels indicate that they are not in the
      * normally-translated range.
-     * 
+     *
      * @param idx {@code non-null;} block to remove (etc.)
      */
     private void removeBlockAndSpecialSuccessors(int idx) {
@@ -587,7 +593,7 @@ public final class Ropper {
 
     /**
      * Extracts the resulting {@link RopMethod} from the instance.
-     * 
+     *
      * @return {@code non-null;} the method object
      */
     private RopMethod getRopMethod() {
@@ -659,11 +665,11 @@ public final class Ropper {
 
     /**
      * Processes the given block.
-     * 
+     *
      * @param block {@code non-null;} block to process
      * @param frame {@code non-null;} start frame for the block
-     * @param workSet {@code non-null;} bits representing work to do, which this
-     * method may add to
+     * @param workSet {@code non-null;} bits representing work to do,
+     * which this method may add to
      */
     private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
         // Prepare the list of caught exceptions for this block.
@@ -703,9 +709,10 @@ public final class Ropper {
             int subroutineLabel = successors.get(1);
 
             if (subroutines[subroutineLabel] == null) {
-                subroutines[subroutineLabel] = new Subroutine (subroutineLabel);
+                subroutines[subroutineLabel] =
+                    new Subroutine (subroutineLabel);
             }
-            
+
             subroutines[subroutineLabel].addCallerBlock(block.getLabel());
 
             calledSubroutine = subroutines[subroutineLabel];
@@ -907,7 +914,7 @@ public final class Ropper {
             successors.setImmutable();
             primarySucc = label;
         }
-        
+
         Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
 
         /*
@@ -926,7 +933,7 @@ public final class Ropper {
                                     RegisterSpecList.EMPTY));
             insnSz++;
         }
-        
+
         /*
          * Construct a block for the remaining instructions (which in
          * the usual case is all of them).
@@ -946,7 +953,7 @@ public final class Ropper {
     /**
      * Helper for {@link #processBlock}, which merges frames and
      * adds to the work set, as necessary.
-     * 
+     *
      * @param label {@code >= 0;} label to work on
      * @param pred  predecessor label; must be {@code >= 0} when
      * {@code label} is a subroutine start block and calledSubroutine
@@ -954,8 +961,8 @@ public final class Ropper {
      * @param calledSubroutine {@code null-ok;} a Subroutine instance if
      * {@code label} is the first block in a subroutine.
      * @param frame {@code non-null;} new frame for the labelled block
-     * @param workSet {@code non-null;} bits representing work to do, which this
-     * method may add to
+     * @param workSet {@code non-null;} bits representing work to do,
+     * which this method may add to
      */
     private void mergeAndWorkAsNecessary(int label, int pred,
             Subroutine calledSubroutine, Frame frame, int[] workSet) {
@@ -1007,7 +1014,8 @@ public final class Ropper {
 
         for (int i = 0; i < sz; i++) {
             Type one = params.get(i);
-            LocalVariableList.Item local = localVariables.pcAndIndexToLocal(0, at);
+            LocalVariableList.Item local =
+                localVariables.pcAndIndexToLocal(0, at);
             RegisterSpec result = (local == null) ?
                 RegisterSpec.make(at, one) :
                 RegisterSpec.makeLocalOptional(at, one, local.getLocalItem());
@@ -1019,7 +1027,7 @@ public final class Ropper {
             at += one.getCategory();
         }
 
-        insns.set(sz, new PlainInsn(Rops.GOTO, pos, null, 
+        insns.set(sz, new PlainInsn(Rops.GOTO, pos, null,
                                     RegisterSpecList.EMPTY));
         insns.setImmutable();
 
@@ -1228,7 +1236,7 @@ public final class Ropper {
     }
 
     /**
-     * Inlines any subroutine calls
+     * Inlines any subroutine calls.
      */
     private void inlineSubroutines() {
         final IntList reachableSubroutineCallerLabels = new IntList(4);
@@ -1237,7 +1245,7 @@ public final class Ropper {
          * Compile a list of all subroutine calls reachable
          * through the normal (non-subroutine) flow.  We do this first, since
          * we'll be affecting the call flow as we go.
-         * 
+         *
          * Start at label 0 --  the param assignment block has nothing for us
          */
         forEachNonSubBlockDepthFirst(0, new BasicBlock.Visitor() {
@@ -1269,14 +1277,15 @@ public final class Ropper {
         }
 
         /*
-        * Inline all reachable subroutines.
-        * Inner subroutines will be inlined as they are encountered.
-        */
+         * Inline all reachable subroutines.
+         * Inner subroutines will be inlined as they are encountered.
+         */
         int sz = reachableSubroutineCallerLabels.size();
         for (int i = 0 ; i < sz ; i++) {
             int label = reachableSubroutineCallerLabels.get(i);
             new SubroutineInliner(
-                    new LabelAllocator(getAvailableLabel()), labelToSubroutines)
+                    new LabelAllocator(getAvailableLabel()),
+                    labelToSubroutines)
                     .inlineSubroutineCalledFrom(labelToBlock(label));
         }
 
@@ -1337,25 +1346,25 @@ public final class Ropper {
 
     /**
      * Inlines a subroutine. Start by calling
-     * {@code inlineSubroutineCalledFrom}.
+     * {@link #inlineSubroutineCalledFrom}.
      */
     private class SubroutineInliner {
         /**
-         * maps original label to the label
-         * that will be used by the inlined version
+         * maps original label to the label that will be used by the
+         * inlined version
          */
         private final HashMap<Integer, Integer> origLabelToCopiedLabel;
 
-        /** Set of original labels that need to be copied. */
+        /** set of original labels that need to be copied */
         private final BitSet workList;
 
-        /** The label of the original start block for this subroutine. */
+        /** the label of the original start block for this subroutine */
         private int subroutineStart;
 
-        /** The label of the ultimate return block. */
+        /** the label of the ultimate return block */
         private int subroutineSuccessor;
 
-        /** Used for generating new labels for copied blocks. */
+        /** used for generating new labels for copied blocks */
         private final LabelAllocator labelAllocator;
 
         /**
@@ -1377,11 +1386,10 @@ public final class Ropper {
 
         /**
          * Inlines a subroutine.
-         * 
-         * @param b block where jsr occurred in the original bytecode
+         *
+         * @param b block where {@code jsr} occurred in the original bytecode
          */
         void inlineSubroutineCalledFrom(final BasicBlock b) {
-
             /*
              * The 0th successor of a subroutine caller block is where
              * the subroutine should return to. The 1st successor is
@@ -1423,6 +1431,7 @@ public final class Ropper {
 
         /**
          * Copies a basic block, mapping its successors along the way.
+         *
          * @param origLabel original block label
          * @param newLabel label that the new block should have
          */
@@ -1500,9 +1509,9 @@ public final class Ropper {
          * subroutine.
          *
          * @param label {@code >= 0;} a basic block label
-         * @param subroutineStart {@code >= 0;} a subroutine as identified by the
-         * label of its start block.
-         * @return true if the block is dominated by the subroutine call.
+         * @param subroutineStart {@code >= 0;} a subroutine as identified
+         * by the label of its start block
+         * @return true if the block is dominated by the subroutine call
          */
         private boolean involvedInSubroutine(int label, int subroutineStart) {
             IntList subroutinesList = labelToSubroutines.get(label);
@@ -1551,10 +1560,12 @@ public final class Ropper {
     }
 
     /**
-     * Finds a {@code Subroutine} that is returned from by a ret in
+     * Finds a {@code Subroutine} that is returned from by a {@code ret} in
      * a given block.
-     * @param label A block that originally contained a ret instruction
-     * @return {@code null-ok;} Subroutine or null if none was found.
+     *
+     * @param label A block that originally contained a {@code ret} instruction
+     * @return {@code null-ok;} found subroutine or {@code null} if none
+     * was found
      */
     private Subroutine subroutineFromRetBlock(int label) {
         for (int i = subroutines.length - 1 ; i >= 0 ; i--) {
@@ -1572,12 +1583,13 @@ public final class Ropper {
 
 
     /**
-     * Removes all move-return-address instructions, returning a new InsnList
-     * if necessary.  The move-return-address insns are dead code after
-     * subroutines have been inlined.
+     * Removes all {@code move-return-address} instructions, returning a new
+     * {@code InsnList} if necessary. The {@code move-return-address}
+     * insns are dead code after subroutines have been inlined.
      *
-     * @param insns InsnList that may contain move-return-address insns
-     * @return InsnList with move-return-address removed.
+     * @param insns {@code InsnList} that may contain
+     * {@code move-return-address} insns
+     * @return {@code InsnList} with {@code move-return-address} removed
      */
     private InsnList filterMoveReturnAddressInsns(InsnList insns) {
         int sz;
@@ -1612,34 +1624,33 @@ public final class Ropper {
 
     /**
      * Visits each non-subroutine block once in depth-first successor order.
+     *
      * @param firstLabel label of start block
      * @param v callback interface
      */
-    private void forEachNonSubBlockDepthFirst(
-            int firstLabel, BasicBlock.Visitor v) {
-
+    private void forEachNonSubBlockDepthFirst(int firstLabel,
+            BasicBlock.Visitor v) {
         forEachNonSubBlockDepthFirst0(labelToBlock(firstLabel),
                 v, new BitSet(maxLabel));
     }
 
     /**
-     * Visits each block once in depth-first successor order, ignoring jsr
-     * targets.  Worker for forEachNonSubBlockDepthFirst().
+     * Visits each block once in depth-first successor order, ignoring
+     * {@code jsr} targets. Worker for {@link #forEachNonSubBlockDepthFirst}.
+     *
      * @param next next block to visit
      * @param v callback interface
      * @param visited set of blocks already visited
      */
     private void forEachNonSubBlockDepthFirst0(
             BasicBlock next, BasicBlock.Visitor v, BitSet visited) {
-
         v.visitBlock(next);
         visited.set(next.getLabel());
 
         IntList successors = next.getSuccessors();
-
         int sz = successors.size();
 
-        for (int i = 0 ; i < sz ; i++) {
+        for (int i = 0; i < sz; i++) {
             int succ = successors.get(i);
 
             if (visited.get(succ)) {
index 643165d..823c2ca 100644 (file)
@@ -40,6 +40,10 @@ public class Blort
         }
     }
 
+    public synchronized void testInstance5() {
+        testInstance5();
+    }
+
     public static synchronized void testStatic1() {
         // This space intentionally left blank.
     }
@@ -63,4 +67,8 @@ public class Blort
             return 2;
         }
     }
+
+    public static synchronized void testStatic5() {
+        testStatic5();
+    }
 }
index 68bdebe..5585038 100644 (file)
@@ -58,11 +58,27 @@ regs: 000b; ins: 0003; outs: 0000
   0010: const-wide/16 v3, #long 2 // #0002
   0012: move-wide v0, v3
   0013: goto 000e // -0005
+Blort.testInstance5:()V:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move-object v0, v3
+  0001: move-object v2, v3
+  0002: monitor-enter v2
+  0003: move-object v1, v0
+  0004: invoke-virtual {v1}, Blort.testInstance5:()V
+  0007: monitor-exit v2
+  0008: return-void
+  0009: move-exception v0
+  000a: monitor-exit v2
+  000b: throw v0
+  catches
+    tries:
+      try 0004..0007
+      catch <any> -> 0009
 Blort.testStatic1:()V:
-regs: 0001; ins: 0000; outs: 0000
-  0000: const-class v0, Blort
-  0002: monitor-enter v0
-  0003: monitor-exit v0
+regs: 0002; ins: 0000; outs: 0000
+  0000: const-class v1, Blort
+  0002: monitor-enter v1
+  0003: monitor-exit v1
   0004: return-void
 Blort.testStatic2:(Ljava/lang/Object;)V:
 regs: 0004; ins: 0001; outs: 0001
@@ -114,3 +130,17 @@ regs: 0009; ins: 0002; outs: 0000
   0010: const-wide/16 v2, #long 2 // #0002
   0012: move-wide v0, v2
   0013: goto 000e // -0005
+Blort.testStatic5:()V:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const-class v1, Blort
+  0002: monitor-enter v1
+  0003: invoke-static {}, Blort.testStatic5:()V
+  0006: monitor-exit v1
+  0007: return-void
+  0008: move-exception v0
+  0009: monitor-exit v1
+  000a: throw v0
+  catches
+    tries:
+      try 0003..0006
+      catch <any> -> 0008
index 104336e..81c7578 100644 (file)
@@ -135,24 +135,20 @@ public class DecimalFormat extends NumberFormat {
 
     @Override
     public StringBuffer format(Object value, StringBuffer buffer, FieldPosition field) {
-
-        if(!(value instanceof Number)) {
+        if (!(value instanceof Number)) {
             throw new IllegalArgumentException();
         }
-        if(buffer == null || field == null) {
+        if (buffer == null || field == null) {
             throw new NullPointerException();
         }
-
         String fieldType = getFieldType(field.getFieldAttribute());
-
         Number number = (Number) value;
-
-        if(number instanceof BigInteger) {
+        if (number instanceof BigInteger) {
             BigInteger valBigInteger = (BigInteger) number;
-            String result = NativeDecimalFormat.format(this.addr,
-                    valBigInteger.toString(10), field, fieldType, null, 0);
+            String result = NativeDecimalFormat.format(this.addr, valBigInteger.toString(10),
+                    field, fieldType, null, 0);
             return buffer.append(result);
-        } else if(number instanceof BigDecimal) {
+        } else if (number instanceof BigDecimal) {
             BigDecimal valBigDecimal = (BigDecimal) number;
             if (getMultiplier() != 1) {
                 valBigDecimal = applyMultiplier(valBigDecimal);
@@ -161,54 +157,39 @@ public class DecimalFormat extends NumberFormat {
             val.append(valBigDecimal.unscaledValue().toString(10));
             int scale = valBigDecimal.scale();
             scale = makeScalePositive(scale, val);
-            String result = NativeDecimalFormat.format(this.addr,
-                    val.toString(), field, fieldType, null, scale);
+            String result = NativeDecimalFormat.format(this.addr, val.toString(),
+                    field, fieldType, null, scale);
             return buffer.append(result);
-        } else {
+        } else if (number instanceof Double || number instanceof Float) {
             double dv = number.doubleValue();
+            String result = NativeDecimalFormat.format(this.addr, dv, field, fieldType, null);
+            return buffer.append(result);
+        } else {
             long lv = number.longValue();
-            if (dv == lv) {
-                String result = NativeDecimalFormat.format(this.addr, lv, field,
-                        fieldType, null);
-                return buffer.append(result);
-            }
-            String result = NativeDecimalFormat.format(this.addr, dv, field,
-                    fieldType, null);
+            String result = NativeDecimalFormat.format(this.addr, lv, field, fieldType, null);
             return buffer.append(result);
         }
     }
 
     @Override
     public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
-
-        if(buffer == null || field == null) {
+        if (buffer == null || field == null) {
             throw new NullPointerException();
         }
-
         String fieldType = getFieldType(field.getFieldAttribute());
-
-        String result = NativeDecimalFormat.format(this.addr, value, field,
-                fieldType, null);
-
+        String result = NativeDecimalFormat.format(this.addr, value, field, fieldType, null);
         buffer.append(result.toCharArray(), 0, result.length());
-
         return buffer;
     }
 
     @Override
     public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) {
-
-        if(buffer == null || field == null) {
+        if (buffer == null || field == null) {
             throw new NullPointerException();
         }
-
         String fieldType = getFieldType(field.getFieldAttribute());
-
-        String result = NativeDecimalFormat.format(this.addr, value, field,
-                fieldType, null);
-
+        String result = NativeDecimalFormat.format(this.addr, value, field, fieldType, null);
         buffer.append(result.toCharArray(), 0, result.length());
-
         return buffer;
     }
 
index 62ca603..553206d 100644 (file)
@@ -948,28 +948,13 @@ public class File implements Serializable, Comparable<File> {
         if (security != null) {
             security.checkRead(path);
         }
-
         if (path.length() == 0) {
             return null;
         }
-
-        // TODO: rewrite the JNI so the rest of this method is just "return listImpl(pathBytes);"
-        if (!isDirectoryImpl(pathBytes) || !existsImpl(pathBytes) || !isReadableImpl(pathBytes)) {
-            return null;
-        }
-        byte[][] implList = listImpl(pathBytes);
-        if (implList == null) {
-            // empty list
-            return new String[0];
-        }
-        String[] result = new String[implList.length];
-        for (int index = 0; index < implList.length; index++) {
-            result[index] = Util.toUTF8String(implList[index]);
-        }
-        return result;
+        return listImpl(pathBytes);
     }
 
-    private synchronized static native byte[][] listImpl(byte[] path);
+    private native String[] listImpl(byte[] path);
 
     /**
      * Gets a list of the files in the directory represented by this file. This
index 071995c..0b92a87 100644 (file)
@@ -1777,9 +1777,7 @@ public final class Formatter implements Closeable, Flushable {
 
             if ('d' == currentConversionType) {
                 NumberFormat numberFormat = getNumberFormat();
-                boolean readableName = formatToken
-                        .isFlagSet(FormatToken.FLAG_COMMA);
-                numberFormat.setGroupingUsed(readableName);
+                numberFormat.setGroupingUsed(formatToken.isFlagSet(FormatToken.FLAG_COMMA));
                 result.append(numberFormat.format(bigInt));
             } else if ('o' == currentConversionType) {
                 // convert BigInteger to a string presentation using radix 8
@@ -1884,16 +1882,15 @@ public final class Formatter implements Closeable, Flushable {
                 return specialNumberResult;
             }
 
-            if ('a' != Character.toLowerCase(currentConversionType)) {
-                formatToken
-                        .setPrecision(formatToken.isPrecisionSet() ? formatToken
-                                .getPrecision()
-                                : FormatToken.DEFAULT_PRECISION);
+            if (Character.toLowerCase(currentConversionType) != 'a' &&
+                    !formatToken.isPrecisionSet()) {
+                formatToken.setPrecision(FormatToken.DEFAULT_PRECISION);
             }
+
             // output result
             FloatUtil floatUtil = new FloatUtil(result, formatToken,
                     (DecimalFormat) getNumberFormat(), arg);
-            floatUtil.transform(formatToken, result);
+            floatUtil.transform();
 
             formatToken.setPrecision(FormatToken.UNSET);
 
@@ -1979,15 +1976,15 @@ public final class Formatter implements Closeable, Flushable {
     }
 
     private static class FloatUtil {
-        private StringBuilder result;
+        private final StringBuilder result;
 
-        private DecimalFormat decimalFormat;
+        private final DecimalFormat decimalFormat;
 
-        private FormatToken formatToken;
+        private final FormatToken formatToken;
 
-        private Object argument;
+        private final Object argument;
 
-        private char minusSign;
+        private final char minusSign;
 
         FloatUtil(StringBuilder result, FormatToken formatToken,
                 DecimalFormat decimalFormat, Object argument) {
@@ -1995,13 +1992,10 @@ public final class Formatter implements Closeable, Flushable {
             this.formatToken = formatToken;
             this.decimalFormat = decimalFormat;
             this.argument = argument;
-            this.minusSign = decimalFormat.getDecimalFormatSymbols()
-                    .getMinusSign();
+            this.minusSign = decimalFormat.getDecimalFormatSymbols().getMinusSign();
         }
 
-        void transform(FormatToken aFormatToken, StringBuilder aResult) {
-            this.result = aResult;
-            this.formatToken = aFormatToken;
+        void transform() {
             switch (formatToken.getConversionType()) {
                 case 'e':
                 case 'E': {
index 905eae2..ed25ce7 100644 (file)
@@ -171,103 +171,143 @@ static jboolean java_io_File_setReadOnlyImpl(JNIEnv* env, jobject recv, jbyteArr
     return (chmod(&path[0], sb.st_mode & ~0222) == 0);
 }
 
-struct ScopedReaddir {
-    ScopedReaddir(DIR* dirp) : dirp(dirp) {
+// Iterates over the filenames in the given directory.
+class ScopedReaddir {
+public:
+    ScopedReaddir(const char* path) {
+        mDirStream = opendir(path);
+        mIsBad = (mDirStream == NULL);
     }
+
     ~ScopedReaddir() {
-        if (dirp != NULL) {
-            closedir(dirp);
+        if (mDirStream != NULL) {
+            closedir(mDirStream);
+        }
+    }
+
+    // Returns the next filename, or NULL.
+    const char* next() {
+        dirent* result = NULL;
+        int rc = readdir_r(mDirStream, &mEntry, &result);
+        if (rc != 0) {
+            mIsBad = true;
+            return NULL;
         }
+        return (result != NULL) ? result->d_name : NULL;
     }
-    dirent* next() {
-        return readdir(dirp);
+
+    // Has an error occurred on this stream?
+    bool isBad() const {
+        return mIsBad;
+    }
+
+private:
+    DIR* mDirStream;
+    dirent mEntry;
+    bool mIsBad;
+};
+
+// DirEntry and DirEntries is a minimal equivalent of std::forward_list
+// for the filenames.
+struct DirEntry {
+    DirEntry(const char* filename) : name(strlen(filename)) {
+        strcpy(&name[0], filename);
+        next = NULL;
     }
-    DIR* dirp;
+    // On Linux, the ext family all limit the length of a directory entry to
+    // less than 256 characters.
+    LocalArray<256> name;
+    DirEntry* next;
 };
 
-// TODO: this is a literal translation of the old code. we should remove the fixed-size buffers here.
-#define MaxPath 1024
+class DirEntries {
+public:
+    DirEntries() : mSize(0), mHead(NULL) {
+    }
+
+    ~DirEntries() {
+        while (mHead) {
+            pop_front();
+        }
+    }
+
+    bool push_front(const char* name) {
+        DirEntry* oldHead = mHead;
+        mHead = new DirEntry(name);
+        if (mHead == NULL) {
+            return false;
+        }
+        mHead->next = oldHead;
+        ++mSize;
+        return true;
+    }
 
-// TODO: Java doesn't guarantee any specific ordering, and with some file systems you will get results in non-alphabetical order, so I've just done the most convenient thing for the native code, but I wonder if we shouldn't pass down an ArrayList<String> and fill it?
-struct LinkedDirEntry {
-    static void addFirst(LinkedDirEntry** list, LinkedDirEntry* newEntry) {
-        newEntry->next = *list;
-        *list = newEntry;
+    const char* front() const {
+        return &mHead->name[0];
     }
 
-    LinkedDirEntry() : next(NULL) {
+    void pop_front() {
+        DirEntry* popped = mHead;
+        if (popped != NULL) {
+            mHead = popped->next;
+            --mSize;
+            delete popped;
+        }
     }
 
-    ~LinkedDirEntry() {
-        delete next;
+    size_t size() const {
+        return mSize;
     }
 
-    char pathEntry[MaxPath];
-    LinkedDirEntry* next;
+private:
+    size_t mSize;
+    DirEntry* mHead;
 };
 
-static jobject java_io_File_listImpl(JNIEnv* env, jclass clazz, jbyteArray pathBytes) {
+// Reads the directory referred to by 'pathBytes', adding each directory entry
+// to 'entries'.
+static bool readDirectory(JNIEnv* env, jbyteArray pathBytes, DirEntries& entries) {
     ScopedByteArray path(env, pathBytes);
-    
-    ScopedReaddir dir(opendir(&path[0]));
-    if (dir.dirp == NULL) {
-        // TODO: shouldn't we throw an IOException?
-        return NULL;
-    }
-    
-    // TODO: merge this into the loop below.
-    dirent* entry = dir.next();
-    if (entry == NULL) {
-        return NULL;
+    ScopedReaddir dir(&path[0]);
+    if (dir.isBad()) {
+        return false;
     }
-    char filename[MaxPath];
-    strcpy(filename, entry->d_name);
-
-    size_t fileCount = 0;
-    LinkedDirEntry* files = NULL;
-    while (entry != NULL) {
-        if (strcmp(".", filename) != 0 && strcmp("..", filename) != 0) {
-            LinkedDirEntry* newEntry = new LinkedDirEntry;
-            if (newEntry == NULL) {
+    const char* filename;
+    while ((filename = dir.next()) != NULL) {
+        if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0) {
+            if (!entries.push_front(filename)) {
                 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
-                return NULL;
+                return false;
             }
-            strcpy(newEntry->pathEntry, filename);
-            
-            LinkedDirEntry::addFirst(&files, newEntry);
-            ++fileCount;
-        }
-
-        entry = dir.next();
-        if (entry != NULL) {
-            strcpy(filename, entry->d_name);
         }
     }
-    
-    // TODO: we should kill the ScopedReaddir about here, since we no longer need it.
-    
-    // TODO: we're supposed to use null to signal errors. we should return "new String[0]" here (or an empty byte[][]).
-    if (fileCount == 0) {
+    return true;
+}
+
+static jobjectArray java_io_File_listImpl(JNIEnv* env, jobject, jbyteArray pathBytes) {
+    // Read the directory entries into an intermediate form.
+    DirEntries files;
+    if (!readDirectory(env, pathBytes, files)) {
         return NULL;
     }
-    
-    // Create a byte[][].
-    // TODO: since the callers all want a String[], why do we return a byte[][]?
-    jclass byteArrayClass = env->FindClass("[B");
-    if (byteArrayClass == NULL) {
+    // Translate the intermediate form into a Java String[].
+    jclass stringClass = env->FindClass("java/lang/String");
+    if (stringClass == NULL) {
         return NULL;
     }
-    jobjectArray answer = env->NewObjectArray(fileCount, byteArrayClass, NULL);
-    int arrayIndex = 0;
-    for (LinkedDirEntry* file = files; file != NULL; file = file->next) {
-        jsize entrylen = strlen(file->pathEntry);
-        jbyteArray entrypath = env->NewByteArray(entrylen);
-        env->SetByteArrayRegion(entrypath, 0, entrylen, (jbyte *) file->pathEntry);
-        env->SetObjectArrayElement(answer, arrayIndex, entrypath);
-        env->DeleteLocalRef(entrypath);
-        ++arrayIndex;
+    jobjectArray result = env->NewObjectArray(files.size(), stringClass, NULL);
+    for (int i = 0; files.size() != 0; files.pop_front(), ++i) {
+        jstring javaFilename = env->NewStringUTF(files.front());
+        if (env->ExceptionCheck()) {
+            return NULL;
+        }
+        env->SetObjectArrayElement(result, i, javaFilename);
+        if (env->ExceptionCheck()) {
+            return NULL;
+        }
+        env->DeleteLocalRef(javaFilename);
     }
-    return answer;
+    return result;
 }
 
 static jboolean java_io_File_mkdirImpl(JNIEnv* env, jobject, jbyteArray pathBytes) {
@@ -311,7 +351,7 @@ static JNINativeMethod gMethods[] = {
     { "isWritableImpl",     "([B)Z",  (void*) java_io_File_isWritableImpl },
     { "lastModifiedImpl",   "([B)J",  (void*) java_io_File_lastModifiedImpl },
     { "lengthImpl",         "([B)J",  (void*) java_io_File_lengthImpl },
-    { "listImpl",           "([B)[[B",(void*) java_io_File_listImpl },
+    { "listImpl",           "([B)[Ljava/lang/String;", (void*) java_io_File_listImpl },
     { "mkdirImpl",          "([B)Z",  (void*) java_io_File_mkdirImpl },
     { "renameToImpl",       "([B[B)Z",(void*) java_io_File_renameToImpl },
     { "setLastModifiedImpl","([BJ)Z", (void*) java_io_File_setLastModifiedImpl },
index 87f17c1..23b0e27 100644 (file)
@@ -301,13 +301,12 @@ public abstract class NumberFormat extends Format {
     @Override
     public StringBuffer format(Object object, StringBuffer buffer,
             FieldPosition field) {
-        if (object instanceof Number) {
+        if (object instanceof Double || object instanceof Float) {
             double dv = ((Number) object).doubleValue();
-            long lv = ((Number) object).longValue();
-            if (dv == lv) {
-                return format(lv, buffer, field);
-            }
             return format(dv, buffer, field);
+        } else if (object instanceof Number) {
+            long lv = ((Number) object).longValue();
+            return format(lv, buffer, field);
         }
         throw new IllegalArgumentException();
     }
index 60d74b8..be933ca 100644 (file)
@@ -18,6 +18,7 @@ package org.apache.harmony.xml;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
 import org.xml.sax.EntityResolver;
 import org.xml.sax.InputSource;
 import org.xml.sax.Locator;
@@ -226,6 +227,20 @@ class ExpatParser {
         }        
     }
 
+    /*package*/ void notationDecl(String name, String publicId, String systemId) throws SAXException {
+        DTDHandler dtdHandler = xmlReader.dtdHandler;
+        if (dtdHandler != null) {
+            dtdHandler.notationDecl(name, publicId, systemId);
+        }
+    }
+
+    /*package*/ void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
+        DTDHandler dtdHandler = xmlReader.dtdHandler;
+        if (dtdHandler != null) {
+            dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
+        }
+    }
+
     /**
      * Handles an external entity.
      *
@@ -791,4 +806,3 @@ class ExpatParser {
         }
     }
 }
-
index a6a83a0..dbe3a3a 100644 (file)
@@ -37,15 +37,12 @@ import java.util.logging.Logger;
  * Does not support {@link DTDHandler}.
  */
 public class ExpatReader implements XMLReader {
-
-    private static final Logger logger
-            = Logger.getLogger(ExpatReader.class.getName());
-
     /*
      * ExpatParser accesses these fields directly during parsing. The user
      * should be able to safely change them during parsing.
      */
     /*package*/ ContentHandler contentHandler;
+    /*package*/ DTDHandler dtdHandler;
     /*package*/ EntityResolver entityResolver;
     /*package*/ ErrorHandler errorHandler;
     /*package*/ LexicalHandler lexicalHandler;
@@ -170,18 +167,12 @@ public class ExpatReader implements XMLReader {
         return entityResolver;
     }
 
-    /**
-     * Not implemented.
-     */
-    public void setDTDHandler(DTDHandler ignored) {
-        logger.warning("DTD handlers aren't supported.");
+    public void setDTDHandler(DTDHandler dtdHandler) {
+        this.dtdHandler = dtdHandler;
     }
 
-    /**
-     * Always returns null.
-     */
     public DTDHandler getDTDHandler() {
-        return null;
+        return dtdHandler;
     }
 
     public void setContentHandler(ContentHandler handler) {
index 701dbd9..f16e905 100644 (file)
@@ -31,7 +31,7 @@
 /**
  * Wrapper around an interned string.
  */
-typedef struct {
+struct InternedString {
 
     /** The interned string itself. */
     jstring interned;
@@ -41,22 +41,22 @@ typedef struct {
 
     /** Hash code of the interned string. */
     int hash;    
-} InternedString;
+};
 
 /**
  * Keeps track of strings between start and end events.
  */
-typedef struct {
+struct StringStack {
 
     jstring* array;
     int capacity;
     int size;
-} StringStack;
+};
 
 /**
  * Data passed to parser handler method by the parser.
  */
-typedef struct {
+struct ParsingContext {
 
     /**
      * The JNI environment for the current thread. This should only be used
@@ -87,21 +87,23 @@ typedef struct {
 
     /** Cache of interned strings. */
     InternedString** internedStrings[BUCKET_COUNT];
-} ParsingContext;
+};
 
-static jmethodID startElementMethod;
-static jmethodID endElementMethod;
-static jmethodID textMethod;
 static jmethodID commentMethod;
-static jmethodID startCdataMethod;
 static jmethodID endCdataMethod;
-static jmethodID startDtdMethod;
 static jmethodID endDtdMethod;
-static jmethodID startNamespaceMethod;
+static jmethodID endElementMethod;
 static jmethodID endNamespaceMethod;
-static jmethodID processingInstructionMethod;
 static jmethodID handleExternalEntityMethod;
 static jmethodID internMethod;
+static jmethodID notationDeclMethod;
+static jmethodID processingInstructionMethod;
+static jmethodID startCdataMethod;
+static jmethodID startDtdMethod;
+static jmethodID startElementMethod;
+static jmethodID startNamespaceMethod;
+static jmethodID textMethod;
+static jmethodID unparsedEntityDeclMethod;
 static jclass stringClass;
 static jstring emptyString;
 
@@ -879,6 +881,53 @@ static int handleExternalEntity(XML_Parser parser, const char* context,
     return env->ExceptionCheck() ? XML_STATUS_ERROR : XML_STATUS_OK;
 }
 
+static void unparsedEntityDecl(void* data, const char* name, const char* base, const char* systemId, const char* publicId, const char* notationName) {
+    ParsingContext* parsingContext = reinterpret_cast<ParsingContext*>(data);
+    jobject javaParser = parsingContext->object;
+    JNIEnv* env = parsingContext->env;
+    
+    // Bail out if a previously called handler threw an exception.
+    if (env->ExceptionCheck()) return;
+    
+    jstring javaName = env->NewStringUTF(name);
+    if (env->ExceptionCheck()) return;
+    jstring javaPublicId = env->NewStringUTF(publicId);
+    if (env->ExceptionCheck()) return;
+    jstring javaSystemId = env->NewStringUTF(systemId);
+    if (env->ExceptionCheck()) return;
+    jstring javaNotationName = env->NewStringUTF(notationName);
+    if (env->ExceptionCheck()) return;
+    
+    env->CallVoidMethod(javaParser, unparsedEntityDeclMethod, javaName, javaPublicId, javaSystemId, javaNotationName);
+    
+    env->DeleteLocalRef(javaName);
+    env->DeleteLocalRef(javaPublicId);
+    env->DeleteLocalRef(javaSystemId);
+    env->DeleteLocalRef(javaNotationName);
+}
+
+static void notationDecl(void* data, const char* name, const char* base, const char* systemId, const char* publicId) {
+    ParsingContext* parsingContext = reinterpret_cast<ParsingContext*>(data);
+    jobject javaParser = parsingContext->object;
+    JNIEnv* env = parsingContext->env;
+    
+    // Bail out if a previously called handler threw an exception.
+    if (env->ExceptionCheck()) return;
+    
+    jstring javaName = env->NewStringUTF(name);
+    if (env->ExceptionCheck()) return;
+    jstring javaPublicId = env->NewStringUTF(publicId);
+    if (env->ExceptionCheck()) return;
+    jstring javaSystemId = env->NewStringUTF(systemId);
+    if (env->ExceptionCheck()) return;
+    
+    env->CallVoidMethod(javaParser, notationDeclMethod, javaName, javaPublicId, javaSystemId);
+    
+    env->DeleteLocalRef(javaName);
+    env->DeleteLocalRef(javaPublicId);
+    env->DeleteLocalRef(javaSystemId);
+}
+
 /**
  * Releases the parsing context.
  */
@@ -945,15 +994,15 @@ static jint initialize(JNIEnv* env, jobject object, jstring javaEncoding,
             XML_SetNamespaceDeclHandler(parser, startNamespace, endNamespace);
         }
 
-        XML_SetCommentHandler(parser, comment);
         XML_SetCdataSectionHandler(parser, startCdata, endCdata);
-
-        XML_SetElementHandler(parser, startElement, endElement);
         XML_SetCharacterDataHandler(parser, text);
+        XML_SetCommentHandler(parser, comment);
         XML_SetDoctypeDeclHandler(parser, startDtd, endDtd);
-        XML_SetProcessingInstructionHandler(parser, processingInstruction);
+        XML_SetElementHandler(parser, startElement, endElement);
         XML_SetExternalEntityRefHandler(parser, handleExternalEntity);
-
+        XML_SetNotationDeclHandler(parser, notationDecl);
+        XML_SetProcessingInstructionHandler(parser, processingInstruction);
+        XML_SetUnparsedEntityDeclHandler(parser, unparsedEntityDecl);
         XML_SetUserData(parser, context);
     } else {
         releaseParsingContext(env, context);
@@ -1358,51 +1407,60 @@ static void freeAttributes(JNIEnv* env, jobject clazz, jint pointer) {
  *
  * @param clazz Java ExpatParser class
  */
-static void staticInitialize(JNIEnv* env, jobject clazz, jstring empty) {
-    startElementMethod = env->GetMethodID((jclass) clazz, "startElement",
+static void staticInitialize(JNIEnv* env, jobject classObject, jstring empty) {
+    jclass clazz = reinterpret_cast<jclass>(classObject);
+    startElementMethod = env->GetMethodID(clazz, "startElement",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V");
     if (startElementMethod == NULL) return;
     
-    endElementMethod = env->GetMethodID((jclass) clazz, "endElement",
+    endElementMethod = env->GetMethodID(clazz, "endElement",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
     if (endElementMethod == NULL) return;
 
-    textMethod = env->GetMethodID((jclass) clazz, "text", "([CI)V");
+    textMethod = env->GetMethodID(clazz, "text", "([CI)V");
     if (textMethod == NULL) return;
 
-    commentMethod = env->GetMethodID((jclass) clazz, "comment", "([CI)V");
+    commentMethod = env->GetMethodID(clazz, "comment", "([CI)V");
     if (commentMethod == NULL) return;
 
-    startCdataMethod = env->GetMethodID((jclass) clazz, "startCdata", "()V");
+    startCdataMethod = env->GetMethodID(clazz, "startCdata", "()V");
     if (startCdataMethod == NULL) return;
 
-    endCdataMethod = env->GetMethodID((jclass) clazz, "endCdata", "()V");
+    endCdataMethod = env->GetMethodID(clazz, "endCdata", "()V");
     if (endCdataMethod == NULL) return;
 
-    startDtdMethod = env->GetMethodID((jclass) clazz, "startDtd",
+    startDtdMethod = env->GetMethodID(clazz, "startDtd",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
     if (startDtdMethod == NULL) return;
 
-    endDtdMethod = env->GetMethodID((jclass) clazz, "endDtd", "()V");
+    endDtdMethod = env->GetMethodID(clazz, "endDtd", "()V");
     if (endDtdMethod == NULL) return;
 
-    startNamespaceMethod = env->GetMethodID((jclass) clazz, "startNamespace",
+    startNamespaceMethod = env->GetMethodID(clazz, "startNamespace",
         "(Ljava/lang/String;Ljava/lang/String;)V");
     if (startNamespaceMethod == NULL) return;
 
-    endNamespaceMethod = env->GetMethodID((jclass) clazz, "endNamespace",
+    endNamespaceMethod = env->GetMethodID(clazz, "endNamespace",
         "(Ljava/lang/String;)V");
     if (endNamespaceMethod == NULL) return;
 
-    processingInstructionMethod = env->GetMethodID((jclass) clazz,
+    processingInstructionMethod = env->GetMethodID(clazz,
         "processingInstruction", "(Ljava/lang/String;Ljava/lang/String;)V");
     if (processingInstructionMethod == NULL) return;
 
-    handleExternalEntityMethod = env->GetMethodID((jclass) clazz,
+    handleExternalEntityMethod = env->GetMethodID(clazz,
         "handleExternalEntity",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
     if (handleExternalEntityMethod == NULL) return;
 
+    notationDeclMethod = env->GetMethodID(clazz, "notationDecl",
+            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+    if (notationDeclMethod == NULL) return;
+
+    unparsedEntityDeclMethod = env->GetMethodID(clazz, "unparsedEntityDecl",
+            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+    if (unparsedEntityDeclMethod == NULL) return;
+
     // Look up String class.
     stringClass = env->FindClass("java/lang/String");
 
index 480bca3..f781611 100644 (file)
@@ -501,27 +501,67 @@ public class ExpatParserTest extends TestCase {
         }
     }
 
-    public void testDtd() throws Exception {
-        Reader in = new StringReader(
-            "<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee'><a></a>");
+    private TestDtdHandler runDtdTest(String s) throws Exception {
+        Reader in = new StringReader(s);
         ExpatReader reader = new ExpatReader();
         TestDtdHandler handler = new TestDtdHandler();
         reader.setContentHandler(handler);
+        reader.setDTDHandler(handler);
         reader.setLexicalHandler(handler);
         reader.parse(new InputSource(in));
+        return handler;
+    }
 
+    public void testDtdDoctype() throws Exception {
+        TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee'><a></a>");
         assertEquals("foo", handler.name);
         assertEquals("bar", handler.publicId);
         assertEquals("tee", handler.systemId);
-
         assertTrue(handler.ended);
     }
 
+    public void testDtdUnparsedEntity_system() throws Exception {
+        TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!ENTITY ent SYSTEM 'blah' NDATA poop> ]><a></a>");
+        assertEquals("ent", handler.ueName);
+        assertEquals(null, handler.uePublicId);
+        assertEquals("blah", handler.ueSystemId);
+        assertEquals("poop", handler.ueNotationName);
+    }
+
+    public void testDtdUnparsedEntity_public() throws Exception {
+        TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!ENTITY ent PUBLIC 'a' 'b' NDATA poop> ]><a></a>");
+        assertEquals("ent", handler.ueName);
+        assertEquals("a", handler.uePublicId);
+        assertEquals("b", handler.ueSystemId);
+        assertEquals("poop", handler.ueNotationName);
+    }
+
+    public void testDtdNotation_system() throws Exception {
+        TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!NOTATION sn SYSTEM 'nf2'> ]><a></a>");
+        assertEquals("sn", handler.ndName);
+        assertEquals(null, handler.ndPublicId);
+        assertEquals("nf2", handler.ndSystemId);
+    }
+
+    public void testDtdNotation_public() throws Exception {
+        TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!NOTATION pn PUBLIC 'nf1'> ]><a></a>");
+        assertEquals("pn", handler.ndName);
+        assertEquals("nf1", handler.ndPublicId);
+        assertEquals(null, handler.ndSystemId);
+    }
+
     static class TestDtdHandler extends DefaultHandler2 {
 
         String name;
         String publicId;
         String systemId;
+        String ndName;
+        String ndPublicId;
+        String ndSystemId;
+        String ueName;
+        String uePublicId;
+        String ueSystemId;
+        String ueNotationName;
 
         boolean ended;
 
@@ -543,6 +583,21 @@ public class ExpatParserTest extends TestCase {
         public void setDocumentLocator(Locator locator) {
             this.locator = locator;
         }
+
+        @Override
+        public void notationDecl(String name, String publicId, String systemId) {
+            this.ndName = name;
+            this.ndPublicId = publicId;
+            this.ndSystemId = systemId;
+        }
+
+        @Override
+        public void unparsedEntityDecl(String entityName, String publicId, String systemId, String notationName) {
+            this.ueName = entityName;
+            this.uePublicId = publicId;
+            this.ueSystemId = systemId;
+            this.ueNotationName = notationName;
+        }
     }
 
     public void testCdata() throws Exception {
index b43acb9..c94b8ad 100644 (file)
@@ -16,6 +16,7 @@ public class Main {
         System.out.println("spawning child");
         ProcessBuilder pb = new ProcessBuilder("/system/bin/sleep", "5");
         Process proc = pb.start();
+        Thread.sleep(1000);
         checkManager();
         proc.waitFor();
         System.out.println("child died");
index fda4e6d..a3279d8 100644 (file)
@@ -403,7 +403,7 @@ static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
 static void scanInstanceFields(const DataObject *obj, ClassObject *clazz,
         GcMarkContext *ctx)
 {
-    if (false && clazz->refOffsets != CLASS_WALK_SUPER) {
+    if (clazz->refOffsets != CLASS_WALK_SUPER) {
         unsigned int refOffsets = clazz->refOffsets;
         while (refOffsets != 0) {
             const int rshift = CLZ(refOffsets);
diff --git a/vm/compiler/template/armv5te-vfp/platform.S b/vm/compiler/template/armv5te-vfp/platform.S
new file mode 100644 (file)
index 0000000..4c8c2a2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+/*
+ * Macro for "MOV LR,PC / LDR PC,xxx", which is not allowed pre-ARMv5.
+ * Jump to subroutine.
+ *
+ * May modify IP and LR.
+ */
+.macro  LDR_PC_LR source
+    mov     lr, pc
+    ldr     pc, \source
+.endm
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    vstmia r0, {d8-d15}
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    vldmia r0, {d8-d15}
+    bx     lr
+
index b960a93..3cefa6d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ===========================================================================
- *  CPU-version-specific defines
+ *  CPU-version-specific defines and utility
  * ===========================================================================
  */
 
     mov     lr, pc
     ldr     pc, \source
 .endm
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    bx     lr
+
index fc968fe..0a1c7c7 100644 (file)
@@ -25,7 +25,7 @@ import armv5te/header.S
 #import cstubs/stubdefs.c
 
 # highly-platform-specific defs
-import armv5te/platform.S
+import armv5te-vfp/platform.S
 
 # common defs for the C helpers; include this before the instruction handlers
 #import c/opcommon.c
index 7f7b478..89fbb23 100644 (file)
@@ -25,7 +25,7 @@ import armv5te/header.S
 #import cstubs/stubdefs.c
 
 # highly-platform-specific defs
-import armv5te/platform.S
+import armv5te-vfp/platform.S
 
 # common defs for the C helpers; include this before the instruction handlers
 #import c/opcommon.c
index 80a9dd8..0dfb986 100644 (file)
@@ -102,10 +102,10 @@ unspecified registers or condition codes.
 #include "../../../mterp/common/asm-constants.h"
 
 
-/* File: armv5te/platform.S */
+/* File: armv5te-vfp/platform.S */
 /*
  * ===========================================================================
- *  CPU-version-specific defines
+ *  CPU-version-specific defines and utility
  * ===========================================================================
  */
 
@@ -120,6 +120,26 @@ unspecified registers or condition codes.
     ldr     pc, \source
 .endm
 
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    vstmia r0, {d8-d15}
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    vldmia r0, {d8-d15}
+    bx     lr
+
+
 
     .global dvmCompilerTemplateStart
     .type   dvmCompilerTemplateStart, %function
index a83344a..0e79497 100644 (file)
@@ -105,7 +105,7 @@ unspecified registers or condition codes.
 /* File: armv5te/platform.S */
 /*
  * ===========================================================================
- *  CPU-version-specific defines
+ *  CPU-version-specific defines and utility
  * ===========================================================================
  */
 
@@ -120,6 +120,24 @@ unspecified registers or condition codes.
     ldr     pc, \source
 .endm
 
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    bx     lr
+
+
 
     .global dvmCompilerTemplateStart
     .type   dvmCompilerTemplateStart, %function
index cb47011..ff69653 100644 (file)
@@ -102,10 +102,10 @@ unspecified registers or condition codes.
 #include "../../../mterp/common/asm-constants.h"
 
 
-/* File: armv5te/platform.S */
+/* File: armv5te-vfp/platform.S */
 /*
  * ===========================================================================
- *  CPU-version-specific defines
+ *  CPU-version-specific defines and utility
  * ===========================================================================
  */
 
@@ -120,6 +120,26 @@ unspecified registers or condition codes.
     ldr     pc, \source
 .endm
 
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    vstmia r0, {d8-d15}
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    vldmia r0, {d8-d15}
+    bx     lr
+
+
 
     .global dvmCompilerTemplateStart
     .type   dvmCompilerTemplateStart, %function
index 10b9bb1..2a7476c 100644 (file)
@@ -1219,6 +1219,9 @@ void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
     InterpState interpState;
     bool change;
 #if defined(WITH_JIT)
+    /* Target-specific save/restore */
+    extern void dvmJitCalleeSave(double *saveArea);
+    extern void dvmJitCalleeRestore(double *saveArea);
     /* Interpreter entry points from compiled code */
     extern void dvmJitToInterpNormal();
     extern void dvmJitToInterpNoChain();
@@ -1256,6 +1259,7 @@ void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
     interpState.debugIsMethodEntry = true;
 #endif
 #if defined(WITH_JIT)
+    dvmJitCalleeSave(interpState.calleeSave);
     interpState.jitState = gDvmJit.pJitEntryTable ? kJitNormal : kJitOff;
 
     /* Setup the Jit-to-interpreter entry points */
@@ -1333,4 +1337,7 @@ void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
     }
 
     *pResult = interpState.retval;
+#if defined(WITH_JIT)
+    dvmJitCalleeRestore(interpState.calleeSave);
+#endif
 }
index 744033e..2928371 100644 (file)
@@ -93,6 +93,14 @@ struct JitToInterpEntries {
 #endif
 };
 
+/*
+ * Size of save area for callee-save FP regs, which are not automatically
+ * saved by interpreter main because it doesn't use them (but Jit'd code
+ * may). Save/restore routine is defined by target, and size should
+ * be >= max needed by any target.
+ */
+#define JIT_CALLEE_SAVE_DOUBLE_COUNT 8
+
 #define JIT_TRACE_THRESH_FILTER_SIZE  16
 #endif
 
@@ -175,6 +183,7 @@ typedef struct InterpState {
 #endif
     const u2* threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
     JitTraceRun trace[MAX_JIT_RUN_LEN];
+    double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT];
 #endif
 
 } InterpState;
index f982793..6046bb3 100644 (file)
@@ -247,6 +247,9 @@ MTERP_CONSTANT(STRING_FIELDOFF_COUNT,    20)
 MTERP_CONSTANT(kInlineCacheMiss,        0)
 MTERP_CONSTANT(kCallsiteInterpreted,    1)
 MTERP_CONSTANT(kSwitchOverflow,         2)
+
+/* Size of callee save area */
+MTERP_CONSTANT(JIT_CALLEE_SAVE_DOUBLE_COUNT,   8)
 #endif
 
 /* ClassObject fields */
@@ -254,9 +257,9 @@ MTERP_OFFSET(offClassObject_descriptor, ClassObject, descriptor, 24)
 MTERP_OFFSET(offClassObject_accessFlags, ClassObject, accessFlags, 32)
 MTERP_OFFSET(offClassObject_pDvmDex,    ClassObject, pDvmDex, 40)
 MTERP_OFFSET(offClassObject_status,     ClassObject, status, 44)
-MTERP_OFFSET(offClassObject_super,      ClassObject, super, 76)
-MTERP_OFFSET(offClassObject_vtableCount, ClassObject, vtableCount, 116)
-MTERP_OFFSET(offClassObject_vtable,     ClassObject, vtable, 120)
+MTERP_OFFSET(offClassObject_super,      ClassObject, super, 72)
+MTERP_OFFSET(offClassObject_vtableCount, ClassObject, vtableCount, 112)
+MTERP_OFFSET(offClassObject_vtable,     ClassObject, vtable, 116)
 
 /* InterpEntry enumeration */
 MTERP_SIZEOF(sizeofClassStatus,         InterpEntry, MTERP_SMALL_ENUM)
index 19a0f96..60da683 100644 (file)
@@ -104,21 +104,13 @@ ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj)
 
     assert(elemClassObj != NULL);
 
-    if (elemClassObj->arrayClass != NULL) {
-        arrayClass = elemClassObj->arrayClass;
-        LOGVV("using cached '%s' class for '%s'\n",
-            arrayClass->descriptor, elemClassObj->descriptor);
-    } else {
-        /* Simply prepend "[" to the descriptor. */
-        int nameLen = strlen(elemClassObj->descriptor);
-        char className[nameLen + 2];
-
-        className[0] = '[';
-        memcpy(className+1, elemClassObj->descriptor, nameLen+1);
-        arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader);
-        if (arrayClass != NULL)
-            elemClassObj->arrayClass = arrayClass;
-    }
+    /* Simply prepend "[" to the descriptor. */
+    int nameLen = strlen(elemClassObj->descriptor);
+    char className[nameLen + 2];
+
+    className[0] = '[';
+    memcpy(className+1, elemClassObj->descriptor, nameLen+1);
+    arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader);
 
     return arrayClass;
 }
@@ -708,4 +700,3 @@ void dvmGcScanPrimitiveClasses()
         dvmMarkObject((Object *)gDvm.primitiveClass[i]);    // may be NULL
     }
 }
-
index 298c230..ba2d9bb 100644 (file)
@@ -378,9 +378,6 @@ struct ClassObject {
        (for String[][][], this will be String) */
     ClassObject*    elementClass;
 
-    /* class object representing an array of this class; set on first use */
-    ClassObject*    arrayClass;
-
     /* arrays only: number of dimensions, e.g. int[][] is 2 */
     int             arrayDim;