*/
public class Version {
/** {@code non-null;} version string */
- public static final String VERSION = "1.3";
+ public static final String VERSION = "1.4";
}
/**
* 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;
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;
/**
* {@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;
/**
* Adds a label to the list of ret blocks (final blocks) for this
* subroutine.
- *
+ *
* @param retBlock ret block label
*/
void addRetBlock(int retBlock) {
* 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
*/
}
successors.setImmutable();
-
+
return successors;
}
/**
* 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
/**
* 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
*/
* 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;
/**
* 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() {
/**
* 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
*/
/**
* 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
*/
/**
* Gets the minimum label for unreserved use.
- *
+ *
* @return {@code >= 0;} the minimum label
*/
private int getMinimumUnreservedLabel() {
/**
* Gets an arbitrary unreserved and available label.
- *
+ *
* @return {@code >= 0;} the label
*/
private int getAvailableLabel() {
/**
* Gets whether the method being translated is synchronized.
- *
+ *
* @return whether the method being translated is synchronized
*/
private boolean isSynchronized() {
/**
* Gets whether the method being translated is static.
- *
+ *
* @return whether the method being translated is static
*/
private boolean isStatic() {
/**
* 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() {
/**
* 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
}
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
*/
/**
* 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) {
* 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
*/
* 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
*/
* 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) {
/**
* Extracts the resulting {@link RopMethod} from the instance.
- *
+ *
* @return {@code non-null;} the method object
*/
private RopMethod getRopMethod() {
/**
* 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.
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];
successors.setImmutable();
primarySucc = label;
}
-
+
Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
/*
RegisterSpecList.EMPTY));
insnSz++;
}
-
+
/*
* Construct a block for the remaining instructions (which in
* the usual case is all of them).
/**
* 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
* @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) {
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());
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();
}
/**
- * Inlines any subroutine calls
+ * Inlines any subroutine calls.
*/
private void inlineSubroutines() {
final IntList reachableSubroutineCallerLabels = new IntList(4);
* 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() {
}
/*
- * 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));
}
/**
* 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;
/**
/**
* 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
/**
* Copies a basic block, mapping its successors along the way.
+ *
* @param origLabel original block label
* @param newLabel label that the new block should have
*/
* 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);
}
/**
- * 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--) {
/**
- * 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;
/**
* 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)) {
}
}
+ public synchronized void testInstance5() {
+ testInstance5();
+ }
+
public static synchronized void testStatic1() {
// This space intentionally left blank.
}
return 2;
}
}
+
+ public static synchronized void testStatic5() {
+ testStatic5();
+ }
}
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
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
@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);
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;
}
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
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
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);
}
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) {
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': {
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) {
{ "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 },
@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();
}
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;
}
}
+ /*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.
*
}
}
}
-
* 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;
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) {
/**
* Wrapper around an interned string.
*/
-typedef struct {
+struct InternedString {
/** The interned string itself. */
jstring interned;
/** 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
/** 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;
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.
*/
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);
*
* @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");
}
}
- 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;
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 {
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");
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);
--- /dev/null
+/*
+ * ===========================================================================
+ * 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
+
/*
* ===========================================================================
- * 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
+
#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
#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
#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
* ===========================================================================
*/
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
/* File: armv5te/platform.S */
/*
* ===========================================================================
- * CPU-version-specific defines
+ * CPU-version-specific defines and utility
* ===========================================================================
*/
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
#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
* ===========================================================================
*/
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
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();
interpState.debugIsMethodEntry = true;
#endif
#if defined(WITH_JIT)
+ dvmJitCalleeSave(interpState.calleeSave);
interpState.jitState = gDvmJit.pJitEntryTable ? kJitNormal : kJitOff;
/* Setup the Jit-to-interpreter entry points */
}
*pResult = interpState.retval;
+#if defined(WITH_JIT)
+ dvmJitCalleeRestore(interpState.calleeSave);
+#endif
}
#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
#endif
const u2* threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
JitTraceRun trace[MAX_JIT_RUN_LEN];
+ double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT];
#endif
} InterpState;
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 */
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)
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;
}
dvmMarkObject((Object *)gDvm.primitiveClass[i]); // may be NULL
}
}
-
(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;