am ac830fea: Fix dx launching script to use the new platform-tools location.
Merge commit 'ac830feace28957c9e84ce2cb0ed2a565bc24c99' into gingerbread-plus-aosp
* commit 'ac830feace28957c9e84ce2cb0ed2a565bc24c99':
Fix dx launching script to use the new platform-tools location.
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1b48950..1bc6e95 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -46,6 +46,9 @@
#$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/dalvikvm/Main.c b/dalvikvm/Main.c
index a6439fb..666317c 100644
--- a/dalvikvm/Main.c
+++ b/dalvikvm/Main.c
@@ -299,4 +299,3 @@
/*printf("--- VM is down, process exiting\n");*/
return result;
}
-
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
index c8720d8..026067b 100644
--- a/dexdump/Android.mk
+++ b/dexdump/Android.mk
@@ -18,8 +18,7 @@
LOCAL_PATH:= $(call my-dir)
dexdump_src_files := \
- DexDump.c \
- OpCodeNames.c
+ DexDump.c
dexdump_c_includes := \
dalvik \
@@ -72,4 +71,3 @@
include $(BUILD_HOST_EXECUTABLE)
endif # !TARGET_SIMULATOR
-
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
index 9d9b6be..33646bb 100644
--- a/dexdump/DexDump.c
+++ b/dexdump/DexDump.c
@@ -34,11 +34,10 @@
#include "libdex/DexClass.h"
#include "libdex/DexProto.h"
#include "libdex/InstrUtils.h"
+#include "libdex/OpCodeNames.h"
#include "libdex/SysUtil.h"
#include "libdex/CmdUtils.h"
-#include "dexdump/OpCodeNames.h"
-
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
@@ -80,20 +79,20 @@
} FieldMethodInfo;
/*
- * Get 2 little-endian bytes.
- */
+ * Get 2 little-endian bytes.
+ */
static inline u2 get2LE(unsigned char const* pSrc)
{
return pSrc[0] | (pSrc[1] << 8);
-}
+}
/*
- * Get 4 little-endian bytes.
- */
+ * Get 4 little-endian bytes.
+ */
static inline u4 get4LE(unsigned char const* pSrc)
{
return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
-}
+}
/*
* Converts a single-character primitive type into its human-readable
@@ -255,7 +254,7 @@
{
#define NUM_FLAGS 18
static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
- {
+ {
/* class, inner class */
"PUBLIC", /* 0x0001 */
"PRIVATE", /* 0x0002 */
@@ -351,14 +350,73 @@
/*
+ * Copy character data from "data" to "out", converting non-ASCII values
+ * to printf format chars or an ASCII filler ('.' or '?').
+ *
+ * The output buffer must be able to hold (2*len)+1 bytes. The result is
+ * NUL-terminated.
+ */
+static void asciify(char* out, const unsigned char* data, size_t len)
+{
+ while (len--) {
+ if (*data < 0x20) {
+ /* could do more here, but we don't need them yet */
+ switch (*data) {
+ case '\0':
+ *out++ = '\\';
+ *out++ = '0';
+ break;
+ case '\n':
+ *out++ = '\\';
+ *out++ = 'n';
+ break;
+ default:
+ *out++ = '.';
+ break;
+ }
+ } else if (*data >= 0x80) {
+ *out++ = '?';
+ } else {
+ *out++ = *data;
+ }
+ data++;
+ }
+ *out = '\0';
+}
+
+/*
* Dump the file header.
*/
void dumpFileHeader(const DexFile* pDexFile)
{
+ const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
const DexHeader* pHeader = pDexFile->pHeader;
+ char sanitized[sizeof(pHeader->magic)*2 +1];
+
+ assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
+
+ if (pOptHeader != NULL) {
+ printf("Optimized DEX file header:\n");
+
+ asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
+ printf("magic : '%s'\n", sanitized);
+ printf("dex_offset : %d (0x%06x)\n",
+ pOptHeader->dexOffset, pOptHeader->dexOffset);
+ printf("dex_length : %d\n", pOptHeader->dexLength);
+ printf("deps_offset : %d (0x%06x)\n",
+ pOptHeader->depsOffset, pOptHeader->depsOffset);
+ printf("deps_length : %d\n", pOptHeader->depsLength);
+ printf("aux_offset : %d (0x%06x)\n",
+ pOptHeader->auxOffset, pOptHeader->auxOffset);
+ printf("aux_length : %d\n", pOptHeader->auxLength);
+ printf("flags : %08x\n", pOptHeader->flags);
+ printf("checksum : %08x\n", pOptHeader->checksum);
+ printf("\n");
+ }
printf("DEX file header:\n");
- printf("magic : '%.8s'\n", pHeader->magic);
+ asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
+ printf("magic : '%s'\n", sanitized);
printf("checksum : %08x\n", pHeader->checksum);
printf("signature : %02x%02x...%02x%02x\n",
pHeader->signature[0], pHeader->signature[1],
@@ -391,6 +449,61 @@
}
/*
+ * Dump the "table of contents" for the aux area.
+ */
+void dumpAuxDirectory(const DexFile* pDexFile)
+{
+ const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+ if (pOptHeader == NULL)
+ return;
+
+ printf("AUX section contents:\n");
+
+ const u4* pAux = (const u4*) ((u1*) pOptHeader + pOptHeader->auxOffset);
+
+ if (*pAux == 0) {
+ printf("(1.0 format, only class lookup table is present)\n\n");
+ return;
+ }
+
+ /*
+ * The "aux" section is in "chunk" format: a 32-bit identifier, a 32-bit
+ * length, then the data. Chunks start on 64-bit boundaries.
+ */
+ while (*pAux != kDexChunkEnd) {
+ const char* verboseStr;
+
+ u4 size = *(pAux+1);
+
+ switch (*pAux) {
+ case kDexChunkClassLookup:
+ verboseStr = "class lookup hash table";
+ break;
+ case kDexChunkRegisterMaps:
+ verboseStr = "register maps";
+ break;
+ case kDexChunkReducingIndexMap:
+ verboseStr = "'reducing' index map";
+ break;
+ case kDexChunkExpandingIndexMap:
+ verboseStr = "'expanding' index map";
+ break;
+ default:
+ verboseStr = "(unknown chunk type)";
+ break;
+ }
+
+ printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pAux,
+ *pAux >> 24, (char)(*pAux >> 16), (char)(*pAux >> 8), (char)*pAux,
+ verboseStr, size);
+
+ size = (size + 8 + 7) & ~7;
+ pAux += size / sizeof(u4);
+ }
+ printf("\n");
+}
+
+/*
* Dump a class_def_item.
*/
void dumpClassDef(DexFile* pDexFile, int idx)
@@ -459,7 +572,7 @@
if (triesSize == 0) {
printf(" catches : (none)\n");
return;
- }
+ }
printf(" catches : %d\n", triesSize);
@@ -471,7 +584,7 @@
u4 start = pTry->startAddr;
u4 end = start + pTry->insnCount;
DexCatchIterator iterator;
-
+
printf(" 0x%04x - 0x%04x\n", start, end);
dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
@@ -479,14 +592,14 @@
for (;;) {
DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
const char* descriptor;
-
+
if (handler == NULL) {
break;
}
-
- descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
+
+ descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
dexStringByTypeIdx(pDexFile, handler->typeIdx);
-
+
printf(" %s -> 0x%04x\n", descriptor,
handler->address);
}
@@ -502,11 +615,11 @@
/*
* Dump the positions list.
*/
-void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
+void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
const DexMethod *pDexMethod)
{
printf(" positions : \n");
- const DexMethodId *pMethodId
+ const DexMethodId *pMethodId
= dexGetMethodId(pDexFile, pDexMethod->methodIdx);
const char *classDescriptor
= dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
@@ -520,7 +633,7 @@
const char *signature)
{
printf(" 0x%04x - 0x%04x reg=%d %s %s %s\n",
- startAddress, endAddress, reg, name, descriptor,
+ startAddress, endAddress, reg, name, descriptor,
signature);
}
@@ -532,9 +645,9 @@
{
printf(" locals : \n");
- const DexMethodId *pMethodId
+ const DexMethodId *pMethodId
= dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- const char *classDescriptor
+ const char *classDescriptor
= dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
@@ -555,7 +668,7 @@
pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
- pMethInfo->classDescriptor =
+ pMethInfo->classDescriptor =
dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
return true;
}
@@ -626,7 +739,7 @@
printf("|%04x: nop // spacer", insnIdx);
}
} else {
- printf("|%04x: %s", insnIdx, getOpcodeName(pDecInsn->opCode));
+ printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opCode));
}
switch (dexGetInstrFormat(gInstrFormat, pDecInsn->opCode)) {
@@ -722,7 +835,14 @@
pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
break;
case kFmt22c: // op vA, vB, thing@CCCC
- if (pDecInsn->opCode >= OP_IGET && pDecInsn->opCode <= OP_IPUT_SHORT) {
+ if (pDecInsn->opCode == OP_INSTANCE_OF ||
+ pDecInsn->opCode == OP_NEW_ARRAY)
+ {
+ printf(" v%d, v%d, %s // class@%04x",
+ pDecInsn->vA, pDecInsn->vB,
+ getClassDescriptor(pDexFile, pDecInsn->vC), pDecInsn->vC);
+ } else {
+ /* iget* and iput*, including dexopt-generated -volatile */
FieldMethodInfo fieldInfo;
if (getFieldInfo(pDexFile, pDecInsn->vC, &fieldInfo)) {
printf(" v%d, v%d, %s.%s:%s // field@%04x", pDecInsn->vA,
@@ -732,10 +852,6 @@
printf(" v%d, v%d, ??? // field@%04x", pDecInsn->vA,
pDecInsn->vB, pDecInsn->vC);
}
- } else {
- printf(" v%d, v%d, %s // class@%04x",
- pDecInsn->vA, pDecInsn->vB,
- getClassDescriptor(pDexFile, pDecInsn->vC), pDecInsn->vC);
}
break;
case kFmt22cs: // [opt] op vA, vB, field offset CCCC
@@ -953,9 +1069,9 @@
insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
} else if (instr == kArrayDataSignature) {
int width = get2LE((const u1*)(insns+1));
- int size = get2LE((const u1*)(insns+2)) |
+ int size = get2LE((const u1*)(insns+2)) |
(get2LE((const u1*)(insns+3))<<16);
- // The plus 1 is to round up for odd size and width
+ // The plus 1 is to round up for odd size and width
insnWidth = 4 + ((size * width) + 1) / 2;
} else {
opCode = instr & 0xff;
@@ -1241,7 +1357,7 @@
printf("Trouble reading class data (#%d)\n", idx);
goto bail;
}
-
+
classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
/*
@@ -1603,8 +1719,10 @@
return;
}
- if (gOptions.showFileHeaders)
+ if (gOptions.showFileHeaders) {
dumpFileHeader(pDexFile);
+ dumpAuxDirectory(pDexFile);
+ }
if (gOptions.outputFormat == OUTPUT_XML)
printf("<api>\n");
@@ -1777,4 +1895,3 @@
return (result != 0);
}
-
diff --git a/dexlist/DexList.c b/dexlist/DexList.c
index 841c17f..3552d2e 100644
--- a/dexlist/DexList.c
+++ b/dexlist/DexList.c
@@ -165,19 +165,19 @@
fprintf(stderr, "Trouble reading class data\n");
return;
}
-
+
if (pClassDef->sourceFileIdx == 0xffffffff) {
fileName = NULL;
} else {
fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
}
-
- /*
+
+ /*
* TODO: Each class def points at a sourceFile, so maybe that
* should be printed out. However, this needs to be coordinated
* with the tools that parse this output.
*/
-
+
for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
dumpMethod(pDexFile, fileName, &pClassData->directMethods[i], i);
}
@@ -291,4 +291,3 @@
free(gParms.argCopy);
return result;
}
-
diff --git a/dexopt/Android.mk b/dexopt/Android.mk
index 8637073..eb486c8 100644
--- a/dexopt/Android.mk
+++ b/dexopt/Android.mk
@@ -35,6 +35,12 @@
libssl \
libdvm
+ifeq ($(TARGET_CPU_SMP),true)
+ LOCAL_CFLAGS += -DANDROID_SMP=1
+else
+ LOCAL_CFLAGS += -DANDROID_SMP=0
+endif
+
LOCAL_MODULE := dexopt
include $(BUILD_EXECUTABLE)
diff --git a/dexopt/OptMain.c b/dexopt/OptMain.c
index 953db0b..8dffcf5 100644
--- a/dexopt/OptMain.c
+++ b/dexopt/OptMain.c
@@ -41,7 +41,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <assert.h>
static const char* kClassesDex = "classes.dex";
@@ -56,7 +55,8 @@
{
ZipArchive zippy;
ZipEntry zipEntry;
- long uncompLen, modWhen, crc32;
+ size_t uncompLen;
+ long modWhen, crc32;
off_t dexOffset;
int err;
int result = -1;
@@ -100,8 +100,8 @@
/*
* Extract some info about the zip entry.
*/
- if (!dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
- &modWhen, &crc32))
+ if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
+ &modWhen, &crc32) != 0)
{
LOGW("DexOptZ: zip archive GetEntryInfo failed on %s\n", debugFileName);
goto bail;
@@ -114,7 +114,7 @@
/*
* Extract the DEX data into the cache file at the current offset.
*/
- if (!dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd)) {
+ if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
LOGW("DexOptZ: extraction of %s from %s failed\n",
kClassesDex, debugFileName);
goto bail;
@@ -485,4 +485,3 @@
fprintf(stderr, "Usage: don't use this\n");
return 1;
}
-
diff --git a/docs/dalvik-bytecode.html b/docs/dalvik-bytecode.html
index 6d6c4f1..e69a962 100644
--- a/docs/dalvik-bytecode.html
+++ b/docs/dalvik-bytecode.html
@@ -448,7 +448,7 @@
no arrays of <code>long</code> or <code>double</code>, but reference
types are acceptable). The constructed
instance is stored as a "result" in the same way that the method invocation
- instructions store their results, so the constructed instance must
+ instructions store their results, so the constructed instance must
be moved to a register with an immediately subsequent
<code>move-result-object</code> instruction (if it is to be used).</td>
</tr>
@@ -1453,7 +1453,7 @@
float result = a % b;
</td>
<td>Floating point remainder after division. This function is different
- than IEEE 754 remainder and is defined as
+ than IEEE 754 remainder and is defined as
<code>result == a - roundTowardZero(a / b) * b</code>.
</td>
</tr>
@@ -1491,7 +1491,7 @@
double result = a % b;
</td>
<td>Floating point remainder after division. This function is different
- than IEEE 754 remainder and is defined as
+ than IEEE 754 remainder and is defined as
<code>result == a - roundTowardZero(a / b) * b</code>.
</td>
</tr>
diff --git a/docs/dalvik-constraints.html b/docs/dalvik-constraints.html
index 105225a..69abf3a 100644
--- a/docs/dalvik-constraints.html
+++ b/docs/dalvik-constraints.html
@@ -5,11 +5,11 @@
<title>Dalvik bytecode constraints</title>
<link rel=stylesheet href="dalvik-constraints.css">
</head>
-
+
<body>
-
+
<h1>Dalvik bytecode constraints</h1>
-
+
<!--
<h1>General integrity constraints</h1>
@@ -18,17 +18,17 @@
<th>
Identifier
</th>
-
+
<th>
Description
</th>
</tr>
-
+
<tr>
<td>
A1
</td>
-
+
<td>
The magic number of the DEX file must be "dex\n035\0".
</td>
@@ -38,7 +38,7 @@
<td>
A1
</td>
-
+
<td>
The checksum must be an Adler-32 checksum of the whole file contents
except magic and checksum field.
@@ -54,14 +54,14 @@
The header_size must have the value 0x70.
The endian_tag must have either the value ENDIAN_CONSTANT or
-REVERSE_ENDIAN_CONSTANT.
-
+REVERSE_ENDIAN_CONSTANT.
+
For each of the link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs
and data sections, the offset and size fields must be either both zero or both
non-zero. In the latter case, the offset must be four-byte-aligned.
All offset fields in the header except map_off must be four-byte-aligned.
-
+
The map_off field must be either zero or point into the data section. In the
latter case, the data section must exist.
@@ -124,7 +124,7 @@
...
-->
-
+
<h2>
Static constraints
</h2>
@@ -134,153 +134,153 @@
They usually can be checked without employing control or data-flow analysis
techniques.
</p>
-
+
<table>
<tr>
<th>
Identifier
</th>
-
+
<th>
Description
</th>
-
+
<th>
Spec equivalent
</th>
</tr>
-
+
<tr>
<td>
A1
</td>
-
+
<td>
- The <code>insns</code> array must not be empty.
+ The <code>insns</code> array must not be empty.
</td>
-
+
<td>
4.8.1.1
</td>
</tr>
-
+
<tr>
<td>
A2
</td>
-
+
<td>
The first opcode in the <code>insns</code> array must have index zero.
</td>
-
+
<td>
4.8.1.3
</td>
</tr>
-
+
<tr>
<td>
A3
</td>
-
+
<td>
The <code>insns</code> array must only contain valid Dalvik opcodes.
</td>
-
+
<td>
4.8.1.4
</td>
</tr>
-
+
<tr>
<td>
A4
</td>
-
+
<td>
The index of instruction <code>n+1</code> must equal the index of
instruction <code>n</code> plus the length of instruction
<code>n</code>, taking into account possible operands.
</td>
-
+
<td>
4.8.1.5
</td>
</tr>
-
+
<tr>
<td>
A5
</td>
-
+
<td>
The last instruction in the <code>insns</code> array must end at index
- <code>insns_size-1</code>.
+ <code>insns_size-1</code>.
</td>
-
+
<td>
4.8.1.6
</td>
</tr>
-
+
<tr>
<td>
A6
</td>
-
+
<td>
All <code>goto</code> and <code>if-<kind></code> targets must
be opcodes within in the same method.
</td>
-
+
<td>
4.8.1.7
</td>
</tr>
-
+
<tr>
<td>
A7
</td>
-
+
<td>
All targets of a <code>packed-switch</code> instruction must be
opcodes within in the same method. The size and the list of targets
- must be consistent.
+ must be consistent.
</td>
-
+
<td>
4.8.1.8
</td>
</tr>
-
+
<tr>
<td>
A8
</td>
-
+
<td>
All targets of a <code>sparse-switch</code> instruction must be
opcodes within in the same method. The corresponding table must be
- consistent and sorted low-to-high.
+ consistent and sorted low-to-high.
</td>
-
+
<td>
4.8.1.9
</td>
</tr>
-
+
<tr>
<td>
A9
</td>
-
+
<td>
The <code>B</code> operand of the <code>const-string</code> and
<code>const-string/jumbo</code> instructions must be a valid index
into the string constant pool.
</td>
-
+
<td>
4.8.1.10
</td>
@@ -290,31 +290,31 @@
<td>
A10
</td>
-
+
<td>
The <code>C</code> operand of the <code>iget<kind></code> and
<code>iput<kind></code> instructions must be a valid index into
the field constant pool. The referenced entry must represent an
instance field.
</td>
-
+
<td>
4.8.1.12
</td>
</tr>
-
+
<tr>
<td>
A11
</td>
-
+
<td>
The <code>C</code> operand of the <code>sget<kind></code> and
<code>sput<kind></code> instructions must be a valid index into
the field constant pool. The referenced entry must represent a static
field.
</td>
-
+
<td>
4.8.1.12
</td>
@@ -324,33 +324,33 @@
<td>
A12
</td>
-
+
<td>
The <code>C</code> operand of the <code>invoke-virtual</code>,
<code>invoke-super</code>, <code<invoke-direct</code> and
<code>invoke-static</code> instructions must be a valid index into the
method constant pool. In all cases, the referenced
- <code>method_id</code> must belong to a class (not an interface).
+ <code>method_id</code> must belong to a class (not an interface).
</td>
-
+
<td>
4.8.1.13
</td>
</tr>
-
+
<tr>
<td>
A13
</td>
-
+
<td>
The <code>B</code> operand of the <code>invoke-virtual/range</code>,
<code>invoke-super/range</code>, <code>invoke-direct/range</code>, and
<code>invoke-static/range</code> instructions must be a valid index
into the method constant pool. In all cases, the referenced
- <code>method_id</code> must belong to a class (not an interface).
+ <code>method_id</code> must belong to a class (not an interface).
</td>
-
+
<td>
4.8.1.13
</td>
@@ -360,81 +360,81 @@
<td>
A14
</td>
-
+
<td>
A method the name of which starts with a '<' must only be invoked
implicitly by the VM, not by code originating from a Dex file. The
only exception is the instance initializer, which may be invoked by
<code>invoke-direct</code>.
</td>
-
+
<td>
4.8.1.14
</td>
</tr>
-
+
<tr>
<td>
A15
</td>
-
+
<td>
The <code>C</code> operand of the <code>invoke-interface</code>
instruction must be a valid index into the method constant pool. The
referenced <code>method_id</code> must belong to an interface (not a
class).
</td>
-
+
<td>
4.8.1.15
</td>
</tr>
-
+
<tr>
<td>
A16
</td>
-
+
<td>
The <code>B</code> operand of the <code>invoke-interface/range</code>
instruction must be a valid index into the method constant pool.
The referenced <code>method_id</code> must belong to an interface (not
a class).
</td>
-
+
<td>
4.8.1.15
</td>
</tr>
-
+
<tr>
<td>
A17
</td>
-
+
<td>
The <code>B</code> operand of the <code>const-class</code>,
<code>check-cast</code>, <code>new-instance</code>, and
<code>filled-new-array/range</code> instructions must be a valid index
into the type constant pool.
</td>
-
+
<td>
4.8.1.16
</td>
</tr>
-
+
<tr>
<td>
A18
</td>
-
+
<td>
The <code>C</code> operand of the <code>instance-of</code>,
<code>new-array</code>, and <code>filled-new-array</code>
instructions must be a valid index into the type constant pool.
</td>
-
+
<td>
4.8.1.16
</td>
@@ -444,85 +444,85 @@
<td>
A19
</td>
-
+
<td>
The dimensions of an array created by a <code>new-array</code>
instruction must be less than <code>256</code>.
</td>
-
+
<td>
4.8.1.17
</td>
</tr>
-
+
<tr>
<td>
A20
</td>
-
+
<td>
The <code>new</code> instruction must not refer to array classes,
interfaces, or abstract classes.
</td>
-
+
<td>
4.8.1.18
</td>
</tr>
-
+
<tr>
<td>
A21
</td>
-
+
<td>
The type referred to by a <code>new-array</code> instruction must be
a valid, non-reference type.
</td>
-
+
<td>
4.8.1.20
</td>
</tr>
-
+
<tr>
<td>
A22
</td>
-
+
<td>
All registers referred to by an instruction in a single-width
(non-pair) fashion must be valid for the current method. That is,
their indices must be non-negative and smaller than
- <code>registers_size</code>.
+ <code>registers_size</code>.
</td>
-
+
<td>
4.8.1.21
</td>
</tr>
-
+
<tr>
<td>
A23
</td>
-
+
<td>
All registers referred to by an instruction in a double-width (pair)
fashion must be valid for the current method. That is, their indices
- must be non-negative and smaller than <code>registers_size-1</code>.
+ must be non-negative and smaller than <code>registers_size-1</code>.
</td>
-
+
<td>
4.8.1.23
</td>
</tr>
</table>
-
+
<h2>
Structural constraints
</h2>
-
+
<p>
Structural constraints are constraints on relationships between several
elements of the bytecode. They usually can't be checked without employing
@@ -534,291 +534,291 @@
<th>
Identifier
</th>
-
+
<th>
Description
</th>
-
+
<th>
Spec equivalent
</th>
</tr>
-
+
<tr>
<td>
B1
</td>
-
+
<td>
The number and types of arguments (registers and immediate values)
must always match the instruction.
</td>
-
+
<td>
4.8.2.1
</td>
</tr>
-
+
<tr>
<td>
B2
</td>
-
+
<td>
- Register pairs must never be broken up.
+ Register pairs must never be broken up.
</td>
-
+
<td>
4.8.2.3
</td>
</tr>
-
+
<tr>
<td>
B3
</td>
-
+
<td>
A register (or pair) has to be assigned first before it can be
read.
</td>
-
+
<td>
4.8.2.4
</td>
</tr>
-
+
<tr>
<td>
B4
</td>
-
+
<td>
An <code>invoke-direct</code> instruction must only invoke an instance
initializer or a method in the current class or one of its
- superclasses.
+ superclasses.
</td>
-
+
<td>
4.8.2.7
</td>
</tr>
-
+
<tr>
<td>
B5
</td>
-
+
<td>
An instance initializer must only be invoked on an uninitialized
instance.
</td>
-
+
<td>
4.8.2.8
</td>
</tr>
-
+
<tr>
<td>
B6
</td>
-
+
<td>
Instance methods may only be invoked on and instance fields may only
- be accessed on already initialized instances.
+ be accessed on already initialized instances.
</td>
-
+
<td>
4.8.2.9
</td>
</tr>
-
+
<tr>
<td>
B7
</td>
-
+
<td>
A register which holds the result of a <code>new-instance</code>code>
instruction must not be used if the same
<code>new-instance</code>code> instruction is again executed before
- the instance is initialized.
+ the instance is initialized.
</td>
-
+
<td>
4.8.2.10
</td>
</tr>
-
+
<tr>
<td>
B8
</td>
-
+
<td>
An instance initializer must call another instance initializer (same
class or superclass) before any instance members can be accessed.
Exceptions are non-inherited instance fields, which can be assigned
before calling another initializer, and the <code>Object</code> class
- in general.
+ in general.
</td>
-
+
<td>
4.8.2.11
</td>
</tr>
-
+
<tr>
<td>
B9
</td>
-
+
<td>
All actual method arguments must be assignment-compatible with their
- respective formal arguments.
+ respective formal arguments.
</td>
-
+
<td>
4.8.2.12
</td>
</tr>
-
+
<tr>
<td>
B10
</td>
-
+
<td>
For each instance method invocation, the actual instance must be
assignment-compatible with the class or interface specified in the
instruction.
</td>
-
+
<td>
4.8.2.13
</td>
</tr>
-
+
<tr>
<td>
B11
</td>
-
+
<td>
A <code>return<kind></code> instruction must match its
- method's return type.
+ method's return type.
</td>
-
+
<td>
4.8.2.14
</td>
</tr>
-
+
<tr>
<td>
B12
</td>
-
+
<td>
When accessing protected members of a superclass, the actual type of
the instance being accessed must be either the current class or one
of its subclasses.
</td>
-
+
<td>
4.8.2.15
</td>
</tr>
-
+
<tr>
<td>
B13
</td>
-
+
<td>
The type of a value stored into a static field must be
assignment-compatible with or convertible to the field's type.
</td>
-
+
<td>
4.8.2.16
</td>
</tr>
-
+
<tr>
<td>
B14
</td>
-
+
<td>
The type of a value stored into a field must be assignment-compatible
with or convertible to the field's type.
</td>
-
+
<td>
4.8.2.17
</td>
</tr>
-
+
<tr>
<td>
B15
</td>
-
+
<td>
The type of every value stored into an array must be
assignment-compatible with the array's component type.
</td>
-
+
<td>
4.8.2.18
</td>
</tr>
-
+
<tr>
<td>
B16
</td>
-
+
<td>
The <code>A</code> operand of a <code>throw</code> instruction must
- be assignment-compatible with <code>java.lang.Throwable</code>.
+ be assignment-compatible with <code>java.lang.Throwable</code>.
</td>
-
+
<td>
4.8.2.19
</td>
</tr>
-
+
<tr>
<td>
B17
</td>
-
+
<td>
The last reachable instruction of a method must either be a backwards
<code>goto</code> or branch, a <code>return</code>, or a
<code>throw</code> instruction. It must not be possible to leave the
<code>insns</code> array at the bottom.
</td>
-
+
<td>
4.8.2.20
</td>
</tr>
-
+
<tr>
<td>
B18
</td>
-
+
<td>
The unassigned half of a former register pair may not be read (is
considered invalid) until it has been re-assigned by some other
instruction.
- </td>
-
+ </td>
+
<td>
4.8.2.3, 4.8.2.4
</td>
@@ -828,15 +828,15 @@
<td>
B19
</td>
-
+
<td>
A <code>move-result<kind></code> instruction must be immediately
preceded (in the <code>insns</code> array) by an
<code><invoke-kind></code> instruction. The only exception is
the <code>move-result-object</code> instruction, which may also be
- preceded by a <code>filled-new-array</code> instruction.
+ preceded by a <code>filled-new-array</code> instruction.
</td>
-
+
<td>
-
</td>
@@ -846,16 +846,16 @@
<td>
B20
</td>
-
+
<td>
A <code>move-result<kind></code> instruction must be immediately
preceded (in actual control flow) by a matching
<code>return-<kind></code> instruction (it must not be jumped
to). The only exception is the <code>move-result-object</code>
instruction, which may also be preceded by a
- <code>filled-new-array</code> instruction.
+ <code>filled-new-array</code> instruction.
</td>
-
+
<td>
-
</td>
@@ -865,28 +865,28 @@
<td>
B21
</td>
-
+
<td>
A <code>move-exception</code> instruction must only appear as the
first instruction in an exception handler.
</td>
-
+
<td>
-
</td>
</tr>
-
+
<tr>
<td>
B22
</td>
-
+
<td>
The <code>packed-switch-data</code>, <code>sparse-switch-data</code>,
and <code>fill-array-data</code> pseudo-instructions must not be
reachable by control flow.
</td>
-
+
<td>
-
</td>
diff --git a/docs/dex-format.css b/docs/dex-format.css
index 17e935f..153dd4e 100644
--- a/docs/dex-format.css
+++ b/docs/dex-format.css
@@ -85,13 +85,13 @@
background: #eeeeff;
}
-table p {
+table p {
margin-bottom: 0pt;
}
/* for the bnf syntax sections */
-table.bnf {
+table.bnf {
background: #eeeeff;
border-color: #aaaaff;
border-style: solid;
@@ -104,7 +104,7 @@
padding-right: 6pt;
}
-table.bnf td {
+table.bnf td {
border: none;
padding-left: 6pt;
padding-right: 6pt;
@@ -112,12 +112,12 @@
padding-bottom: 1pt;
}
-table.bnf td:first-child {
+table.bnf td:first-child {
padding-right: 0pt;
width: 8pt;
}
-table.bnf td:first-child td {
+table.bnf td:first-child td {
padding-left: 0pt;
}
diff --git a/docs/dex-format.html b/docs/dex-format.html
index bc69dd0..cab9d4c 100644
--- a/docs/dex-format.html
+++ b/docs/dex-format.html
@@ -1305,7 +1305,7 @@
<tr>
<td>data_off</td>
<td>uint</td>
- <td>offset from the start of the file to the start of the
+ <td>offset from the start of the file to the start of the
<code>data</code> section.
</td>
</tr>
@@ -1559,7 +1559,7 @@
<td>data</td>
<td>ubyte[]</td>
<td>a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes)
- followed by a byte of value <code>0</code>. See
+ followed by a byte of value <code>0</code>. See
"MUTF-8 (Modified UTF-8) Encoding" above for details and
discussion about the data format.
<p><b>Note:</b> It is acceptable to have a string which includes
@@ -1892,7 +1892,7 @@
</tbody>
</table>
-<p><b>Note:</b> All elements' <code>field_id</code>s and
+<p><b>Note:</b> All elements' <code>field_id</code>s and
<code>method_id</code>s must refer to the same defining class.</p>
<h3><code>encoded_field</code> Format</h3>
@@ -2055,10 +2055,10 @@
<tr>
<td>debug_info_off</td>
<td>uint</td>
- <td>offset from the start of the file to the debug info (line numbers +
- local variable info) sequence for this code, or <code>0</code> if
- there simply is no information. The offset, if non-zero, should be
- to a location in the <code>data</code> section. The format of
+ <td>offset from the start of the file to the debug info (line numbers +
+ local variable info) sequence for this code, or <code>0</code> if
+ there simply is no information. The offset, if non-zero, should be
+ to a location in the <code>data</code> section. The format of
the data is specified by "<code>debug_info_item</code>" below.
</td>
</tr>
@@ -2258,7 +2258,7 @@
should be associated with the next positions table entry emitted by
the state machine. It is initialized in the sequence header, and may
change in positive or negative directions but must never be less than
-<code>1</code>. The <code>source_file</code> register represents the
+<code>1</code>. The <code>source_file</code> register represents the
source file that the line number entries refer to. It is initialized to
the value of <code>source_file_idx</code> in <code>class_def_item</code>.
The other two variables, <code>prologue_end</code> and
@@ -2282,7 +2282,7 @@
<tr>
<td>line_start</td>
<td>uleb128</td>
- <td>the initial value for the state machine's <code>line</code> register.
+ <td>the initial value for the state machine's <code>line</code> register.
Does not represent an actual positions entry.
</td>
</tr>
@@ -2351,7 +2351,7 @@
<code>name_idx</code>: string index of the name<br/>
<code>type_idx</code>: type index of the type
</td>
- <td>introduces a local variable at the current address. Either
+ <td>introduces a local variable at the current address. Either
<code>name_idx</code> or <code>type_idx</code> may be
<code>NO_INDEX</code> to indicate that that value is unknown.
</td>
@@ -2363,7 +2363,7 @@
uleb128p1 name_idx<br/>
uleb128p1 type_idx<br/>
uleb128p1 sig_idx
- </td>
+ </td>
<td><code>register_num</code>: register that will contain local<br/>
<code>name_idx</code>: string index of the name<br/>
<code>type_idx</code>: type index of the type<br/>
@@ -2385,7 +2385,7 @@
<td>0x05</td>
<td>uleb128 register_num</td>
<td><code>register_num</code>: register that contained local</td>
- <td>marks a currently-live local variable as out of scope at the current
+ <td>marks a currently-live local variable as out of scope at the current
address
</td>
</tr>
@@ -2404,9 +2404,9 @@
<td>0x07</td>
<td></td>
<td><i>(none)</i></td>
- <td>sets the <code>prologue_end</code> state machine register,
- indicating that the next position entry that is added should be
- considered the end of a method prologue (an appropriate place for
+ <td>sets the <code>prologue_end</code> state machine register,
+ indicating that the next position entry that is added should be
+ considered the end of a method prologue (an appropriate place for
a method breakpoint). The <code>prologue_end</code> register is
cleared by any special (<code>>= 0x0a</code>) opcode.
</td>
@@ -2416,9 +2416,9 @@
<td>0x08</td>
<td></td>
<td><i>(none)</i></td>
- <td>sets the <code>epilogue_begin</code> state machine register,
- indicating that the next position entry that is added should be
- considered the beginning of a method epilogue (an appropriate place
+ <td>sets the <code>epilogue_begin</code> state machine register,
+ indicating that the next position entry that is added should be
+ considered the beginning of a method epilogue (an appropriate place
to suspend execution before method exit).
The <code>epilogue_begin</code> register is cleared by any special
(<code>>= 0x0a</code>) opcode.
@@ -2427,7 +2427,7 @@
<tr>
<td>DBG_SET_FILE</td>
<td>0x09</td>
- <td>uleb128p1 name_idx</td>
+ <td>uleb128p1 name_idx</td>
<td><code>name_idx</code>: string index of source file name;
<code>NO_INDEX</code> if unknown
</td>
@@ -2438,7 +2438,7 @@
</tr>
<tr>
<td><i>Special Opcodes</i></td>
- <!-- When updating the range below, make sure to search for other
+ <!-- When updating the range below, make sure to search for other
instances of 0x0a in this section. -->
<td>0x0a…0xff</td>
<td></td>
@@ -2532,7 +2532,7 @@
</tbody>
</table>
-<p><b>Note:</b> All elements' <code>field_id</code>s and
+<p><b>Note:</b> All elements' <code>field_id</code>s and
<code>method_id</code>s must refer to the same defining class.</p>
<h3><code>field_annotation</code> Format</h3>
diff --git a/docs/embedded-vm-control.html b/docs/embedded-vm-control.html
index e3797f3..ec2b694 100644
--- a/docs/embedded-vm-control.html
+++ b/docs/embedded-vm-control.html
@@ -16,6 +16,7 @@
<li><a href="#dp">Deadlock Prediction</a>
<li><a href="#stackdump">Stack Dumps</a>
<li><a href="#dexcheck">DEX File Checksums</a>
+ <li><a href="#general">General Flags</a>
</ul>
<h2><a name="introduction">Introduction (read this first!)</a></h2>
@@ -288,6 +289,22 @@
to check for corruption in a large set of files.
+<h2><a name="general">General Flags</a></h2>
+
+<p>In the "Honeycomb" release, a general mechanism for passing flags to
+the VM was introduced:
+
+<pre>adb shell setprop dalvik.vm.extra-opts "flag1 flag2 ... flagN"</pre>
+
+<p>The flags are separated by spaces. You can specify as many as you want
+so long as they all fit within the system property value length limit
+(currently 92 characters).
+
+<p>The extra-opts flags will be added at the end of the command line,
+which means they will override earlier settings. This can be used, for
+example, to experiment with different values for <code>-Xmx</code> even
+though the Android framework is setting it explicitly.
+
<address>Copyright © 2008 The Android Open Source Project</address>
</body></html>
diff --git a/docs/heap-profiling.html b/docs/heap-profiling.html
index 3570fdb..ca0c2bc 100644
--- a/docs/heap-profiling.html
+++ b/docs/heap-profiling.html
@@ -165,12 +165,27 @@
</p>
-<h3>Android 2.2 ("Froyo")</h3>
+<h3>Android 2.2 ("Froyo"), Android 2.x ("Gingerbread")</h3>
<p>
DDMS heap dump requests are now streamed directly out of the VM, removing
the external storage requirement.
</p>
+<h3>Android 2.x ("Honeycomb")</h3>
+<p>
+The <code>kill -10</code> (<code>SIGUSR1</code>) method of generating heap
+dumps has been removed, in favor of a much more useful shell command:
+</p>
+<blockquote><pre>am dumpheap <pid> <output-file-name></pre></blockquote>
+<p>
+Unlike the <code>SIGUSR1</code> approach, this does not require a rooted
+phone. It's only necessary for the application to be debuggable (by setting
+<code>android:debuggable="true"</code> in the <code><application></code>
+element of the app manifest). The output file is opened by "am", which
+means you can write the data to a file on <code>/sdcard</code> without
+needing the <code>WRITE_EXTERNAL_STORAGE</code> permission.
+</p>
+
<h2>Examining the data</h2>
<p>
The data file format was augmented slightly from the common hprof format,
diff --git a/docs/hello-world.html b/docs/hello-world.html
index dbbaea6..7491a28 100644
--- a/docs/hello-world.html
+++ b/docs/hello-world.html
@@ -22,7 +22,7 @@
% <font color="green">dx --dex --output=foo.jar Foo.class</font><br>
% <font color="green">adb push foo.jar /sdcard</font><br>
% <font color="green">adb shell dalvikvm -cp /sdcard/foo.jar Foo</font><br>
-Hello, world
+Hello, world
</code>
</p><p>
The <code>-cp</code> option sets the classpath. The initial directory
diff --git a/docs/instruction-formats.css b/docs/instruction-formats.css
index ee23c5c..a2dc42f 100644
--- a/docs/instruction-formats.css
+++ b/docs/instruction-formats.css
@@ -124,6 +124,6 @@
width: 22%;
}
-table.format p {
+table.format p {
margin-bottom: 0pt;
}
\ No newline at end of file
diff --git a/docs/java-bytecode.css b/docs/java-bytecode.css
index 6075c0d..48984b2 100644
--- a/docs/java-bytecode.css
+++ b/docs/java-bytecode.css
@@ -10,7 +10,7 @@
}
}
-h1 {
+h1 {
text-align: center;
}
@@ -26,16 +26,16 @@
border-width: 0;
}
-td.outer {
+td.outer {
width: 25%;
padding: 0;
}
-td.outer table {
+td.outer table {
width: 100%;
}
-td.outer td {
+td.outer td {
border-width: 0;
background: #f8f8f8;
padding: 1pt;
@@ -43,11 +43,11 @@
padding-right: 2pt;
}
-tr.d td {
+tr.d td {
background: #dddddd;
}
-td.outer td + td + td {
+td.outer td + td + td {
font-family: monospace;
font-weight: bold;
padding-right: 5pt;
diff --git a/docs/java-constraints.html b/docs/java-constraints.html
index 2410a1e..9d3c434 100644
--- a/docs/java-constraints.html
+++ b/docs/java-constraints.html
@@ -30,7 +30,7 @@
constraint will fail during the Dx conversion or during verification in
the VM itself.
</p>
-
+
<h2>
Static constraints
</h2>
@@ -40,311 +40,311 @@
They usually can be checked without employing control or data-flow analysis
techniques.
</p>
-
+
<table>
<tr>
<th>
Identifier
</th>
-
+
<th>
Description
</th>
-
+
<th>
Spec equivalent
</th>
-
+
<th>
Failure mode
</th>
</tr>
-
+
<tr>
<td>
A1
</td>
-
+
<td>
- The <code>code</code> array must not be empty.
+ The <code>code</code> array must not be empty.
</td>
-
+
<td>
4.8.1.1
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A2
</td>
-
+
<td>
- The <code>code</code> array must not be larger than 65535 bytes.
+ The <code>code</code> array must not be larger than 65535 bytes.
</td>
-
+
<td>
4.8.1.2
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A3
</td>
-
+
<td>
The first opcode in <code>code</code> array must have index
<code>0</code>.
</td>
-
+
<td>
4.8.1.3
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A4
</td>
-
+
<td>
The <code>code</code> array must only contain valid opcodes.
</td>
-
+
<td>
4.8.1.4
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A5
</td>
-
+
<td>
The index of instruction <code>n+1</code> must equal the index of
instruction <code>n</code> plus the length of instruction
<code>n</code>, taking into account a possible <code>wide</code>
instruction. Opcodes modified by a <code>wide</code> instruction must
- not be directly reachable.
+ not be directly reachable.
</td>
-
+
<td>
4.8.1.5
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A6
</td>
-
+
<td>
The last instruction in <code>code</code> array must end at index
- <code>code_length-1</code>.
+ <code>code_length-1</code>.
</td>
-
+
<td>
4.8.1.6
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A7
</td>
-
+
<td>
All jump and branch targets must be opcodes within the same method.
Opcodes modified by a <code>wide</code> instruction must not be
- directly reachable via a jump or branch instruction.
+ directly reachable via a jump or branch instruction.
</td>
-
+
<td>
4.8.1.7
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A8
</td>
-
+
<td>
All targets of a <code>tableswitch</code> instruction must be opcodes
within the same method. Upper and lower bounds must be consistent.
Opcodes modified by a <code>wide</code> instruction must not be
- directly reachable via a <code>tableswitch</code> instruction.
+ directly reachable via a <code>tableswitch</code> instruction.
</td>
-
+
<td>
4.8.1.8
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A9
</td>
-
+
<td>
All targets of a <code>lookupswitch</code> instruction must be opcodes
within the same method. Its table must be consistent and sorted
low-to-high. Opcodes modified by a <code>wide</code> instruction must
- not be directly reachable via a <code>lookupswitch</code> instruction.
+ not be directly reachable via a <code>lookupswitch</code> instruction.
</td>
-
+
<td>
4.8.1.9
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A10
</td>
-
+
<td>
The operands of <code>ldc</code> and <code>ldc_w</code> instructions
must be valid indices into the constant pool. The respective entries
must be of type <code>CONSTANT_Integer</code>,
- <code>CONSTANT_Float</code>, or <code>CONSTANT_String</code>.
+ <code>CONSTANT_Float</code>, or <code>CONSTANT_String</code>.
</td>
-
+
<td>
4.8.1.10
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A11
</td>
-
+
<td>
The operands of <code>ldc2_w</code> instructions must be valid indices
into the constant pool. The respective entries must be of type
<code>CONSTANT_Long</code> or <code>CONSTANT_Double</code>. The
subsequent constant pool entry must be valid and remain unused.
</td>
-
+
<td>
4.8.1.11
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A12
</td>
-
+
<td>
The Operands of <code>get<kind></code> and
<code>put<kind></code> instructions must be valid indices into
constant pool. The respective entries must be of type
<code>CONSTANT_Fieldref</code>.
</td>
-
+
<td>
4.8.1.12
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A13
</td>
-
+
<td>
The first two operands of <code>invokevirtual</code>,
<code>invokespecial</code>, and <code>invokestatic</code> must form a
valid 16-bit index into the constant pool. The respective entries must
be of type <code>CONSTANT_Methodref</code>.
</td>
-
+
<td>
4.8.1.13
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A14
</td>
-
+
<td>
Methods whose names start with '<' must only be invoked implicitly by
the VM, not by class file code. The only exception is the instance
initializer, which may be invoked by <code>invokespecial</code>.
</td>
-
+
<td>
4.8.1.14
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A15
</td>
-
+
<td>
The first two operands of <code>invokeinterface</code> must form a
valid 16-bit index into the constant pool. The entry must be of type
@@ -352,21 +352,21 @@
specify number of local variables and the fourth operand must always
be zero.
</td>
-
+
<td>
4.8.1.15
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A16
</td>
-
+
<td>
The operands of <code>instanceof</code>, <code>checkcast</code>,
<code>new</code>, and <code>anewarray</code> instructions must
@@ -375,218 +375,218 @@
into the constant pool. All respective entries must be of type
<code>CONSTANT_Class</code>.
</td>
-
+
<td>
4.8.1.16
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A17
</td>
-
+
<td>
The dimensions of an array created by <code>anewarray</code>
instructions must be less than <code>256</code>.
</td>
-
+
<td>
4.8.1.17
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A18
</td>
-
+
<td>
The <code>new</code> instruction must not reference array classes,
interfaces, or abstract classes.
</td>
-
+
<td>
4.8.1.18
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A19
</td>
-
+
<td>
The type referenced by a <code>multinewarray</code> instruction must
have at least as many dimensions as specified in the instruction. The
- dimensions operand must not be <code>0</code>
+ dimensions operand must not be <code>0</code>
</td>
-
+
<td>
4.8.1.19
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A20
</td>
-
+
<td>
The type referenced by a <code>newarray</code> instruction must be a
valid, non-reference type.
</td>
-
+
<td>
4.8.1.20
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A21
</td>
-
+
<td>
The index operand of instructions explicitly referencing single-width
local variables must be non-negative and smaller than
<code>max_locals</code>.
</td>
-
+
<td>
4.8.1.21
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A22
</td>
-
+
<td>
The index operand of instructions implicitly referencing single-width
local variables must be non-negative and smaller than
<code>max_locals</code>.
</td>
-
+
<td>
4.8.1.22
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A23
</td>
-
+
<td>
The index operand of instructions explicitly referencing double-width
local variables must be non-negative and smaller than
<code>max_locals-1</code>.
</td>
-
+
<td>
4.8.1.23
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A24
</td>
-
+
<td>
The index operand of instructions implicitly referencing double-width
local variables must be non-negative and smaller than
<code>max_locals-1</code>.
</td>
-
+
<td>
4.8.1.24
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A25
</td>
-
+
<td>
The index operand of <code>wide</code> instructions explicitly
referencing single-width local variables must be non-negative and
smaller than <code>max_locals</code>.
</td>
-
+
<td>
4.8.1.25
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
A26
</td>
-
+
<td>
The index operand of <code>wide</code> instructions explicitly
referencing double-width local variables must be non-negative and
smaller than <code>max_locals-1</code>.
</td>
-
+
<td>
4.8.1.25
</td>
-
+
<td>
DX
</td>
</tr>
</table>
-
+
<h2>
Structural constraints
</h2>
-
+
<p>
Structural constraints are constraints on relationships between several
elements of the bytecode. They usually can't be checked without employing
@@ -598,466 +598,466 @@
<th>
Identifier
</th>
-
+
<th>
Description
</th>
-
+
<th>
Spec equivalent
</th>
-
+
<th>
Failure mode
</th>
</tr>
-
+
<tr>
<td>
B1
</td>
-
+
<td>
The number and types of arguments (operands and local variables) must
always match the instruction.
</td>
-
+
<td>
4.8.2.1
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B2
</td>
-
+
<td>
The operand stack must have the same depth for all executions paths
- leading to an instruction.
+ leading to an instruction.
</td>
-
+
<td>
4.8.2.2
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B3
</td>
-
+
<td>
- Local variable pairs must never be broken up.
+ Local variable pairs must never be broken up.
</td>
-
+
<td>
4.8.2.3
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B4
</td>
-
+
<td>
A local variable (or pair) has to be assigned first before it can be
read.
</td>
-
+
<td>
4.8.2.4
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B5
</td>
-
+
<td>
- The operand stack must never grow beyond <code>max_stack</code>.
+ The operand stack must never grow beyond <code>max_stack</code>.
</td>
-
+
<td>
4.8.2.5
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B6
</td>
-
+
<td>
- The operand stack must never underflow.
+ The operand stack must never underflow.
</td>
-
+
<td>
4.8.2.6
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B7
</td>
-
+
<td>
An <code>invokespecial</code> instruction must only invoke an instance
initializer or a method in the current class or one of its
- superclasses.
+ superclasses.
</td>
-
+
<td>
4.8.2.7
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B8
</td>
-
+
<td>
An instance initializer must only be invoked on an uninitialized
- instance residing on the operand stack.
+ instance residing on the operand stack.
</td>
-
+
<td>
4.8.2.8
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B9
</td>
-
+
<td>
Instance methods may only be invoked on and instance fields may only
- be accessed on already initialized instances.
+ be accessed on already initialized instances.
</td>
-
+
<td>
4.8.2.9
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B10
</td>
-
+
<td>
The must be no backwards branches with uninitialized instances on the
operand stack or in local variables. There must be no code protected
by an exception handler that contains local variables with
uninitialized instances.
</td>
-
+
<td>
4.8.2.10
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B11
</td>
-
+
<td>
An instance initializer must call another instance initializer (same
class or superclass) before any instance members can be accessed.
Exceptions are non-inherited instance fields, which can be assigned
before calling another initializer, and the <code>Object</code> class
- in general.
+ in general.
</td>
-
+
<td>
4.8.2.11
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B12
</td>
-
+
<td>
All actual method arguments must be assignment-compatible with formal
- arguments.
+ arguments.
</td>
-
+
<td>
4.8.2.12
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B13
</td>
-
+
<td>
For each instance method invocation, the actual instance must be
assignment-compatible with the class or interface specified in the
instruction.
</td>
-
+
<td>
4.8.2.13
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B14
</td>
-
+
<td>
- A returns instruction must match its method's return type.
+ A returns instruction must match its method's return type.
</td>
-
+
<td>
4.8.2.14
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B15
</td>
-
+
<td>
When accessing protected members of a superclass, the actual type of
the instance being accessed must be either the current class or one
of its subclasses.
</td>
-
+
<td>
4.8.2.15
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B16
</td>
-
+
<td>
The type of a value stored into a static field must be
assignment-compatible with or convertible to the field's type.
</td>
-
+
<td>
4.8.2.16
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B17
</td>
-
+
<td>
The type of a value stored into a field must be assignment-compatible
with or convertible to the field's type.
</td>
-
+
<td>
4.8.2.17
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B18
</td>
-
+
<td>
The type of every value stored into an array must be
assignment-compatible with the array's component type.
</td>
-
+
<td>
4.8.2.18
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B19
</td>
-
+
<td>
The operand of an <code>athrow</code> instruction must be
- assignment-compatible with <code>java.lang.Throwable</code>.
+ assignment-compatible with <code>java.lang.Throwable</code>.
</td>
-
+
<td>
4.8.2.19
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B20
</td>
-
+
<td>
The last reachable instruction of a method must either be a backwards
jump or branch, a return, or an <code>athrow</code> instruction. It
must not be possible to leave the <code>code</code> array at the
bottom.
</td>
-
+
<td>
4.8.2.20
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B21
</td>
-
+
<td>
Local variable values must not be used as return addresses.
</td>
-
+
<td>
4.8.2.21
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B22
</td>
-
+
<td>
There must be a single, uniquely determined return instruction per
subroutine call.
</td>
-
+
<td>
4.8.2.22
</td>
-
+
<td>
VM
</td>
</tr>
-
+
<tr>
<td>
B23
</td>
-
+
<td>
Subroutine calls must not be directly or indirectly self-recursive.
</td>
-
+
<td>
4.8.2.23
</td>
-
+
<td>
DX
</td>
</tr>
-
+
<tr>
<td>
B24
</td>
-
+
<td>
<code>ReturnAddress</code> instances must not be reused. If a
subroutine returns to a <code>ReturnAddress</code> further up the
@@ -1065,16 +1065,16 @@
<code>ReturnAddress</code> instances further down the stack must
never be used.
</td>
-
+
<td>
4.8.2.24
</td>
-
+
<td>
DX
</td>
</tr>
-
+
</table>
</body>
</html>
diff --git a/docs/jni-tips.html b/docs/jni-tips.html
index 3d2f347..76cb03f 100644
--- a/docs/jni-tips.html
+++ b/docs/jni-tips.html
@@ -124,7 +124,7 @@
* class/field/method IDs for this class. Returns false on failure.
*/
native private static boolean nativeClassInit();
-
+
/*
* Invoke the native initializer when the class is loaded.
*/
@@ -410,7 +410,7 @@
</p>
<ul>
<li> Check for null pointers where not allowed.
-<li>
+</li>
<li> Verify argument type correctness (jclass is a class object,
jfieldID points to field data, jstring is a java.lang.String).
</li>
diff --git a/docs/libraries.html b/docs/libraries.html
index e1c3035..ed2fa72 100644
--- a/docs/libraries.html
+++ b/docs/libraries.html
@@ -6,7 +6,7 @@
<head>
<title>Dalvik Libraries</title>
-
+
<link rel=stylesheet href="dex-format.css">
<link href="prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="prettify.js"></script>
diff --git a/docs/opcodes/opcode-04-move-wide.html b/docs/opcodes/opcode-04-move-wide.html
index e043be9..8a3bd00 100644
--- a/docs/opcodes/opcode-04-move-wide.html
+++ b/docs/opcodes/opcode-04-move-wide.html
@@ -19,7 +19,7 @@
<p>
Note: It is legal to move from vN to either vN-1 or vN+1, so implementations
must arrange for both halves of a register pair to be read before anything is
-written.
+written.
</p>
<h2>Details</h2>
diff --git a/docs/opcodes/opcode-07-move-object.html b/docs/opcodes/opcode-07-move-object.html
index e62750d..f290277 100644
--- a/docs/opcodes/opcode-07-move-object.html
+++ b/docs/opcodes/opcode-07-move-object.html
@@ -79,7 +79,7 @@
becomes undefined.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-0a-move-result.html b/docs/opcodes/opcode-0a-move-result.html
index f043d13..616087f 100644
--- a/docs/opcodes/opcode-0a-move-result.html
+++ b/docs/opcodes/opcode-0a-move-result.html
@@ -17,7 +17,7 @@
Move the single-word non-object result of the most recent invoke-kind into the
indicated register. This must be done as the instruction immediately after an
invoke-kind whose (single-word, non-object) result is not to be ignored;
-anywhere else is invalid.
+anywhere else is invalid.
</p>
<h2>Details</h2>
@@ -57,7 +57,7 @@
<li>
The result delivered by the invoke-kind instruction must not be a reference
value or require a register pair.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -76,7 +76,7 @@
becomes undefined.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
@@ -89,7 +89,7 @@
This instruction can also be thought of as reading the contents of a special
"result" register that is made valid and defined by executing a non-void return
instruction or a filled-new-array instruction. The execution of any other
-instruction (including this one) renders this special register invalid.
+instruction (including this one) renders this special register invalid.
</p>
</body>
diff --git a/docs/opcodes/opcode-0b-move-result-wide.html b/docs/opcodes/opcode-0b-move-result-wide.html
index c3e5779..c53517a 100644
--- a/docs/opcodes/opcode-0b-move-result-wide.html
+++ b/docs/opcodes/opcode-0b-move-result-wide.html
@@ -17,7 +17,7 @@
Move the double-word result of the most recent invoke-kind into the indicated
register pair. This must be done as the instruction immediately after an
invoke-kind whose (double-word) result is not to be ignored; anywhere else is
-invalid.
+invalid.
</p>
<h2>Details</h2>
@@ -60,7 +60,7 @@
or a double value.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
@@ -81,7 +81,7 @@
becomes undefined.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-0c-move-result-object.html b/docs/opcodes/opcode-0c-move-result-object.html
index f065fed..1538735 100644
--- a/docs/opcodes/opcode-0c-move-result-object.html
+++ b/docs/opcodes/opcode-0c-move-result-object.html
@@ -77,7 +77,7 @@
becomes undefined.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
@@ -90,7 +90,7 @@
This instruction can also be thought of as reading the contents of a special
"result" register that is made valid and defined by executing a non-void return
instruction or a filled-new-array instruction. The execution of any other
-instruction (including this one) renders this special register invalid.
+instruction (including this one) renders this special register invalid.
</p>
</body>
diff --git a/docs/opcodes/opcode-0d-move-exception.html b/docs/opcodes/opcode-0d-move-exception.html
index 3c3bc83..0f756d0 100644
--- a/docs/opcodes/opcode-0d-move-exception.html
+++ b/docs/opcodes/opcode-0d-move-exception.html
@@ -17,7 +17,7 @@
Save a just-caught exception into the given register. This should be the first
instruction of any exception handler whose caught exception is not to be
ignored, and this instruction may only ever occur as the first instruction of an
-exception handler; anywhere else is invalid.
+exception handler; anywhere else is invalid.
</p>
<h2>Details</h2>
@@ -51,7 +51,7 @@
the handlers defined for the method in the Dex file.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
diff --git a/docs/opcodes/opcode-0e-return-void.html b/docs/opcodes/opcode-0e-return-void.html
index 7a9431e..0498f81 100644
--- a/docs/opcodes/opcode-0e-return-void.html
+++ b/docs/opcodes/opcode-0e-return-void.html
@@ -14,7 +14,7 @@
<h2>Purpose</h2>
<p>
-Return from a void method.
+Return from a void method.
</p>
<h2>Details</h2>
@@ -72,8 +72,8 @@
</li>
</ul>
</li>
-</ul>
-
+</ul>
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-0f-return.html b/docs/opcodes/opcode-0f-return.html
index 33e0b7c..4de55ea 100644
--- a/docs/opcodes/opcode-0f-return.html
+++ b/docs/opcodes/opcode-0f-return.html
@@ -52,8 +52,8 @@
<li>
The type of vA must match the return type of the method.
</li>
-</ul>
-
+</ul>
+
<h2>Behavior</h2>
<ul>
@@ -89,7 +89,7 @@
</ul>
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-10-return-wide.html b/docs/opcodes/opcode-10-return-wide.html
index f1a6b83..4ccfce4 100644
--- a/docs/opcodes/opcode-10-return-wide.html
+++ b/docs/opcodes/opcode-10-return-wide.html
@@ -53,7 +53,7 @@
The type of vA must match the return type of the method.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
diff --git a/docs/opcodes/opcode-11-return-object.html b/docs/opcodes/opcode-11-return-object.html
index 369233c..b4866ed 100644
--- a/docs/opcodes/opcode-11-return-object.html
+++ b/docs/opcodes/opcode-11-return-object.html
@@ -84,7 +84,7 @@
</li>
</ul>
</li>
-</ul>
+</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-12-const.html b/docs/opcodes/opcode-12-const.html
index b2d894f..d2b6ef9 100644
--- a/docs/opcodes/opcode-12-const.html
+++ b/docs/opcodes/opcode-12-const.html
@@ -15,7 +15,7 @@
<p>
Move the given literal value (sign-extended to 32 bits, if necessary) into the
-specified register.
+specified register.
</p>
<h2>Details</h2>
@@ -72,7 +72,7 @@
<ul>
<li>
If we are executing the /high16 variant, then B is left-shifted by 16
- bits, that is, B'=B << 0x10
+ bits, that is, B'=B << 0x10
<li>
Otherwise, if B is a 4 bit or 16 bit constant, it is sign-extended to 32
bits, that is, B'=sign-extended(B).
@@ -91,7 +91,7 @@
If v(A+1) is the upper half of a register pair, v(A+1)' becomes undefined.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-16-const-wide.html b/docs/opcodes/opcode-16-const-wide.html
index ac92b04..6197e35 100644
--- a/docs/opcodes/opcode-16-const-wide.html
+++ b/docs/opcodes/opcode-16-const-wide.html
@@ -15,7 +15,7 @@
<p>
Move the given literal value (sign-extended to 64 bits) into the specified
-register-pair.
+register-pair.
</p>
<h2>Details</h2>
@@ -98,7 +98,7 @@
<li>
If v(A+2) is the upper half of a register pair, v(A+2)' becomes undefined.
</li>
-</ul>
+</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-1a-const-string.html b/docs/opcodes/opcode-1a-const-string.html
index bd89b70..d10c115 100644
--- a/docs/opcodes/opcode-1a-const-string.html
+++ b/docs/opcodes/opcode-1a-const-string.html
@@ -15,7 +15,7 @@
<p>
Move a reference to the string specified by the given index into the specified
-register.
+register.
</p>
<h2>Details</h2>
@@ -52,7 +52,7 @@
</li>
<li>
B must be a valid index into the string constant pool.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -72,7 +72,7 @@
</li>
<li>
If v(A+1) is the upper half of a register pair, v(A+1)' becomes undefined.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-1b-const-class.html b/docs/opcodes/opcode-1b-const-class.html
index 7a33e77..f40b986 100644
--- a/docs/opcodes/opcode-1b-const-class.html
+++ b/docs/opcodes/opcode-1b-const-class.html
@@ -16,7 +16,7 @@
<p>
Move a reference to the class specified by the given index into the specified
register. In the case where the indicated type is primitive, this will store a
-reference to the primitive type's degenerate class.
+reference to the primitive type's degenerate class.
</p>
<h2>Details</h2>
diff --git a/docs/opcodes/opcode-1d-monitor-enter.html b/docs/opcodes/opcode-1d-monitor-enter.html
index cecc939..28c10f4 100644
--- a/docs/opcodes/opcode-1d-monitor-enter.html
+++ b/docs/opcodes/opcode-1d-monitor-enter.html
@@ -14,7 +14,7 @@
<h2>Purpose</h2>
<p>
-Acquire the monitor for the indicated object.
+Acquire the monitor for the indicated object.
</p>
<h2>Details</h2>
@@ -46,7 +46,7 @@
Register vA must contain a reference to an object.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
diff --git a/docs/opcodes/opcode-1e-monitor-exit.html b/docs/opcodes/opcode-1e-monitor-exit.html
index bee711d..cd7b165 100644
--- a/docs/opcodes/opcode-1e-monitor-exit.html
+++ b/docs/opcodes/opcode-1e-monitor-exit.html
@@ -25,7 +25,7 @@
catch-all (e.g., finally) block as the monitor cleanup for that block itself,
as a way to handle the arbitrary exceptions that might get thrown due to the
historical implementation of Thread.stop(), while still managing to have proper
-monitor hygiene.
+monitor hygiene.
</p>
<h2>Details</h2>
@@ -57,7 +57,7 @@
Register vA must contain a reference to an object.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
@@ -83,7 +83,7 @@
an exception handler it cannot be distinguished from the same type of
exception being thrown immediately after the monitor-exit instruction.
</li>
-</ul>
+</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-1f-check-cast.html b/docs/opcodes/opcode-1f-check-cast.html
index 6325ca4..8eedd2d 100644
--- a/docs/opcodes/opcode-1f-check-cast.html
+++ b/docs/opcodes/opcode-1f-check-cast.html
@@ -15,7 +15,7 @@
<p>
Throw if the reference in the given register cannot be cast to the indicated
-type. The type must be a reference type (not a primitive type).
+type. The type must be a reference type (not a primitive type).
</p>
<h2>Details</h2>
@@ -53,8 +53,8 @@
<li>
Type pool entry B must contain a valid type descriptor for a reference type.
</li>
-</ul>
-
+</ul>
+
<h2>Behavior</h2>
<ul>
diff --git a/docs/opcodes/opcode-20-instance-of.html b/docs/opcodes/opcode-20-instance-of.html
index 5dbfef7..88076d8 100644
--- a/docs/opcodes/opcode-20-instance-of.html
+++ b/docs/opcodes/opcode-20-instance-of.html
@@ -55,7 +55,7 @@
<li>
Type constant pool entry C must contain a valid type descriptor for a
reference type.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -88,7 +88,7 @@
</li>
<li>
If v(A+1) is the upper half of a register pair, v(A+1)' becomes undefined.
- </li>
+ </li>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-21-array-length.html b/docs/opcodes/opcode-21-array-length.html
index 5767742..8072a7c 100644
--- a/docs/opcodes/opcode-21-array-length.html
+++ b/docs/opcodes/opcode-21-array-length.html
@@ -48,7 +48,7 @@
Register vB must contain a reference to an array.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
diff --git a/docs/opcodes/opcode-22-new-instance.html b/docs/opcodes/opcode-22-new-instance.html
index ec0a347..bdcfc3e 100644
--- a/docs/opcodes/opcode-22-new-instance.html
+++ b/docs/opcodes/opcode-22-new-instance.html
@@ -15,7 +15,7 @@
<p>
Construct a new instance of the indicated type, storing a reference to it in the
-destination. The type must refer to a non-array class.
+destination. The type must refer to a non-array class.
</p>
<h2>Details</h2>
@@ -77,7 +77,7 @@
</li>
<li>
If v(A+1) is the upper part of a register pair, v(A+1)' becomes undefined.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
@@ -88,7 +88,7 @@
</li>
<li>
All exceptions that are possible during instantiation can occur.
- </li>
+ </li>
</ul>
</body>
diff --git a/docs/opcodes/opcode-23-new-array.html b/docs/opcodes/opcode-23-new-array.html
index be46a49..29327e9 100644
--- a/docs/opcodes/opcode-23-new-array.html
+++ b/docs/opcodes/opcode-23-new-array.html
@@ -15,7 +15,7 @@
<p>
Construct a new array of the indicated type and size. The type must be an array
-type.
+type.
</p>
<h2>Details</h2>
@@ -56,7 +56,7 @@
</li>
<li>
Type constant pool entry C must contain a valid array type descriptor.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -87,7 +87,7 @@
</li>
<li>
If v(A+1) is the upper half of a register pair, v(A+1)' becomes undefined.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
@@ -101,7 +101,7 @@
</li>
<li>
All exceptions that are possible during instantiation can occur.
- </li>
+ </li>
</ul>
</body>
diff --git a/docs/opcodes/opcode-24-filled-new-array.html b/docs/opcodes/opcode-24-filled-new-array.html
index cba0c5d..1dfa089 100644
--- a/docs/opcodes/opcode-24-filled-new-array.html
+++ b/docs/opcodes/opcode-24-filled-new-array.html
@@ -21,7 +21,7 @@
store their results, so the constructed instance must be moved to a register
with a subsequent move-result-object instruction (if it is to be used).
</p>
-
+
<h2>Details</h2>
<table class="instruc">
@@ -80,9 +80,9 @@
<li>
If the element type is a reference type, then all actual arguments
(vD .. vA, depending on B) must be references, too.
- </li>
+ </li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
@@ -115,7 +115,7 @@
If B > 3 then R[3] = vG
</li>
<li>
- If B > 4 then R[4] = vA
+ If B > 4 then R[4] = vA
</li>
</ul>
</li>
@@ -123,7 +123,7 @@
No reference to R is stored in any register. Instead, R can be accessed by a
move-result-object instruction immediately following this filled-new-array
instruction.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
@@ -137,7 +137,7 @@
</li>
<li>
All exceptions that are possible during instantiation can occur.
- </li>
+ </li>
</ul>
</body>
diff --git a/docs/opcodes/opcode-25-filled-new-array-range.html b/docs/opcodes/opcode-25-filled-new-array-range.html
index 944a8b1..2ee7505 100644
--- a/docs/opcodes/opcode-25-filled-new-array-range.html
+++ b/docs/opcodes/opcode-25-filled-new-array-range.html
@@ -16,7 +16,7 @@
<p>
Construct an array of the given type and size, filling it with the supplied
contents. Clarifications and restrictions are the same as filled-new-array,
-described above.
+described above.
</p>
<h2>Details</h2>
@@ -70,7 +70,7 @@
</li>
<li>
The element size of the type denoted by B must be no larger than 32 bits.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -102,7 +102,7 @@
...
</li>
<li>
- J[vA] = vN
+ J[vA] = vN
</li>
</ul>
</li>
@@ -110,7 +110,7 @@
No reference to J is stored in any register. Instead, J can be accessed by a
move-result-object instruction immediately following this filled-new-array
instruction.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-26-fill-array-data.html b/docs/opcodes/opcode-26-fill-array-data.html
index c5040a5..77b45ae 100644
--- a/docs/opcodes/opcode-26-fill-array-data.html
+++ b/docs/opcodes/opcode-26-fill-array-data.html
@@ -21,7 +21,7 @@
Note: The address of the table is guaranteed to be even (that is, 4-byte
aligned). If the code size of the method is otherwise odd, then an extra code
unit is inserted between the main code and the table whose value is the same as
-a nop.
+a nop.
</p>
<h2>Details</h2>
@@ -69,8 +69,8 @@
<li>
The table size must be equal or smaller than the array length.
</li>
-</ul>
-
+</ul>
+
<h2>Behavior</h2>
<ul>
@@ -88,7 +88,7 @@
<ul>
<li>
- NullPointerException if vA is null.
+ NullPointerException if vA is null.
</li>
</ul>
diff --git a/docs/opcodes/opcode-27-throw.html b/docs/opcodes/opcode-27-throw.html
index f4416ce..1a0eb09 100644
--- a/docs/opcodes/opcode-27-throw.html
+++ b/docs/opcodes/opcode-27-throw.html
@@ -50,7 +50,7 @@
to the usual rules of the Java programming language.
</li>
</ul>
-
+
<h2>Behavior</h2>
<ul>
@@ -73,7 +73,7 @@
</li>
<li>
Otherwise, the indicated exception.
- </li>
+ </li>
</ul>
</body>
diff --git a/docs/opcodes/opcode-28-goto.html b/docs/opcodes/opcode-28-goto.html
index 5ca92b6..fec294c 100644
--- a/docs/opcodes/opcode-28-goto.html
+++ b/docs/opcodes/opcode-28-goto.html
@@ -18,7 +18,7 @@
</p>
<p>
Note: The branch offset may not be 0. (A spin loop may be legally constructed
-either with goto/32 or by including a nop as a target before the branch.)
+either with goto/32 or by including a nop as a target before the branch.)
</p>
<h2>Details</h2>
@@ -48,7 +48,7 @@
</li>
<li>
A must not be 0.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -60,7 +60,7 @@
</li>
<li>
Executions resumes at PC'.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-29-goto-16.html b/docs/opcodes/opcode-29-goto-16.html
index abe4aec..791456b 100644
--- a/docs/opcodes/opcode-29-goto-16.html
+++ b/docs/opcodes/opcode-29-goto-16.html
@@ -18,7 +18,7 @@
</p>
<p>
Note: The branch offset may not be 0. (A spin loop may be legally constructed
-either with goto/32 or by including a nop as a target before the branch.)
+either with goto/32 or by including a nop as a target before the branch.)
</p>
<h2>Details</h2>
@@ -48,7 +48,7 @@
</li>
<li>
A must not be 0.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -60,7 +60,7 @@
</li>
<li>
Executions resumes at PC'.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-2a-goto-32.html b/docs/opcodes/opcode-2a-goto-32.html
index 7d64ac9..b98dd85 100644
--- a/docs/opcodes/opcode-2a-goto-32.html
+++ b/docs/opcodes/opcode-2a-goto-32.html
@@ -53,7 +53,7 @@
</li>
<li>
Executions resumes at PC'.
- </li>
+ </li>
</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-2b-packed-switch.html b/docs/opcodes/opcode-2b-packed-switch.html
index 73125bd..b2d5251 100644
--- a/docs/opcodes/opcode-2b-packed-switch.html
+++ b/docs/opcodes/opcode-2b-packed-switch.html
@@ -22,7 +22,7 @@
Note: The address of the table is guaranteed to be even (that is, 4-byte
aligned). If the code size of the method is otherwise odd, then an extra code
unit is inserted between the main code and the table whose value is the same as
-a nop.
+a nop.
</p>
<h2>Details</h2>
@@ -92,7 +92,7 @@
statement.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-2c-sparse-switch.html b/docs/opcodes/opcode-2c-sparse-switch.html
index cec581e..9d81eda 100644
--- a/docs/opcodes/opcode-2c-sparse-switch.html
+++ b/docs/opcodes/opcode-2c-sparse-switch.html
@@ -22,7 +22,7 @@
Note: The address of the table is guaranteed to be even (that is, 4-byte
aligned). If the code size of the method is otherwise odd, then an extra code
unit is inserted between the main code and the table whose value is the same as
-a nop.
+a nop.
</p>
<h2>Details</h2>
@@ -87,11 +87,11 @@
</li>
</ul>
</li>
- <li>
+ <li>
Otherwise execution continues at the instruction following the sparse-switch
statement.
</li>
-</ul>
+</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-2d-cmp-kind.html b/docs/opcodes/opcode-2d-cmp-kind.html
index 431ccd4..f55a006 100644
--- a/docs/opcodes/opcode-2d-cmp-kind.html
+++ b/docs/opcodes/opcode-2d-cmp-kind.html
@@ -24,7 +24,7 @@
For example, to check to see if floating point a < b, then it is advisable to
use cmpg-float; a result of -1 indicates that the test was true, and the other
values indicate it was false either due to a valid comparison or because one
-or the other values was NaN.
+or the other values was NaN.
</p>
<h2>Details</h2>
@@ -71,7 +71,7 @@
For the -long variant, both both vB and vC must be the lower part of a
register pair holding a long value.
</li>
-</ul>
+</ul>
<h2>Behavior</h2>
@@ -109,8 +109,8 @@
<li>
If v(A+1) is the upper half of a register pair, v(A+1)' becomes undefined.
</li>
-</ul>
-
+</ul>
+
<h2>Exceptions</h2>
<p>
diff --git a/docs/opcodes/opcode-32-if-test.html b/docs/opcodes/opcode-32-if-test.html
index af0adb2..ee394f6 100644
--- a/docs/opcodes/opcode-32-if-test.html
+++ b/docs/opcodes/opcode-32-if-test.html
@@ -20,7 +20,7 @@
<p>
Note: The branch offset may not be 0. (A spin loop may be legally constructed
either by branching around a backward goto or by including a nop as a target
-before the branch.)
+before the branch.)
</p>
<h2>Details</h2>
@@ -68,7 +68,7 @@
</li>
C must of a signed offset that, when added to the PC of the instruction,
points to a valid bytecode instruction inside the same method.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -89,7 +89,7 @@
</li>
</ul>
</li>
-</ul>
+</ul>
<h2>Exceptions</h2>
diff --git a/docs/opcodes/opcode-38-if-testz.html b/docs/opcodes/opcode-38-if-testz.html
index 354e894..060bbdb 100644
--- a/docs/opcodes/opcode-38-if-testz.html
+++ b/docs/opcodes/opcode-38-if-testz.html
@@ -20,7 +20,7 @@
<p>
Note: The branch offset may not be 0. (A spin loop may be legally constructed
either by branching around a backward goto or by including a nop as a target
- before the branch.)
+ before the branch.)
</p>
<h2>Details</h2>
@@ -67,7 +67,7 @@
</li>
<li>
B must not be 0.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
diff --git a/docs/opcodes/opcode-44-aget.html b/docs/opcodes/opcode-44-aget.html
index b9d6f23..6e8836f 100644
--- a/docs/opcodes/opcode-44-aget.html
+++ b/docs/opcodes/opcode-44-aget.html
@@ -15,7 +15,7 @@
<p>
Perform the identified array operation at the identified index of the given
-array, storing into the value register.
+array, storing into the value register.
</p>
<h2>Details</h2>
@@ -63,7 +63,7 @@
</li>
<li>
Register vC must contain an integer value.
- </li>
+ </li>
</ul>
<h2>Behavior</h2>
@@ -97,7 +97,7 @@
v(A+2)' becomes undefined.
</li>
</ul>
-
+
<h2>Exceptions</h2>
<ul>
@@ -107,7 +107,7 @@
<li>
ArrayIndexOutOfBoundsException if vC < 0 or vC >= array.length.
</li>
-</ul>
+</ul>
</body>
</html>
diff --git a/docs/opcodes/opcode-7b-unop.html b/docs/opcodes/opcode-7b-unop.html
index 1068a25..8b06092 100644
--- a/docs/opcodes/opcode-7b-unop.html
+++ b/docs/opcodes/opcode-7b-unop.html
@@ -84,7 +84,7 @@
<ul>
<li>
- The given operation <unop> is performed according to the semantics
+ The given operation <unop> is performed according to the semantics
specified in table XXX.
</li>
<li>
diff --git a/docs/porting-proto.c.txt b/docs/porting-proto.c.txt
index 2f72bac..98c6fd3 100644
--- a/docs/porting-proto.c.txt
+++ b/docs/porting-proto.c.txt
@@ -242,4 +242,3 @@
#ifdef __ARM_ARCH_7A__
# warning "found __ARM_ARCH_7A__"
#endif
-
diff --git a/docs/prettify.js b/docs/prettify.js
index c954118..9e99fc6 100644
--- a/docs/prettify.js
+++ b/docs/prettify.js
@@ -969,7 +969,7 @@
var newlineRe = /\r\n?|\n/g;
var trailingSpaceRe = /[ \r\n]$/;
var lastWasSpace = true; // the last text chunk emitted ended with a space.
-
+
// A helper function that is responsible for opening sections of decoration
// and outputing properly escaped chunks of source
function emitTextUpTo(sourceIdx) {
diff --git a/docs/verifier.html b/docs/verifier.html
index 022923b..21bbdf0 100644
--- a/docs/verifier.html
+++ b/docs/verifier.html
@@ -45,6 +45,10 @@
it's very helpful to start with the assumption that the bytecode
is valid.
</ol>
+<p>
+It's also a convenient framework to deal with certain situations, notably
+replacement of instructions that access volatile 64-bit fields with
+more rigorous versions that guarantee atomicity.
<h2>Verifier Differences</h2>
diff --git a/dvz/Android.mk b/dvz/Android.mk
index 56b7890..72b92a0 100644
--- a/dvz/Android.mk
+++ b/dvz/Android.mk
@@ -9,10 +9,10 @@
LOCAL_SHARED_LIBRARIES := \
libcutils
-LOCAL_C_INCLUDES :=
+LOCAL_C_INCLUDES :=
-LOCAL_CFLAGS :=
+LOCAL_CFLAGS :=
-LOCAL_MODULE := dvz
+LOCAL_MODULE := dvz
include $(BUILD_EXECUTABLE)
diff --git a/dvz/dvz.c b/dvz/dvz.c
index 2d204bb..88fe086 100644
--- a/dvz/dvz.c
+++ b/dvz/dvz.c
@@ -45,7 +45,7 @@
int err;
g_pid = pid;
-
+
my_pgid = getpgid(0);
if (my_pgid < 0) {
perror ("error with getpgid()");
@@ -62,8 +62,8 @@
// The zygote was unable to move this process into our pgid
// We have to forward signals
- int forward_signals[]
- = {SIGHUP, SIGINT, SIGTERM, SIGWINCH,
+ int forward_signals[]
+ = {SIGHUP, SIGINT, SIGTERM, SIGWINCH,
SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT};
struct sigaction sa;
diff --git a/dx/etc/dx.bat b/dx/etc/dx.bat
index 1361bb6..36b6206 100755
--- a/dx/etc/dx.bat
+++ b/dx/etc/dx.bat
@@ -83,4 +83,3 @@
set javaOpts=%javaOpts% %defaultMx%
call java %javaOpts% -Djava.ext.dirs=%frameworkdir% -jar %jarpath% %args%
-
diff --git a/dx/etc/run-opcode-gen b/dx/etc/run-opcode-gen
index 70e9707..061c048 100755
--- a/dx/etc/run-opcode-gen
+++ b/dx/etc/run-opcode-gen
@@ -18,5 +18,3 @@
./opcode-gen ../src/com/android/dx/dex/code/DalvOps.java
./opcode-gen ../src/com/android/dx/dex/code/Dops.java
-
-
diff --git a/dx/src/com/android/dx/Version.java b/dx/src/com/android/dx/Version.java
index e0427a8..b22173d 100644
--- a/dx/src/com/android/dx/Version.java
+++ b/dx/src/com/android/dx/Version.java
@@ -21,5 +21,5 @@
*/
public class Version {
/** {@code non-null;} version string */
- public static final String VERSION = "1.4";
+ public static final String VERSION = "1.5";
}
diff --git a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
index acf5a9e..fe0b3ab 100644
--- a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
+++ b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
@@ -34,7 +34,7 @@
/**
* Constructs an instance.
- *
+ *
* @param value {@code non-null;} the annotation default value
* @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
@@ -58,7 +58,7 @@
/**
* Gets the annotation default value.
- *
+ *
* @return {@code non-null;} the value
*/
public Constant getValue() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttCode.java b/dx/src/com/android/dx/cf/attrib/AttCode.java
index 89ba895..8d34c69 100644
--- a/dx/src/com/android/dx/cf/attrib/AttCode.java
+++ b/dx/src/com/android/dx/cf/attrib/AttCode.java
@@ -45,7 +45,7 @@
/**
* Constructs an instance.
- *
+ *
* @param maxStack {@code >= 0;} the stack size
* @param maxLocals {@code >= 0;} the number of locals
* @param code {@code non-null;} array containing the bytecode per se
@@ -100,7 +100,7 @@
/**
* Gets the maximum stack size.
- *
+ *
* @return {@code >= 0;} the maximum stack size
*/
public int getMaxStack() {
@@ -109,7 +109,7 @@
/**
* Gets the number of locals.
- *
+ *
* @return {@code >= 0;} the number of locals
*/
public int getMaxLocals() {
@@ -118,7 +118,7 @@
/**
* Gets the bytecode array.
- *
+ *
* @return {@code non-null;} the bytecode array
*/
public BytecodeArray getCode() {
@@ -127,7 +127,7 @@
/**
* Gets the exception table.
- *
+ *
* @return {@code non-null;} the exception table
*/
public ByteCatchList getCatches() {
@@ -136,7 +136,7 @@
/**
* Gets the associated attribute list.
- *
+ *
* @return {@code non-null;} the attribute list
*/
public AttributeList getAttributes() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttConstantValue.java b/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
index a7436f3..aa6d1b3 100644
--- a/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
+++ b/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
@@ -35,7 +35,7 @@
/**
* Constructs an instance.
- *
+ *
* @param constantValue {@code non-null;} the constant value, which must
* be an instance of one of: {@code CstString},
* {@code CstInteger}, {@code CstLong},
@@ -68,7 +68,7 @@
* is an instance of one of: {@code CstString},
* {@code CstInteger}, {@code CstLong},
* {@code CstFloat}, or {@code CstDouble}.
- *
+ *
* @return {@code non-null;} the constant value
*/
public TypedConstant getConstantValue() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
index 68a24d9..6717e15 100644
--- a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
+++ b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
@@ -35,7 +35,7 @@
/**
* Constructs an instance.
- *
+ *
* @param type {@code non-null;} the innermost enclosing class
* @param method {@code null-ok;} the name-and-type of the innermost enclosing
* method, if any
@@ -58,7 +58,7 @@
/**
* Gets the innermost enclosing class.
- *
+ *
* @return {@code non-null;} the innermost enclosing class
*/
public CstType getEnclosingClass() {
@@ -68,7 +68,7 @@
/**
* Gets the name-and-type of the innermost enclosing method, if
* any.
- *
+ *
* @return {@code null-ok;} the name-and-type of the innermost enclosing
* method, if any
*/
diff --git a/dx/src/com/android/dx/cf/attrib/AttExceptions.java b/dx/src/com/android/dx/cf/attrib/AttExceptions.java
index c592047..a17e009 100644
--- a/dx/src/com/android/dx/cf/attrib/AttExceptions.java
+++ b/dx/src/com/android/dx/cf/attrib/AttExceptions.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param exceptions {@code non-null;} list of classes, presumed but not
* verified to be subclasses of {@code Throwable}
*/
@@ -59,7 +59,7 @@
* Gets the list of classes associated with this instance. In
* general, these classes are not pre-verified to be subclasses of
* {@code Throwable}.
- *
+ *
* @return {@code non-null;} the list of classes
*/
public TypeList getExceptions() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
index bd6c7cd..77a4b08 100644
--- a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
+++ b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance.
- *
+ *
* @param innerClasses {@code non-null;} list of inner class entries
*/
public AttInnerClasses(InnerClassList innerClasses) {
@@ -55,7 +55,7 @@
/**
* Gets the list of "inner class" entries associated with this instance.
- *
+ *
* @return {@code non-null;} the list
*/
public InnerClassList getInnerClasses() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java b/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
index 38980be..5eac8cb 100644
--- a/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
+++ b/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param lineNumbers {@code non-null;} list of line number entries
*/
public AttLineNumberTable(LineNumberList lineNumbers) {
@@ -56,7 +56,7 @@
/**
* Gets the list of "line number" entries associated with this instance.
- *
+ *
* @return {@code non-null;} the list
*/
public LineNumberList getLineNumbers() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
index 53ba64f..1d2b4aa 100644
--- a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
+++ b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
@@ -27,7 +27,7 @@
/**
* Constructs an instance.
- *
+ *
* @param localVariables {@code non-null;} list of local variable entries
*/
public AttLocalVariableTable(LocalVariableList localVariables) {
diff --git a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
index 49cdb0c..2520bf6 100644
--- a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
+++ b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
@@ -27,7 +27,7 @@
/**
* Constructs an instance.
- *
+ *
* @param localVariables {@code non-null;} list of local variable entries
*/
public AttLocalVariableTypeTable(LocalVariableList localVariables) {
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
index e83b76f..d3afe27 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
- *
+ *
* @param annotations {@code non-null;} the list of annotations
* @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
index 7dfe206..c9c5136 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance.
- *
+ *
* @param parameterAnnotations {@code non-null;} the parameter annotations
* @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
index 9de0588..a6a640d 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
- *
+ *
* @param annotations {@code non-null;} the list of annotations
* @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
index 76607c0..177eb4c 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance.
- *
+ *
* @param annotations {@code non-null;} the parameter annotations
* @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
diff --git a/dx/src/com/android/dx/cf/attrib/AttSignature.java b/dx/src/com/android/dx/cf/attrib/AttSignature.java
index b9cb97d..f6023f3 100644
--- a/dx/src/com/android/dx/cf/attrib/AttSignature.java
+++ b/dx/src/com/android/dx/cf/attrib/AttSignature.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance.
- *
+ *
* @param signature {@code non-null;} the signature string
*/
public AttSignature(CstUtf8 signature) {
@@ -50,7 +50,7 @@
/**
* Gets the signature string.
- *
+ *
* @return {@code non-null;} the signature string
*/
public CstUtf8 getSignature() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttSourceFile.java b/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
index 941a2b0..b84ff4d 100644
--- a/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
+++ b/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance.
- *
+ *
* @param sourceFile {@code non-null;} the name of the source file
*/
public AttSourceFile(CstUtf8 sourceFile) {
@@ -50,7 +50,7 @@
/**
* Gets the source file name of this instance.
- *
+ *
* @return {@code non-null;} the source file
*/
public CstUtf8 getSourceFile() {
diff --git a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
index 4d9201e..bc138af 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
@@ -32,7 +32,7 @@
/**
* Constructs an instance.
- *
+ *
* @param attributeName {@code non-null;} the name of the attribute
* @param annotations {@code non-null;} the list of annotations
* @param byteLength {@code >= 0;} attribute data length in the original
@@ -63,7 +63,7 @@
/**
* Gets the list of annotations associated with this instance.
- *
+ *
* @return {@code non-null;} the list
*/
public final Annotations getAnnotations() {
diff --git a/dx/src/com/android/dx/cf/attrib/BaseAttribute.java b/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
index c9c1b33..9961725 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
- *
+ *
* @param name {@code non-null;} attribute name
*/
public BaseAttribute(String name) {
diff --git a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
index 5ba5889..27cd6fb 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
@@ -29,7 +29,7 @@
/**
* Constructs an instance.
- *
+ *
* @param name {@code non-null;} attribute name
* @param localVariables {@code non-null;} list of local variable entries
*/
@@ -56,7 +56,7 @@
/**
* Gets the list of "local variable" entries associated with this instance.
- *
+ *
* @return {@code non-null;} the list
*/
public final LocalVariableList getLocalVariables() {
diff --git a/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
index 1b204b3..791f8cd 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
@@ -32,7 +32,7 @@
/**
* Constructs an instance.
- *
+ *
* @param attributeName {@code non-null;} the name of the attribute
* @param parameterAnnotations {@code non-null;} the annotations
* @param byteLength {@code >= 0;} attribute data length in the original
@@ -64,7 +64,7 @@
/**
* Gets the list of annotation lists associated with this instance.
- *
+ *
* @return {@code non-null;} the list
*/
public final AnnotationsList getParameterAnnotations() {
diff --git a/dx/src/com/android/dx/cf/attrib/RawAttribute.java b/dx/src/com/android/dx/cf/attrib/RawAttribute.java
index 585e5c5..e905dd1 100644
--- a/dx/src/com/android/dx/cf/attrib/RawAttribute.java
+++ b/dx/src/com/android/dx/cf/attrib/RawAttribute.java
@@ -28,13 +28,13 @@
/**
* {@code null-ok;} constant pool to use for resolution of cpis in {@link
- * #data}
+ * #data}
*/
private final ConstantPool pool;
/**
* Constructs an instance.
- *
+ *
* @param name {@code non-null;} attribute name
* @param data {@code non-null;} attribute data
* @param pool {@code null-ok;} constant pool to use for cpi resolution
@@ -52,7 +52,7 @@
/**
* Constructs an instance from a sub-array of a {@link ByteArray}.
- *
+ *
* @param name {@code non-null;} attribute name
* @param data {@code non-null;} array containing the attribute data
* @param offset offset in {@code data} to the attribute data
@@ -66,7 +66,7 @@
/**
* Get the raw data of the attribute.
- *
+ *
* @return {@code non-null;} the data
*/
public ByteArray getData() {
@@ -82,7 +82,7 @@
* Gets the constant pool to use for cpi resolution, if any. It
* presumably came from the class file that this attribute came
* from.
- *
+ *
* @return {@code null-ok;} the constant pool
*/
public ConstantPool getPool() {
diff --git a/dx/src/com/android/dx/cf/code/BaseMachine.java b/dx/src/com/android/dx/cf/code/BaseMachine.java
index b7e700d..aae6056 100644
--- a/dx/src/com/android/dx/cf/code/BaseMachine.java
+++ b/dx/src/com/android/dx/cf/code/BaseMachine.java
@@ -27,7 +27,7 @@
/**
* Base implementation of {@link Machine}.
- *
+ *
* <p><b>Note:</b> For the most part, the documentation for this class
* ignores the distinction between {@link Type} and {@link
* TypeBearer}.</p>
@@ -35,7 +35,7 @@
public abstract class BaseMachine implements Machine {
/* {@code non-null;} the prototype for the associated method */
private final Prototype prototype;
-
+
/** {@code non-null;} primary arguments */
private TypeBearer[] args;
@@ -77,7 +77,7 @@
/**
* Constructs an instance.
- *
+ *
* @param prototype {@code non-null;} the prototype for the associated method
*/
public BaseMachine(Prototype prototype) {
@@ -132,7 +132,7 @@
public void popArgs(Frame frame, Prototype prototype) {
StdTypeList types = prototype.getParameterTypes();
int size = types.size();
-
+
// Use the above method to do the actual popping...
popArgs(frame, size);
@@ -253,7 +253,7 @@
/**
* Gets the number of primary arguments.
- *
+ *
* @return {@code >= 0;} the number of primary arguments
*/
protected final int argCount() {
@@ -263,7 +263,7 @@
/**
* Gets the width of the arguments (where a category-2 value counts as
* two).
- *
+ *
* @return {@code >= 0;} the argument width
*/
protected final int argWidth() {
@@ -278,7 +278,7 @@
/**
* Gets the {@code n}th primary argument.
- *
+ *
* @param n {@code >= 0, < argCount();} which argument
* @return {@code non-null;} the indicated argument
*/
@@ -297,7 +297,7 @@
/**
* Gets the type auxiliary argument.
- *
+ *
* @return {@code null-ok;} the salient type
*/
protected final Type getAuxType() {
@@ -306,7 +306,7 @@
/**
* Gets the {@code int} auxiliary argument.
- *
+ *
* @return the argument value
*/
protected final int getAuxInt() {
@@ -315,7 +315,7 @@
/**
* Gets the constant auxiliary argument.
- *
+ *
* @return {@code null-ok;} the argument value
*/
protected final Constant getAuxCst() {
@@ -324,7 +324,7 @@
/**
* Gets the branch target auxiliary argument.
- *
+ *
* @return the argument value
*/
protected final int getAuxTarget() {
@@ -333,7 +333,7 @@
/**
* Gets the switch cases auxiliary argument.
- *
+ *
* @return {@code null-ok;} the argument value
*/
protected final SwitchList getAuxCases() {
@@ -350,7 +350,7 @@
}
/**
* Gets the last local index accessed.
- *
+ *
* @return {@code >= -1;} the salient local index or {@code -1} if none
* was set since the last time {@link #clearArgs} was called
*/
@@ -364,7 +364,7 @@
* by a previous call to {@link #localTarget} with the type of what
* should be the sole result set by a call to {@link #setResult} (or
* the combination {@link #clearResult} then {@link #addResult}.
- *
+ *
* @return {@code null-ok;} the salient register spec or {@code null} if no
* local target was set since the last time {@link #clearArgs} was
* called
@@ -375,7 +375,7 @@
}
if (resultCount != 1) {
- throw new SimException("local target with " +
+ throw new SimException("local target with " +
((resultCount == 0) ? "no" : "multiple") + " results");
}
@@ -413,10 +413,10 @@
/**
* Sets the results list to be the given single value.
- *
+ *
* <p><b>Note:</b> If there is more than one result value, the
* others may be added by using {@link #addResult}.</p>
- *
+ *
* @param result {@code non-null;} result value
*/
protected final void setResult(TypeBearer result) {
@@ -430,9 +430,9 @@
/**
* Adds an additional element to the list of results.
- *
+ *
* @see #setResult
- *
+ *
* @param result {@code non-null;} result value
*/
protected final void addResult(TypeBearer result) {
@@ -447,7 +447,7 @@
/**
* Gets the count of results. This throws an exception if results were
* never set. (Explicitly clearing the results counts as setting them.)
- *
+ *
* @return {@code >= 0;} the count
*/
protected final int resultCount() {
@@ -461,7 +461,7 @@
/**
* Gets the width of the results (where a category-2 value counts as
* two).
- *
+ *
* @return {@code >= 0;} the result width
*/
protected final int resultWidth() {
@@ -476,7 +476,7 @@
/**
* Gets the {@code n}th result value.
- *
+ *
* @param n {@code >= 0, < resultCount();} which result
* @return {@code non-null;} the indicated result value
*/
@@ -498,7 +498,7 @@
* there is a local target (see {@link #localTarget}), then the sole
* result is stored to that target; otherwise any results are pushed
* onto the stack.
- *
+ *
* @param frame {@code non-null;} frame to operate on
*/
protected final void storeResults(Frame frame) {
@@ -528,7 +528,7 @@
/**
* Throws an exception that indicates a mismatch in local variable
* types.
- *
+ *
* @param found {@code non-null;} the encountered type
* @param local {@code non-null;} the local variable's claimed type
*/
@@ -536,8 +536,8 @@
TypeBearer local) {
throw new SimException("local variable type mismatch: " +
"attempt to set or access a value of type " +
- found.toHuman() +
- " using a local variable of type " +
+ found.toHuman() +
+ " using a local variable of type " +
local.toHuman() +
". This is symptomatic of .class transformation tools " +
"that ignore local variable information.");
diff --git a/dx/src/com/android/dx/cf/code/BasicBlocker.java b/dx/src/com/android/dx/cf/code/BasicBlocker.java
index d67e525..8fb9560 100644
--- a/dx/src/com/android/dx/cf/code/BasicBlocker.java
+++ b/dx/src/com/android/dx/cf/code/BasicBlocker.java
@@ -54,13 +54,13 @@
/**
* {@code non-null, sparse;} for each instruction offset to a branch of
- * some sort, the list of targets for that instruction
+ * some sort, the list of targets for that instruction
*/
private final IntList[] targetLists;
/**
* {@code non-null, sparse;} for each instruction offset to a throwing
- * instruction, the list of exception handlers for that instruction
+ * instruction, the list of exception handlers for that instruction
*/
private final ByteCatchList[] catchLists;
@@ -71,7 +71,7 @@
* Identifies and enumerates the basic blocks in the given method,
* returning a list of them. The returned list notably omits any
* definitely-dead code that is identified in the process.
- *
+ *
* @param method {@code non-null;} method to convert
* @return {@code non-null;} list of basic blocks
*/
@@ -85,7 +85,7 @@
/**
* Constructs an instance. This class is not publicly instantiable; use
* {@link #identifyBlocks}.
- *
+ *
* @param method {@code non-null;} method to convert
*/
private BasicBlocker(ConcreteMethod method) {
@@ -174,7 +174,7 @@
if ((type == Type.INT) || (type == Type.LONG)) {
visitThrowing(offset, length, true);
}
- break;
+ break;
}
default: {
visitCommon(offset, length, true);
@@ -265,7 +265,7 @@
/**
* Extracts the list of basic blocks from the bit sets.
- *
+ *
* @return {@code non-null;} the list of basic blocks
*/
private ByteBlockList getBlockList() {
@@ -367,7 +367,7 @@
/**
* Sets a bit in the work set, but only if the instruction in question
* isn't yet known to be possibly-live.
- *
+ *
* @param offset offset to the instruction in question
* @param blockStart {@code true} iff this instruction starts a
* basic block
@@ -384,7 +384,7 @@
/**
* Helper method used by all the visitor methods.
- *
+ *
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
* @param nextIsLive {@code true} iff the instruction after
@@ -417,7 +417,7 @@
* Helper method used by all the visitor methods that deal with
* opcodes that possibly throw. This method should be called after calling
* {@link #visitCommon}.
- *
+ *
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
* @param nextIsLive {@code true} iff the instruction after
diff --git a/dx/src/com/android/dx/cf/code/ByteBlock.java b/dx/src/com/android/dx/cf/code/ByteBlock.java
index 40b91c3..73bbbab 100644
--- a/dx/src/com/android/dx/cf/code/ByteBlock.java
+++ b/dx/src/com/android/dx/cf/code/ByteBlock.java
@@ -40,8 +40,8 @@
private final ByteCatchList catches;
/**
- * Constructs an instance.
- *
+ * Constructs an instance.
+ *
* @param label {@code >= 0;} target label for this block
* @param start {@code >= 0;} bytecode offset (inclusive) of the start
* of the block
@@ -99,7 +99,7 @@
/**
* Gets the label of this block.
- *
+ *
* @return {@code >= 0;} the label
*/
public int getLabel() {
@@ -108,7 +108,7 @@
/**
* Gets the bytecode offset (inclusive) of the start of this block.
- *
+ *
* @return {@code >= 0;} the start offset
*/
public int getStart() {
@@ -117,7 +117,7 @@
/**
* Gets the bytecode offset (exclusive) of the end of this block.
- *
+ *
* @return {@code > getStart();} the end offset
*/
public int getEnd() {
@@ -125,9 +125,9 @@
}
/**
- * Gets the list of successors that this block may branch to
+ * Gets the list of successors that this block may branch to
* non-exceptionally.
- *
+ *
* @return {@code non-null;} the successor list
*/
public IntList getSuccessors() {
@@ -136,7 +136,7 @@
/**
* Gets the list of exceptions caught and their handler targets.
- *
+ *
* @return {@code non-null;} the catch list
*/
public ByteCatchList getCatches() {
diff --git a/dx/src/com/android/dx/cf/code/ByteCatchList.java b/dx/src/com/android/dx/cf/code/ByteCatchList.java
index aab2087..36c37af 100644
--- a/dx/src/com/android/dx/cf/code/ByteCatchList.java
+++ b/dx/src/com/android/dx/cf/code/ByteCatchList.java
@@ -129,7 +129,7 @@
* is <i>not</i> found for the exception type of the given item in
* the given array. A match is considered to be either an exact type
* match or the class {@code Object} which represents a catch-all.
- *
+ *
* @param item {@code non-null;} item with the exception type to look for
* @param arr {@code non-null;} array to search in
* @param count {@code non-null;} maximum number of elements in the array to check
@@ -153,7 +153,7 @@
* is a list of all the exception handler addresses, with the given
* {@code noException} address appended if appropriate. The
* result is automatically made immutable.
- *
+ *
* @param noException {@code >= -1;} the no-exception address to append, or
* {@code -1} not to append anything
* @return {@code non-null;} list of exception targets, with
diff --git a/dx/src/com/android/dx/cf/code/ByteOps.java b/dx/src/com/android/dx/cf/code/ByteOps.java
index ea7b514..1376008 100644
--- a/dx/src/com/android/dx/cf/code/ByteOps.java
+++ b/dx/src/com/android/dx/cf/code/ByteOps.java
@@ -272,20 +272,20 @@
/**
* "l": {@code op local}; category-1 local; implies
* {@code max_locals} is at least two more than the given
- * local number
+ * local number
*/
public static final int FMT_LOCAL_1 = 10;
/**
* "m": {@code op local}; category-2 local; implies
* {@code max_locals} is at least two more than the given
- * local number
+ * local number
*/
public static final int FMT_LOCAL_2 = 11;
/**
* "y": {@code op #byte} ({@code bipush} and
- * {@code newarray})
+ * {@code newarray})
*/
public static final int FMT_LITERAL_BYTE = 12;
@@ -342,7 +342,7 @@
/**
* {@code non-null;} map from opcodes to format or'ed with allowed constant
- * pool types
+ * pool types
*/
private static final int[] OPCODE_INFO = new int[256];
@@ -622,7 +622,7 @@
/**
* Gets the name of the given opcode.
- *
+ *
* @param opcode {@code >= 0, <= 255;} the opcode
* @return {@code non-null;} its name
*/
@@ -639,7 +639,7 @@
/**
* Gets the format and allowed cp types of the given opcode.
- *
+ *
* @param opcode {@code >= 0, <= 255;} the opcode
* @return its format and allowed cp types
*/
diff --git a/dx/src/com/android/dx/cf/code/BytecodeArray.java b/dx/src/com/android/dx/cf/code/BytecodeArray.java
index 83cff5d..80e94bf 100644
--- a/dx/src/com/android/dx/cf/code/BytecodeArray.java
+++ b/dx/src/com/android/dx/cf/code/BytecodeArray.java
@@ -46,7 +46,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} underlying bytes
* @param pool {@code non-null;} constant pool to use when resolving constant
* pool indices
@@ -66,7 +66,7 @@
/**
* Gets the underlying byte array.
- *
+ *
* @return {@code non-null;} the byte array
*/
public ByteArray getBytes() {
@@ -75,7 +75,7 @@
/**
* Gets the size of the bytecode array, per se.
- *
+ *
* @return {@code >= 0;} the length of the bytecode array
*/
public int size() {
@@ -86,7 +86,7 @@
* Gets the total length of this structure in bytes, when included in
* a {@code Code} attribute. The returned value includes the
* array size plus four bytes for {@code code_length}.
- *
+ *
* @return {@code >= 4;} the total length, in bytes
*/
public int byteLength() {
@@ -95,7 +95,7 @@
/**
* Parses each instruction in the array, in order.
- *
+ *
* @param visitor {@code null-ok;} visitor to call back to for each instruction
*/
public void forEach(Visitor visitor) {
@@ -114,7 +114,7 @@
/**
* Finds the offset to each instruction in the bytecode array. The
* result is a bit set with the offset of each opcode-per-se flipped on.
- *
+ *
* @see Bits
* @return {@code non-null;} appropriately constructed bit set
*/
@@ -138,7 +138,7 @@
* the indicated offset (that is, the bit index), repeating until the
* work set is empty. It is expected that the visitor will regularly
* set new bits in the work set during the process.
- *
+ *
* @param workSet {@code non-null;} the work set to process
* @param visitor {@code non-null;} visitor to call back to for each instruction
*/
@@ -162,16 +162,16 @@
* Parses the instruction at the indicated offset. Indicate the
* result by calling the visitor if supplied and by returning the
* number of bytes consumed by the instruction.
- *
+ *
* <p>In order to simplify further processing, the opcodes passed
* to the visitor are canonicalized, altering the opcode to a more
* universal one and making formerly implicit arguments
* explicit. In particular:</p>
- *
+ *
* <ul>
* <li>The opcodes to push literal constants of primitive types all become
* {@code ldc}.
- * E.g., {@code fconst_0}, {@code sipush}, and
+ * E.g., {@code fconst_0}, {@code sipush}, and
* {@code lconst_0} qualify for this treatment.</li>
* <li>{@code aconst_null} becomes {@code ldc} of a
* "known null."</li>
@@ -202,7 +202,7 @@
* their pushed type. E.g., {@code arraylength} gets type
* {@code Type.INT}.</li>
* </ul>
- *
+ *
* @param offset {@code >= 0, < bytes.size();} offset to the start of the
* instruction
* @param visitor {@code null-ok;} visitor to call back to
@@ -313,7 +313,7 @@
case ByteOps.LDC: {
int idx = bytes.getUnsignedByte(offset + 1);
Constant cst = pool.get(idx);
- int value = (cst instanceof CstInteger) ?
+ int value = (cst instanceof CstInteger) ?
((CstInteger) cst).getValue() : 0;
visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value);
return 2;
@@ -321,7 +321,7 @@
case ByteOps.LDC_W: {
int idx = bytes.getUnsignedShort(offset + 1);
Constant cst = pool.get(idx);
- int value = (cst instanceof CstInteger) ?
+ int value = (cst instanceof CstInteger) ?
((CstInteger) cst).getValue() : 0;
visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value);
return 3;
@@ -798,7 +798,7 @@
/**
* Helper to deal with {@code tableswitch}.
- *
+ *
* @param offset the offset to the {@code tableswitch} opcode itself
* @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
@@ -841,7 +841,7 @@
/**
* Helper to deal with {@code lookupswitch}.
- *
+ *
* @param offset the offset to the {@code lookupswitch} opcode itself
* @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
@@ -1059,10 +1059,10 @@
}
}
-
+
/**
* Helper to deal with {@code wide}.
- *
+ *
* @param offset the offset to the {@code wide} opcode itself
* @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
@@ -1145,7 +1145,7 @@
public interface Visitor {
/**
* Visits an invalid instruction.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
@@ -1155,7 +1155,7 @@
/**
* Visits an instruction which has no inline arguments
* (implicit or explicit).
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
@@ -1166,7 +1166,7 @@
/**
* Visits an instruction which has a local variable index argument.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
@@ -1188,13 +1188,13 @@
* should-be-zero value left-shifted by 8. In the case of entries
* of type {@code int}, the {@code value} field always
* holds the raw value (for convenience of clients).
- *
+ *
* <p><b>Note:</b> In order to avoid giving it a barely-useful
* visitor all its own, {@code newarray} also uses this
* form, passing {@code value} as the array type code and
* {@code cst} as a {@link CstType} instance
* corresponding to the array type.</p>
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
@@ -1207,7 +1207,7 @@
/**
* Visits an instruction which has a branch target argument.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
@@ -1218,7 +1218,7 @@
/**
* Visits a switch instruction.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
@@ -1318,7 +1318,7 @@
return previousOffset;
}
}
-
+
/**
* Base implementation of {@link Visitor}, which has empty method
* bodies for all methods.
diff --git a/dx/src/com/android/dx/cf/code/ConcreteMethod.java b/dx/src/com/android/dx/cf/code/ConcreteMethod.java
index 70b6b45..da6cff7 100644
--- a/dx/src/com/android/dx/cf/code/ConcreteMethod.java
+++ b/dx/src/com/android/dx/cf/code/ConcreteMethod.java
@@ -43,13 +43,13 @@
/**
* {@code null-ok;} the class's {@code SourceFile} attribute value,
- * if any
+ * if any
*/
private final CstUtf8 sourceFile;
/**
* whether the class that this method is part of is defined with
- * {@code ACC_SUPER}
+ * {@code ACC_SUPER}
*/
private final boolean accSuper;
@@ -64,7 +64,7 @@
/**
* Constructs an instance.
- *
+ *
* @param method {@code non-null;} the method to be based on
* @param cf {@code non-null;} the class file that contains this method
* @param keepLines whether to keep the line number information
@@ -179,7 +179,7 @@
/**
* Gets whether the class that this method is part of is defined with
* {@code ACC_SUPER}.
- *
+ *
* @return the {@code ACC_SUPER} value
*/
public boolean getAccSuper() {
@@ -188,7 +188,7 @@
/**
* Gets the maximum stack size.
- *
+ *
* @return {@code >= 0;} the maximum stack size
*/
public int getMaxStack() {
@@ -197,7 +197,7 @@
/**
* Gets the number of locals.
- *
+ *
* @return {@code >= 0;} the number of locals
*/
public int getMaxLocals() {
@@ -206,7 +206,7 @@
/**
* Gets the bytecode array.
- *
+ *
* @return {@code non-null;} the bytecode array
*/
public BytecodeArray getCode() {
@@ -215,7 +215,7 @@
/**
* Gets the exception table.
- *
+ *
* @return {@code non-null;} the exception table
*/
public ByteCatchList getCatches() {
@@ -224,7 +224,7 @@
/**
* Gets the line number list.
- *
+ *
* @return {@code non-null;} the line number list
*/
public LineNumberList getLineNumbers() {
@@ -233,7 +233,7 @@
/**
* Gets the local variable list.
- *
+ *
* @return {@code non-null;} the local variable list
*/
public LocalVariableList getLocalVariables() {
@@ -243,7 +243,7 @@
/**
* Returns a {@link SourcePosition} instance corresponding to the
* given bytecode offset.
- *
+ *
* @param offset {@code >= 0;} the bytecode offset
* @return {@code non-null;} an appropriate instance
*/
diff --git a/dx/src/com/android/dx/cf/code/ExecutionStack.java b/dx/src/com/android/dx/cf/code/ExecutionStack.java
index 15a9e6c..8f5b528 100644
--- a/dx/src/com/android/dx/cf/code/ExecutionStack.java
+++ b/dx/src/com/android/dx/cf/code/ExecutionStack.java
@@ -24,7 +24,7 @@
/**
* Representation of a Java method execution stack.
- *
+ *
* <p><b>Note:</b> For the most part, the documentation for this class
* ignores the distinction between {@link Type} and {@link
* TypeBearer}.</p>
@@ -35,13 +35,13 @@
/**
* {@code >= 0;} stack pointer (points one past the end) / current stack
- * size
+ * size
*/
private int stackPtr;
/**
- * Constructs an instance.
- *
+ * Constructs an instance.
+ *
* @param maxStack {@code >= 0;} the maximum size of the stack for this
* instance
*/
@@ -53,7 +53,7 @@
/**
* Makes and returns a mutable copy of this instance.
- *
+ *
* @return {@code non-null;} the copy
*/
public ExecutionStack copy() {
@@ -68,7 +68,7 @@
/**
* Annotates (adds context to) the given exception with information
* about this instance.
- *
+ *
* @param ex {@code non-null;} the exception to annotate
*/
public void annotate(ExceptionWithContext ex) {
@@ -85,7 +85,7 @@
/**
* Replaces all the occurrences of the given uninitialized type in
* this stack with its initialized equivalent.
- *
+ *
* @param type {@code non-null;} type to replace
*/
public void makeInitialized(Type type) {
@@ -107,7 +107,7 @@
/**
* Gets the maximum stack size for this instance.
- *
+ *
* @return {@code >= 0;} the max stack size
*/
public int getMaxStack() {
@@ -116,7 +116,7 @@
/**
* Gets the current stack size.
- *
+ *
* @return {@code >= 0, < getMaxStack();} the current stack size
*/
public int size() {
@@ -138,7 +138,7 @@
/**
* Pushes a value of the given type onto the stack.
- *
+ *
* @param type {@code non-null;} type of the value
* @throws SimException thrown if there is insufficient room on the
* stack for the value
@@ -175,10 +175,10 @@
* {@code n == 0} means to peek at the top of the stack. Note that
* this will return {@code null} if the indicated element is the
* deeper half of a category-2 value.
- *
+ *
* @param n {@code >= 0;} which element to peek at
* @return {@code null-ok;} the type of value stored at that element
- * @throws SimException thrown if {@code n >= size()}
+ * @throws SimException thrown if {@code n >= size()}
*/
public TypeBearer peek(int n) {
if (n < 0) {
@@ -197,7 +197,7 @@
* stack, returning the type per se, as opposed to the
* <i>type-bearer</i>. This method is just a convenient shorthand
* for {@code peek(n).getType()}.
- *
+ *
* @see #peek
*/
public Type peekType(int n) {
@@ -206,7 +206,7 @@
/**
* Pops the top element off of the stack.
- *
+ *
* @return {@code non-null;} the type formerly on the top of the stack
* @throws SimException thrown if the stack is empty
*/
@@ -226,7 +226,7 @@
* contexts, particularly when merging two instances. As such, it places
* the following restriction on its behavior: You may only replace
* values with other values of the same category.
- *
+ *
* @param n {@code >= 0;} which element to change, where {@code 0} is
* the top element of the stack
* @param type {@code non-null;} type of the new value
@@ -281,7 +281,7 @@
* Gets the string form for a stack element. This is the same as
* {@code toString()} except that {@code null} is converted
* to {@code "<invalid>"}.
- *
+ *
* @param type {@code null-ok;} the stack element
* @return {@code non-null;} the string form
*/
@@ -295,7 +295,7 @@
/**
* Throws a properly-formatted exception.
- *
+ *
* @param msg {@code non-null;} useful message
* @return never (keeps compiler happy)
*/
diff --git a/dx/src/com/android/dx/cf/code/Frame.java b/dx/src/com/android/dx/cf/code/Frame.java
index f345335..002a4fb 100644
--- a/dx/src/com/android/dx/cf/code/Frame.java
+++ b/dx/src/com/android/dx/cf/code/Frame.java
@@ -197,7 +197,7 @@
} catch (NullPointerException ex) {
throw new NullPointerException("can't return from non-subroutine");
}
-
+
return (subLocals == null) ? null
: new Frame(subLocals, stack, newSubroutines);
}
@@ -234,7 +234,7 @@
* Merges this frame's subroutine lists with another. The result
* is the deepest common nesting (effectively, the common prefix of the
* two lists).
- *
+ *
* @param otherSubroutines label list of subroutine start blocks, from
* least-nested to most-nested.
* @return {@code non-null;} merged subroutine nest list as described above
@@ -359,7 +359,7 @@
RuntimeException("Incompatible merged subroutines");
}
}
-
+
}
return new Frame(resultLocals, resultStack, resultSubroutines);
diff --git a/dx/src/com/android/dx/cf/code/LineNumberList.java b/dx/src/com/android/dx/cf/code/LineNumberList.java
index 7af3f4e..f54f8b5 100644
--- a/dx/src/com/android/dx/cf/code/LineNumberList.java
+++ b/dx/src/com/android/dx/cf/code/LineNumberList.java
@@ -29,7 +29,7 @@
/**
* Returns an instance which is the concatenation of the two given
* instances.
- *
+ *
* @param list1 {@code non-null;} first instance
* @param list2 {@code non-null;} second instance
* @return {@code non-null;} combined instance
@@ -58,7 +58,7 @@
/**
* Constructs an instance.
- *
+ *
* @param count the number of elements to be in the list
*/
public LineNumberList(int count) {
@@ -67,7 +67,7 @@
/**
* Gets the indicated item.
- *
+ *
* @param n {@code >= 0;} which item
* @return {@code null-ok;} the indicated item
*/
@@ -77,7 +77,7 @@
/**
* Sets the item at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param item {@code non-null;} the item
*/
@@ -91,7 +91,7 @@
/**
* Sets the item at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param startPc {@code >= 0;} start pc of this item
* @param lineNumber {@code >= 0;} corresponding line number
@@ -102,7 +102,7 @@
/**
* Gets the line number associated with the given address.
- *
+ *
* @param pc {@code >= 0;} the address to look up
* @return {@code >= -1;} the associated line number, or {@code -1} if
* none is known
@@ -146,7 +146,7 @@
/**
* Constructs an instance.
- *
+ *
* @param startPc {@code >= 0;} start pc of this item
* @param lineNumber {@code >= 0;} corresponding line number
*/
@@ -165,7 +165,7 @@
/**
* Gets the start pc of this item.
- *
+ *
* @return the start pc
*/
public int getStartPc() {
@@ -174,7 +174,7 @@
/**
* Gets the line number of this item.
- *
+ *
* @return the line number
*/
public int getLineNumber() {
diff --git a/dx/src/com/android/dx/cf/code/LocalVariableList.java b/dx/src/com/android/dx/cf/code/LocalVariableList.java
index 8f49a33..dbf8ba2 100644
--- a/dx/src/com/android/dx/cf/code/LocalVariableList.java
+++ b/dx/src/com/android/dx/cf/code/LocalVariableList.java
@@ -33,7 +33,7 @@
/**
* Returns an instance which is the concatenation of the two given
* instances. The result is immutable.
- *
+ *
* @param list1 {@code non-null;} first instance
* @param list2 {@code non-null;} second instance
* @return {@code non-null;} combined instance
@@ -69,7 +69,7 @@
* any element whose {name, index, start, length} matches an
* element in the signature list gets augmented with the
* corresponding signature. The result is immutable.
- *
+ *
* @param descriptorList {@code non-null;} list with descriptors
* @param signatureList {@code non-null;} list with signatures
* @return {@code non-null;} the merged result
@@ -88,7 +88,7 @@
item = item.withSignature(signature);
}
result.set(i, item);
- }
+ }
result.setImmutable();
return result;
@@ -96,7 +96,7 @@
/**
* Constructs an instance.
- *
+ *
* @param count the number of elements to be in the list
*/
public LocalVariableList(int count) {
@@ -105,7 +105,7 @@
/**
* Gets the indicated item.
- *
+ *
* @param n {@code >= 0;} which item
* @return {@code null-ok;} the indicated item
*/
@@ -115,7 +115,7 @@
/**
* Sets the item at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param item {@code non-null;} the item
*/
@@ -129,10 +129,10 @@
/**
* Sets the item at the given index.
- *
+ *
* <p><b>Note:</b> At least one of {@code descriptor} or
* {@code signature} must be passed as non-null.</p>
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param startPc {@code >= 0;} the start pc of this variable's scope
* @param length {@code >= 0;} the length (in bytecodes) of this variable's
@@ -151,7 +151,7 @@
* Gets the local variable information in this instance which matches
* the given {@link com.android.dx.cf.code.LocalVariableList.Item}
* in all respects but the type descriptor and signature, if any.
- *
+ *
* @param item {@code non-null;} local variable information to match
* @return {@code null-ok;} the corresponding local variable information stored
* in this instance, or {@code null} if there is no matching
@@ -176,7 +176,7 @@
* and local index, if any. <b>Note:</b> In standard classfiles, a
* variable's start point is listed as the address of the instruction
* <i>just past</i> the one that sets the variable.
- *
+ *
* @param pc {@code >= 0;} the address to look up
* @param index {@code >= 0;} the local variable index
* @return {@code null-ok;} the associated local variable information, or
@@ -220,10 +220,10 @@
/**
* Constructs an instance.
- *
+ *
* <p><b>Note:</b> At least one of {@code descriptor} or
* {@code signature} must be passed as non-null.</p>
- *
+ *
* @param startPc {@code >= 0;} the start pc of this variable's scope
* @param length {@code >= 0;} the length (in bytecodes) of this variable's
* scope
@@ -265,7 +265,7 @@
/**
* Gets the start pc of this variable's scope.
- *
+ *
* @return {@code >= 0;} the start pc of this variable's scope
*/
public int getStartPc() {
@@ -274,7 +274,7 @@
/**
* Gets the length (in bytecodes) of this variable's scope.
- *
+ *
* @return {@code >= 0;} the length (in bytecodes) of this variable's scope
*/
public int getLength() {
@@ -311,7 +311,7 @@
/**
* Gets the variable's local index.
- *
+ *
* @return {@code >= 0;} the variable's local index
*/
public int getIndex() {
@@ -321,7 +321,7 @@
/**
* Gets the variable's type descriptor. This is a convenient shorthand
* for {@code Type.intern(getDescriptor().getString())}.
- *
+ *
* @return {@code non-null;} the variable's type
*/
public Type getType() {
@@ -331,7 +331,7 @@
/**
* Constructs and returns an instance which is identical to this
* one, except that the signature is changed to the given value.
- *
+ *
* @param newSignature {@code non-null;} the new signature
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -343,7 +343,7 @@
/**
* Gets whether this instance matches (describes) the given
* address and index.
- *
+ *
* @param pc {@code >= 0;} the address in question
* @param index {@code >= 0;} the local variable index in question
* @return {@code true} iff this instance matches {@code pc}
@@ -359,7 +359,7 @@
* Gets whether this instance matches (describes) the given
* other instance exactly in all fields except type descriptor and
* type signature.
- *
+ *
* @param other {@code non-null;} the instance to compare to
* @return {@code true} iff this instance matches
*/
diff --git a/dx/src/com/android/dx/cf/code/LocalsArray.java b/dx/src/com/android/dx/cf/code/LocalsArray.java
index b2c2689..75af047 100644
--- a/dx/src/com/android/dx/cf/code/LocalsArray.java
+++ b/dx/src/com/android/dx/cf/code/LocalsArray.java
@@ -26,7 +26,7 @@
/**
* Representation of an array of local variables, with Java semantics.
- *
+ *
* <p><b>Note:</b> For the most part, the documentation for this class
* ignores the distinction between {@link Type} and {@link
* TypeBearer}.</p>
@@ -37,14 +37,14 @@
* Constructs an instance, explicitly indicating the mutability.
*
* @param mutable {@code true} if this instance is mutable
- */
+ */
protected LocalsArray(boolean mutable) {
super(mutable);
}
/**
* Makes and returns a mutable copy of this instance.
- *
+ *
* @return {@code non-null;} the copy
*/
public abstract LocalsArray copy();
@@ -52,7 +52,7 @@
/**
* Annotates (adds context to) the given exception with information
* about this instance.
- *
+ *
* @param ex {@code non-null;} the exception to annotate
*/
public abstract void annotate(ExceptionWithContext ex);
@@ -60,14 +60,14 @@
/**
* Replaces all the occurrences of the given uninitialized type in
* this array with its initialized equivalent.
- *
+ *
* @param type {@code non-null;} type to replace
*/
public abstract void makeInitialized(Type type);
/**
* Gets the maximum number of locals this instance can refer to.
- *
+ *
* @return the max locals
*/
public abstract int getMaxLocals();
@@ -79,7 +79,7 @@
* by the operation. In case of either category, if the <i>previous</i>
* local contains a category-2 value, then it too is invalidated by
* this operation.
- *
+ *
* @param idx {@code >= 0, < getMaxLocals();} which local
* @param type {@code non-null;} new type for the local at {@code idx}
*/
@@ -90,14 +90,14 @@
* to that register spec (which includes type and optional name
* information). This is identical to calling
* {@code set(spec.getReg(), spec)}.
- *
+ *
* @param spec {@code non-null;} register spec to use as the basis for the update
*/
public abstract void set(RegisterSpec spec);
/**
* Invalidates the local at the given index.
- *
+ *
* @param idx {@code >= 0, < getMaxLocals();} which local
*/
public abstract void invalidate(int idx);
@@ -105,7 +105,7 @@
/**
* Gets the type stored at the given local index, or {@code null}
* if the given local is uninitialized / invalid.
- *
+ *
* @param idx {@code >= 0, < getMaxLocals();} which local
* @return {@code null-ok;} the type of value stored in that local
*/
@@ -115,7 +115,7 @@
* Gets the type stored at the given local index, only succeeding if
* the given local contains a valid type (though it is allowed to
* be an uninitialized instance).
- *
+ *
* @param idx {@code >= 0, < getMaxLocals();} which local
* @return {@code non-null;} the type of value stored in that local
* @throws SimException thrown if {@code idx} is valid, but
@@ -126,7 +126,7 @@
/**
* Gets the type stored at the given local index, which is expected
* to be an initialized category-1 value.
- *
+ *
* @param idx {@code >= 0, < getMaxLocals();} which local
* @return {@code non-null;} the type of value stored in that local
* @throws SimException thrown if {@code idx} is valid, but
@@ -139,7 +139,7 @@
/**
* Gets the type stored at the given local index, which is expected
* to be a category-2 value.
- *
+ *
* @param idx {@code >= 0, < getMaxLocals();} which local
* @return {@code non-null;} the type of value stored in that local
* @throws SimException thrown if {@code idx} is valid, but
diff --git a/dx/src/com/android/dx/cf/code/LocalsArraySet.java b/dx/src/com/android/dx/cf/code/LocalsArraySet.java
index fa2acbe..5d03055 100644
--- a/dx/src/com/android/dx/cf/code/LocalsArraySet.java
+++ b/dx/src/com/android/dx/cf/code/LocalsArraySet.java
@@ -74,7 +74,7 @@
super(primary.getMaxLocals() > 0);
this.primary = primary;
- this.secondaries = secondaries;
+ this.secondaries = secondaries;
}
/**
diff --git a/dx/src/com/android/dx/cf/code/Machine.java b/dx/src/com/android/dx/cf/code/Machine.java
index aff50b2..72ba3b4 100644
--- a/dx/src/com/android/dx/cf/code/Machine.java
+++ b/dx/src/com/android/dx/cf/code/Machine.java
@@ -33,11 +33,11 @@
* Gets the effective prototype of the method that this instance is
* being used for. The <i>effective</i> prototype includes an initial
* {@code this} argument for instance methods.
- *
+ *
* @return {@code non-null;} the method prototype
*/
public Prototype getPrototype();
-
+
/**
* Clears the regular and auxiliary arguments area.
*/
diff --git a/dx/src/com/android/dx/cf/code/Merger.java b/dx/src/com/android/dx/cf/code/Merger.java
index 8da9a18..51c31c3 100644
--- a/dx/src/com/android/dx/cf/code/Merger.java
+++ b/dx/src/com/android/dx/cf/code/Merger.java
@@ -34,7 +34,7 @@
/**
* Merges two locals arrays. If the merged result is the same as the first
* argument, then return the first argument (not a copy).
- *
+ *
* @param locals1 {@code non-null;} a locals array
* @param locals2 {@code non-null;} another locals array
* @return {@code non-null;} the result of merging the two locals arrays
@@ -86,7 +86,7 @@
/**
* Merges two stacks. If the merged result is the same as the first
* argument, then return the first argument (not a copy).
- *
+ *
* @param stack1 {@code non-null;} a stack
* @param stack2 {@code non-null;} another stack
* @return {@code non-null;} the result of merging the two stacks
@@ -143,7 +143,7 @@
/**
* Merges two frame types.
- *
+ *
* @param ft1 {@code non-null;} a frame type
* @param ft2 {@code non-null;} another frame type
* @return {@code non-null;} the result of merging the two types
@@ -212,7 +212,7 @@
* type {@code Object} is the supertype of all reference
* types and all arrays are assignable to
* {@code Serializable} and {@code Cloneable}.
- *
+ *
* @param supertypeBearer {@code non-null;} the supertype
* @param subtypeBearer {@code non-null;} the subtype
*/
diff --git a/dx/src/com/android/dx/cf/code/ReturnAddress.java b/dx/src/com/android/dx/cf/code/ReturnAddress.java
index 47c6071..ee36450 100644
--- a/dx/src/com/android/dx/cf/code/ReturnAddress.java
+++ b/dx/src/com/android/dx/cf/code/ReturnAddress.java
@@ -33,7 +33,7 @@
/**
* Constructs an instance.
- *
+ *
* @param subroutineAddress {@code >= 0;} the start address of the
* subroutine being returned from
*/
@@ -99,7 +99,7 @@
/**
* Gets the subroutine address.
- *
+ *
* @return {@code >= 0;} the subroutine address
*/
public int getSubroutineAddress() {
diff --git a/dx/src/com/android/dx/cf/code/RopperMachine.java b/dx/src/com/android/dx/cf/code/RopperMachine.java
index dd7fcd4..ebff24b 100644
--- a/dx/src/com/android/dx/cf/code/RopperMachine.java
+++ b/dx/src/com/android/dx/cf/code/RopperMachine.java
@@ -53,7 +53,7 @@
/**
* {@code non-null;} method constant for use in converting
- * {@code multianewarray} instructions
+ * {@code multianewarray} instructions
*/
private static final CstMethodRef MULTIANEWARRAY_METHOD =
new CstMethodRef(ARRAY_REFLECT_TYPE,
@@ -106,19 +106,19 @@
/**
* {@code null-ok;} the appropriate {@code return} op or {@code null}
- * if it is not yet known
+ * if it is not yet known
*/
private Rop returnOp;
/**
* {@code null-ok;} the source position for the return block or {@code null}
- * if it is not yet known
+ * if it is not yet known
*/
private SourcePosition returnPosition;
/**
* Constructs an instance.
- *
+ *
* @param ropper {@code non-null;} ropper controlling this instance
* @param method {@code non-null;} method being converted
* @param advice {@code non-null;} translation advice to use
@@ -126,7 +126,7 @@
public RopperMachine(Ropper ropper, ConcreteMethod method,
TranslationAdvice advice) {
super(method.getEffectiveDescriptor());
-
+
if (ropper == null) {
throw new NullPointerException("ropper == null");
}
@@ -153,7 +153,7 @@
/**
* Gets the instructions array. It is shared and gets modified by
* subsequent calls to this instance.
- *
+ *
* @return {@code non-null;} the instructions array
*/
public ArrayList<Insn> getInsns() {
@@ -162,7 +162,7 @@
/**
* Gets the return opcode encountered, if any.
- *
+ *
* @return {@code null-ok;} the return opcode
*/
public Rop getReturnOp() {
@@ -171,7 +171,7 @@
/**
* Gets the return position, if known.
- *
+ *
* @return {@code null-ok;} the return position
*/
public SourcePosition getReturnPosition() {
@@ -200,7 +200,7 @@
/**
* Gets whether {@link #catches} was used. This indicates that the
* last instruction in the block is one of the ones that can throw.
- *
+ *
* @return whether {@code catches} has been used
*/
public boolean wereCatchesUsed() {
@@ -210,7 +210,7 @@
/**
* Gets whether the block just processed ended with a
* {@code return}.
- *
+ *
* @return whether the block returns
*/
public boolean returns() {
@@ -224,7 +224,7 @@
* successor. This may return something other than
* {@code -1} in the case of an instruction with no
* successors at all (primary or otherwise).
- *
+ *
* @return {@code >= -1;} the primary successor index
*/
public int getPrimarySuccessorIndex() {
@@ -235,7 +235,7 @@
* Gets how many extra blocks will be needed to represent the
* block currently being translated. Each extra block should consist
* of one instruction from the end of the original block.
- *
+ *
* @return {@code >= 0;} the number of extra blocks needed
*/
public int getExtraBlockCount() {
@@ -318,7 +318,7 @@
* the "temporary stack" area defined for the method, and
* then move stuff back down onto the main "stack" in the
* arrangement specified by the stack op pattern.
- *
+ *
* Note: This code ends up emitting a lot of what will
* turn out to be superfluous moves (e.g., moving back and
* forth to the same local when doing a dup); however,
@@ -350,7 +350,7 @@
stackPointer += type.getType().getCategory();
}
return;
- }
+ }
TypeBearer destType = (dest != null) ? dest : Type.VOID;
Constant cst = getAuxCst();
@@ -369,7 +369,7 @@
* Add an array constructor for the int[] containing all the
* dimensions.
*/
- RegisterSpec dimsReg =
+ RegisterSpec dimsReg =
RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY);
rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount);
insn = new ThrowingCstInsn(rop, pos, sources, catches,
@@ -383,7 +383,7 @@
/*
* Add a const-class instruction for the specified array
- * class.
+ * class.
*/
/*
@@ -438,7 +438,7 @@
RegisterSpec objectReg =
RegisterSpec.make(dest.getReg(), Type.OBJECT);
-
+
insn = new ThrowingCstInsn(
Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()),
pos, RegisterSpecList.make(classReg, dimsReg),
@@ -609,7 +609,7 @@
* action we take here is to convert these initialization
* bytecodes into a single fill-array-data ROP which lays out
* all the constant values in a table.
- */
+ */
if (initValues != null) {
extraBlockCount++;
insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos,
@@ -622,7 +622,7 @@
/**
* Helper for {@link #run}, which gets the list of sources for the.
* instruction.
- *
+ *
* @param opcode the opcode being translated
* @param stackPointer {@code >= 0;} the stack pointer after the
* instruction's arguments have been popped
@@ -634,7 +634,7 @@
if (count == 0) {
// We get an easy out if there aren't any sources.
return RegisterSpecList.EMPTY;
- }
+ }
int localIndex = getLocalIndex();
RegisterSpecList sources;
@@ -696,7 +696,7 @@
/**
* Sets or updates the information about the return block.
- *
+ *
* @param op {@code non-null;} the opcode to use
* @param pos {@code non-null;} the position to use
*/
@@ -727,7 +727,7 @@
/**
* Gets the register opcode for the given Java opcode.
- *
+ *
* @param jop {@code >= 0;} the Java opcode
* @param cst {@code null-ok;} the constant argument, if any
* @return {@code >= 0;} the corresponding register opcode
@@ -756,7 +756,7 @@
case ByteOps.LDC2_W: {
return RegOps.CONST;
}
- case ByteOps.ILOAD:
+ case ByteOps.ILOAD:
case ByteOps.ISTORE: {
return RegOps.MOVE;
}
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
index 408e126..f96699e 100644
--- a/dx/src/com/android/dx/cf/code/Simulator.java
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -48,7 +48,7 @@
private static final String LOCAL_MISMATCH_ERROR =
"This is symptomatic of .class transformation tools that ignore " +
"local variable information.";
-
+
/** {@code non-null;} machine to use when simulating */
private final Machine machine;
@@ -63,7 +63,7 @@
/**
* Constructs an instance.
- *
+ *
* @param machine {@code non-null;} machine to use when simulating
* @param method {@code non-null;} method data to use
*/
@@ -85,7 +85,7 @@
/**
* Simulates the effect of executing the given basic block. This modifies
* the passed-in frame to represent the end result.
- *
+ *
* @param bb {@code non-null;} the basic block
* @param frame {@code non-null;} frame to operate on
*/
@@ -109,7 +109,7 @@
/**
* Simulates the effect of the instruction at the given offset, by
* making appropriate calls on the given frame.
- *
+ *
* @param offset {@code >= 0;} offset of the instruction to simulate
* @param frame {@code non-null;} frame to operate on
* @return the length of the instruction, in bytes
@@ -139,7 +139,7 @@
private final Machine machine;
/**
- * {@code null-ok;} frame to use; set with each call to
+ * {@code null-ok;} frame to use; set with each call to
* {@link Simulator#simulate}
*/
private Frame frame;
@@ -157,7 +157,7 @@
/**
* Sets the frame to act on.
- *
+ *
* @param frame {@code non-null;} the frame
*/
public void setFrame(Frame frame) {
@@ -382,7 +382,7 @@
if (stack.peekType(0).isCategory2()) {
throw illegalTos();
}
-
+
if (stack.peekType(1).isCategory2()) {
// "form 2" in vmspec-2
machine.popArgs(frame, 2);
@@ -474,7 +474,7 @@
/**
* Checks whether the prototype is compatible with returning the
* given type, and throws if not.
- *
+ *
* @param encountered {@code non-null;} the encountered return type
*/
private void checkReturnType(Type encountered) {
@@ -503,7 +503,7 @@
* possible, we replace the type with the one indicated in
* the local variable table, though we still need to check
* to make sure it's valid for the opcode.
- *
+ *
* The reason we use (offset + length) for the localOffset
* for a store is because it is only after the store that
* the local type becomes valid. On the other hand, the
@@ -599,7 +599,7 @@
* Get the instance prototype, and use it to direct
* the machine.
*/
- Prototype prototype =
+ Prototype prototype =
((CstMethodRef) cst).getPrototype(false);
machine.popArgs(frame, prototype);
break;
@@ -609,7 +609,7 @@
* Get the static prototype, and use it to direct
* the machine.
*/
- Prototype prototype =
+ Prototype prototype =
((CstMethodRef) cst).getPrototype(true);
machine.popArgs(frame, prototype);
break;
diff --git a/dx/src/com/android/dx/cf/code/SwitchList.java b/dx/src/com/android/dx/cf/code/SwitchList.java
index fdd1596..621d728 100644
--- a/dx/src/com/android/dx/cf/code/SwitchList.java
+++ b/dx/src/com/android/dx/cf/code/SwitchList.java
@@ -31,7 +31,7 @@
/**
* {@code non-null;} list of targets corresponding to the test values; there
* is always one extra element in the target list, to hold the
- * default target
+ * default target
*/
private final IntList targets;
@@ -40,7 +40,7 @@
/**
* Constructs an instance.
- *
+ *
* @param size {@code >= 0;} the number of elements to be in the table
*/
public SwitchList(int size) {
@@ -60,7 +60,7 @@
/**
* Gets the size of the list.
- *
+ *
* @return {@code >= 0;} the list size
*/
public int size() {
@@ -69,9 +69,9 @@
/**
* Gets the indicated test value.
- *
+ *
* @param n {@code >= 0;}, < size(); which index
- * @return the test value
+ * @return the test value
*/
public int getValue(int n) {
return values.get(n);
@@ -80,7 +80,7 @@
/**
* Gets the indicated target. Asking for the target at {@code size()}
* returns the default target.
- *
+ *
* @param n {@code >= 0, <= size();} which index
* @return {@code >= 0;} the target
*/
@@ -91,7 +91,7 @@
/**
* Gets the default target. This is just a shorthand for
* {@code getTarget(size())}.
- *
+ *
* @return {@code >= 0;} the default target
*/
public int getDefaultTarget() {
@@ -101,7 +101,7 @@
/**
* Gets the list of all targets. This includes one extra element at the
* end of the list, which holds the default target.
- *
+ *
* @return {@code non-null;} the target list
*/
public IntList getTargets() {
@@ -110,7 +110,7 @@
/**
* Gets the list of all case values.
- *
+ *
* @return {@code non-null;} the case value list
*/
public IntList getValues() {
@@ -120,7 +120,7 @@
/**
* Sets the default target. It is only valid to call this method
* when all the non-default elements have been set.
- *
+ *
* @param target {@code >= 0;} the absolute (not relative) default target
* address
*/
@@ -140,7 +140,7 @@
/**
* Adds the given item.
- *
+ *
* @param value the test value
* @param target {@code >= 0;} the absolute (not relative) target address
*/
diff --git a/dx/src/com/android/dx/cf/code/ValueAwareMachine.java b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
index 43aab8a..de75db5 100644
--- a/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
+++ b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
@@ -29,7 +29,7 @@
public class ValueAwareMachine extends BaseMachine {
/**
* Constructs an instance.
- *
+ *
* @param prototype {@code non-null;} the prototype for the associated
* method
*/
@@ -96,7 +96,7 @@
case ByteOps.IUSHR:
case ByteOps.IAND:
case ByteOps.IOR:
- case ByteOps.IXOR:
+ case ByteOps.IXOR:
case ByteOps.IINC:
case ByteOps.I2L:
case ByteOps.I2F:
@@ -161,7 +161,7 @@
}
Type type = ((TypeBearer) getAuxCst()).getType();
if (type == Type.VOID) {
- clearResult();
+ clearResult();
} else {
setResult(type);
}
diff --git a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
index 7cd9c9b..5eecfa6 100644
--- a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
+++ b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
@@ -53,7 +53,7 @@
/**
* -1 || >= 10; the end offset of this constant pool in the
* {@code byte[]} which it came from or {@code -1} if not
- * yet parsed
+ * yet parsed
*/
private int endOffset;
@@ -62,7 +62,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} the bytes of the file
*/
public ConstantPoolParser(ByteArray bytes) {
@@ -76,7 +76,7 @@
/**
* Sets the parse observer for this instance.
- *
+ *
* @param observer {@code null-ok;} the observer
*/
public void setObserver(ParseObserver observer) {
@@ -86,7 +86,7 @@
/**
* Gets the end offset of this constant pool in the {@code byte[]}
* which it came from.
- *
+ *
* @return {@code >= 10;} the end offset
*/
public int getEndOffset() {
@@ -96,7 +96,7 @@
/**
* Gets the actual constant pool.
- *
+ *
* @return {@code non-null;} the constant pool
*/
public StdConstantPool getPool() {
@@ -213,7 +213,7 @@
* parsed, also storing it in the constant pool. This will also
* have the side effect of parsing any entries the indicated one
* depends on.
- *
+ *
* @param idx which constant
* @return {@code non-null;} the parsed constant
*/
@@ -314,7 +314,7 @@
/**
* Parses a utf8 constant.
- *
+ *
* @param at offset to the start of the constant (where the tag byte is)
* @return {@code non-null;} the parsed value
*/
diff --git a/dx/src/com/android/dx/cf/direct/AnnotationParser.java b/dx/src/com/android/dx/cf/direct/AnnotationParser.java
index 88e4cd2..ca38fc5 100644
--- a/dx/src/com/android/dx/cf/direct/AnnotationParser.java
+++ b/dx/src/com/android/dx/cf/direct/AnnotationParser.java
@@ -71,10 +71,10 @@
* was parsed
*/
private int parseCursor;
-
+
/**
* Constructs an instance.
- *
+ *
* @param cf {@code non-null;} class file to parse from
* @param offset {@code >= 0;} offset into the class file data to parse at
* @param length {@code >= 0;} number of bytes left in the attribute data
@@ -93,15 +93,15 @@
this.input = bytes.makeDataInputStream();
this.parseCursor = 0;
}
-
+
/**
* Parses an annotation value ({@code element_value}) attribute.
- *
+ *
* @return {@code non-null;} the parsed constant value
*/
public Constant parseValueAttribute() {
Constant result;
-
+
try {
result = parseValue();
@@ -118,14 +118,14 @@
/**
* Parses a parameter annotation attribute.
- *
+ *
* @param visibility {@code non-null;} visibility of the parsed annotations
* @return {@code non-null;} the parsed list of lists of annotations
*/
public AnnotationsList parseParameterAttribute(
AnnotationVisibility visibility) {
AnnotationsList result;
-
+
try {
result = parseAnnotationsList(visibility);
@@ -139,10 +139,10 @@
return result;
}
-
+
/**
* Parses an annotation attribute, per se.
- *
+ *
* @param visibility {@code non-null;} visibility of the parsed annotations
* @return {@code non-null;} the list of annotations read from the attribute
* data
@@ -150,7 +150,7 @@
public Annotations parseAnnotationAttribute(
AnnotationVisibility visibility) {
Annotations result;
-
+
try {
result = parseAnnotations(visibility);
@@ -167,7 +167,7 @@
/**
* Parses a list of annotation lists.
- *
+ *
* @param visibility {@code non-null;} visibility of the parsed annotations
* @return {@code non-null;} the list of annotation lists read from the attribute
* data
@@ -202,7 +202,7 @@
/**
* Parses an annotation list.
- *
+ *
* @param visibility {@code non-null;} visibility of the parsed annotations
* @return {@code non-null;} the list of annotations read from the attribute
* data
@@ -237,7 +237,7 @@
/**
* Parses a single annotation.
- *
+ *
* @param visibility {@code non-null;} visibility of the parsed annotation
* @return {@code non-null;} the parsed annotation
*/
@@ -274,18 +274,18 @@
annotation.setImmutable();
return annotation;
}
-
+
/**
* Parses a {@link NameValuePair}.
- *
+ *
* @return {@code non-null;} the parsed element
*/
private NameValuePair parseElement() throws IOException {
requireLength(5);
-
+
int elementNameIndex = input.readUnsignedShort();
CstUtf8 elementName = (CstUtf8) pool.get(elementNameIndex);
-
+
if (observer != null) {
parsed(2, "element_name: " + elementName.toHuman());
parsed(0, "value: ");
@@ -303,7 +303,7 @@
/**
* Parses an annotation value.
- *
+ *
* @return {@code non-null;} the parsed value
*/
private Constant parseValue() throws IOException {
@@ -352,7 +352,7 @@
int classInfoIndex = input.readUnsignedShort();
CstUtf8 value = (CstUtf8) pool.get(classInfoIndex);
Type type = Type.internReturnType(value.getString());
-
+
if (observer != null) {
parsed(2, "class_info: " + type.toHuman());
}
@@ -370,7 +370,7 @@
int constNameIndex = input.readUnsignedShort();
CstUtf8 typeName = (CstUtf8) pool.get(typeNameIndex);
CstUtf8 constName = (CstUtf8) pool.get(constNameIndex);
-
+
if (observer != null) {
parsed(2, "type_name: " + typeName.toHuman());
parsed(2, "const_name: " + constName.toHuman());
@@ -416,11 +416,11 @@
}
}
}
-
+
/**
* Helper for {@link #parseValue}, which parses a constant reference
* and returns the referred-to constant value.
- *
+ *
* @return {@code non-null;} the parsed value
*/
private Constant parseConstant() throws IOException {
@@ -428,8 +428,8 @@
Constant value = (Constant) pool.get(constValueIndex);
if (observer != null) {
- String human = (value instanceof CstUtf8)
- ? ((CstUtf8) value).toQuoted()
+ String human = (value instanceof CstUtf8)
+ ? ((CstUtf8) value).toQuoted()
: value.toHuman();
parsed(2, "constant_value: " + human);
}
@@ -440,7 +440,7 @@
/**
* Helper which will throw an exception if the given number of bytes
* is not available to be read.
- *
+ *
* @param requiredLength the number of required bytes
*/
private void requireLength(int requiredLength) throws IOException {
@@ -448,12 +448,12 @@
throw new ParseException("truncated annotation attribute");
}
}
-
+
/**
* Helper which indicates that some bytes were just parsed. This should
* only be used (for efficiency sake) if the parse is known to be
* observed.
- *
+ *
* @param length {@code >= 0;} number of bytes parsed
* @param message {@code non-null;} associated message
*/
@@ -465,7 +465,7 @@
/**
* Convenience wrapper that simply calls through to
* {@code observer.changeIndent()}.
- *
+ *
* @param indent the amount to change the indent by
*/
private void changeIndent(int indent) {
diff --git a/dx/src/com/android/dx/cf/direct/AttributeFactory.java b/dx/src/com/android/dx/cf/direct/AttributeFactory.java
index d00a859..f98372c 100644
--- a/dx/src/com/android/dx/cf/direct/AttributeFactory.java
+++ b/dx/src/com/android/dx/cf/direct/AttributeFactory.java
@@ -57,7 +57,7 @@
* indicated position in the given array. This method figures out
* the name, and then does all the setup to call on to {@link #parse0},
* which does the actual construction.
- *
+ *
* @param cf {@code non-null;} class file to parse from
* @param context context to parse in; one of the {@code CTX_*}
* constants
@@ -96,7 +96,7 @@
return parse0(cf, context, name.getString(), offset + 6, length,
observer);
} catch (ParseException ex) {
- ex.addContext("...while parsing " +
+ ex.addContext("...while parsing " +
((name != null) ? (name.toHuman() + " ") : "") +
"attribute at offset " + Hex.u4(offset));
throw ex;
@@ -107,7 +107,7 @@
* Parses attribute content. The base class implements this by constructing
* an instance of {@link RawAttribute}. Subclasses are expected to
* override this to do something better in most cases.
- *
+ *
* @param cf {@code non-null;} class file to parse from
* @param context context to parse in; one of the {@code CTX_*}
* constants
diff --git a/dx/src/com/android/dx/cf/direct/ClassPathOpener.java b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
index 927e9bd..4e8c435 100644
--- a/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
+++ b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
@@ -207,7 +207,7 @@
byte[] buf = new byte[20000];
boolean any = false;
- ArrayList<? extends java.util.zip.ZipEntry> entriesList
+ ArrayList<? extends java.util.zip.ZipEntry> entriesList
= Collections.list(zip.entries());
if (sort) {
diff --git a/dx/src/com/android/dx/cf/direct/CodeObserver.java b/dx/src/com/android/dx/cf/direct/CodeObserver.java
index 952f1bc..efcc80b 100644
--- a/dx/src/com/android/dx/cf/direct/CodeObserver.java
+++ b/dx/src/com/android/dx/cf/direct/CodeObserver.java
@@ -47,7 +47,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} actual array of bytecode
* @param observer {@code non-null;} observer to inform of parsing
*/
@@ -198,7 +198,7 @@
/**
* Helper to produce the first bit of output for each instruction.
- *
+ *
* @param offset the offset to the start of the instruction
*/
private String header(int offset) {
@@ -220,7 +220,7 @@
/**
* Helper for {@link #visitConstant} where the constant is an
* {@code int}.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length instruction length
@@ -247,7 +247,7 @@
/**
* Helper for {@link #visitConstant} where the constant is a
* {@code long}.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length instruction length
@@ -271,7 +271,7 @@
/**
* Helper for {@link #visitConstant} where the constant is a
* {@code float}.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length instruction length
@@ -289,7 +289,7 @@
/**
* Helper for {@link #visitConstant} where the constant is a
* {@code double}.
- *
+ *
* @param opcode the opcode
* @param offset offset to the instruction
* @param length instruction length
diff --git a/dx/src/com/android/dx/cf/direct/DirectClassFile.java b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
index ac227fa..b194572 100644
--- a/dx/src/com/android/dx/cf/direct/DirectClassFile.java
+++ b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
@@ -46,18 +46,18 @@
/**
* minimum {@code .class} file major version
- *
+ *
* The class file definition (vmspec/2nd-edition) says:
- *
+ *
* "Implementations of version 1.2 of the
* Java 2 platform can support class file
* formats of versions in the range 45.0
* through 46.0 inclusive."
- *
+ *
* The class files generated by the build are currently
* (as of 11/2006) reporting version 49.0 (0x31.0x00),
* however, so we use that as our upper bound.
- *
+ *
* Valid ranges are typically of the form
* "A.0 through B.C inclusive" where A <= B and C >= 0,
* which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION.
@@ -72,7 +72,7 @@
/**
* {@code non-null;} the file path for the class, excluding any base directory
- * specification
+ * specification
*/
private final String filePath;
@@ -83,19 +83,19 @@
* whether to be strict about parsing; if
* {@code false}, this avoids doing checks that only exist
* for purposes of verification (such as magic number matching and
- * path-package consistency checking)
+ * path-package consistency checking)
*/
private final boolean strictParse;
/**
* {@code null-ok;} the constant pool; only ever {@code null}
- * before the constant pool is successfully parsed
+ * before the constant pool is successfully parsed
*/
private StdConstantPool pool;
/**
* the class file field {@code access_flags}; will be {@code -1}
- * before the file is successfully parsed
+ * before the file is successfully parsed
*/
private int accessFlags;
@@ -108,33 +108,33 @@
/**
* {@code null-ok;} the class file field {@code super_class}, interpreted
- * as a type constant if non-zero
+ * as a type constant if non-zero
*/
private CstType superClass;
/**
* {@code null-ok;} the class file field {@code interfaces}; only
* ever {@code null} before the file is successfully
- * parsed
+ * parsed
*/
private TypeList interfaces;
/**
* {@code null-ok;} the class file field {@code fields}; only ever
- * {@code null} before the file is successfully parsed
+ * {@code null} before the file is successfully parsed
*/
private FieldList fields;
/**
* {@code null-ok;} the class file field {@code methods}; only ever
- * {@code null} before the file is successfully parsed
+ * {@code null} before the file is successfully parsed
*/
private MethodList methods;
/**
* {@code null-ok;} the class file field {@code attributes}; only
* ever {@code null} before the file is successfully
- * parsed
+ * parsed
*/
private StdAttributeList attributes;
@@ -147,7 +147,7 @@
/**
* Returns the string form of an object or {@code "(none)"}
* (rather than {@code "null"}) for {@code null}.
- *
+ *
* @param obj {@code null-ok;} the object to stringify
* @return {@code non-null;} the appropriate string form
*/
@@ -161,7 +161,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} the bytes of the file
* @param filePath {@code non-null;} the file path for the class,
* excluding any base directory specification
@@ -188,7 +188,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} the bytes of the file
* @param filePath {@code non-null;} the file path for the class,
* excluding any base directory specification
@@ -204,7 +204,7 @@
/**
* Sets the parse observer for this instance.
- *
+ *
* @param observer {@code null-ok;} the observer
*/
public void setObserver(ParseObserver observer) {
@@ -213,7 +213,7 @@
/**
* Sets the attribute factory to use.
- *
+ *
* @param attributeFactory {@code non-null;} the attribute factory
*/
public void setAttributeFactory(AttributeFactory attributeFactory) {
@@ -226,7 +226,7 @@
/**
* Gets the {@link ByteArray} that this instance's data comes from.
- *
+ *
* @return {@code non-null;} the bytes
*/
public ByteArray getBytes() {
@@ -318,7 +318,7 @@
* translated to type constants. Instance construction will fail
* if any of the (alleged) indices turn out not to refer to
* constant pool entries of type {@code Class}.
- *
+ *
* @param offset offset into {@link #bytes} for the start of the
* data
* @param size number of elements in the list (not number of bytes)
@@ -332,14 +332,14 @@
if (pool == null) {
throw new IllegalStateException("pool not yet initialized");
}
-
+
return new DcfTypeList(bytes, offset, size, pool, observer);
}
/**
* Gets the class file field {@code magic}, but without doing any
* checks or parsing first.
- *
+ *
* @return the magic value
*/
public int getMagic0() {
@@ -349,7 +349,7 @@
/**
* Gets the class file field {@code minor_version}, but
* without doing any checks or parsing first.
- *
+ *
* @return the minor version
*/
public int getMinorVersion0() {
@@ -359,7 +359,7 @@
/**
* Gets the class file field {@code major_version}, but
* without doing any checks or parsing first.
- *
+ *
* @return the major version
*/
public int getMajorVersion0() {
@@ -404,7 +404,7 @@
/**
* Sees if the .class file header magic/version are within
* range.
- *
+ *
* @param magic the value of a classfile "magic" field
* @param minorVersion the value of a classfile "minor_version" field
* @param majorVersion the value of a classfile "major_version" field
@@ -479,7 +479,7 @@
if (observer != null) {
observer.parsed(bytes, at, 2,
- "access_flags: " +
+ "access_flags: " +
AccessFlags.classString(accessFlags));
observer.parsed(bytes, at + 2, 2, "this_class: " + thisClass);
observer.parsed(bytes, at + 4, 2, "super_class: " +
@@ -559,7 +559,7 @@
private static class DcfTypeList implements TypeList {
/** {@code non-null;} array containing the data */
private final ByteArray bytes;
-
+
/** number of elements in the list (not number of bytes) */
private final int size;
@@ -568,7 +568,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} original classfile's bytes
* @param offset offset into {@link #bytes} for the start of the
* data
@@ -628,6 +628,6 @@
/** {@inheritDoc} */
public TypeList withAddedType(Type type) {
throw new UnsupportedOperationException("unsupported");
- }
+ }
}
}
diff --git a/dx/src/com/android/dx/cf/direct/FieldListParser.java b/dx/src/com/android/dx/cf/direct/FieldListParser.java
index 24ba7e0..2d8280d 100644
--- a/dx/src/com/android/dx/cf/direct/FieldListParser.java
+++ b/dx/src/com/android/dx/cf/direct/FieldListParser.java
@@ -33,7 +33,7 @@
/**
* Constructs an instance.
- *
+ *
* @param cf {@code non-null;} the class file to parse from
* @param definer {@code non-null;} class being defined
* @param offset offset in {@code bytes} to the start of the list
@@ -47,7 +47,7 @@
/**
* Gets the parsed list.
- *
+ *
* @return {@code non-null;} the parsed list
*/
public StdFieldList getList() {
diff --git a/dx/src/com/android/dx/cf/direct/MemberListParser.java b/dx/src/com/android/dx/cf/direct/MemberListParser.java
index a0023c6..91a5e1d 100644
--- a/dx/src/com/android/dx/cf/direct/MemberListParser.java
+++ b/dx/src/com/android/dx/cf/direct/MemberListParser.java
@@ -131,7 +131,7 @@
/**
* Gets the human-oriented name for what this instance is parsing.
* Subclasses must override this method.
- *
+ *
* @return {@code non-null;} the human oriented name
*/
protected abstract String humanName();
@@ -148,7 +148,7 @@
/**
* Gets the {@code CTX_*} constant to use when parsing attributes.
* Subclasses must override this method.
- *
+ *
* @return {@code non-null;} the human oriented name
*/
protected abstract int getAttributeContext();
diff --git a/dx/src/com/android/dx/cf/direct/MethodListParser.java b/dx/src/com/android/dx/cf/direct/MethodListParser.java
index 6ab1aba..9e3494e 100644
--- a/dx/src/com/android/dx/cf/direct/MethodListParser.java
+++ b/dx/src/com/android/dx/cf/direct/MethodListParser.java
@@ -33,7 +33,7 @@
/**
* Constructs an instance.
- *
+ *
* @param cf {@code non-null;} the class file to parse from
* @param definer {@code non-null;} class being defined
* @param offset offset in {@code bytes} to the start of the list
@@ -47,7 +47,7 @@
/**
* Gets the parsed list.
- *
+ *
* @return {@code non-null;} the parsed list
*/
public StdMethodList getList() {
diff --git a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
index da12a4e..a6a97af 100644
--- a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
+++ b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
@@ -366,7 +366,7 @@
if (observer != null) {
observer.parsed(bytes, offset, 2, "class: " + type);
- observer.parsed(bytes, offset + 2, 2, "method: " +
+ observer.parsed(bytes, offset + 2, 2, "method: " +
DirectClassFile.stringOrNone(method));
}
@@ -439,13 +439,13 @@
list.set(i, innerClass, outerClass, name, accessFlags);
if (observer != null) {
observer.parsed(bytes, offset, 2,
- "inner_class: " +
+ "inner_class: " +
DirectClassFile.stringOrNone(innerClass));
observer.parsed(bytes, offset + 2, 2,
- " outer_class: " +
+ " outer_class: " +
DirectClassFile.stringOrNone(outerClass));
observer.parsed(bytes, offset + 4, 2,
- " name: " +
+ " name: " +
DirectClassFile.stringOrNone(name));
observer.parsed(bytes, offset + 6, 2,
" access_flags: " +
@@ -548,7 +548,7 @@
/**
* Parse the table part of either a {@code LocalVariableTable}
* or a {@code LocalVariableTypeTable}.
- *
+ *
* @param bytes {@code non-null;} bytes to parse, which should <i>only</i>
* contain the table data (no header)
* @param pool {@code non-null;} constant pool to use
@@ -578,13 +578,13 @@
CstUtf8 type = (CstUtf8) pool.get(typeIdx);
CstUtf8 descriptor = null;
CstUtf8 signature = null;
-
+
if (typeTable) {
signature = type;
} else {
descriptor = type;
}
-
+
list.set(i, startPc, length, name,
descriptor, signature, index);
@@ -614,7 +614,7 @@
AnnotationParser ap =
new AnnotationParser(cf, offset, length, observer);
- Annotations annotations =
+ Annotations annotations =
ap.parseAnnotationAttribute(AnnotationVisibility.BUILD);
return new AttRuntimeInvisibleAnnotations(annotations, length);
@@ -631,7 +631,7 @@
AnnotationParser ap =
new AnnotationParser(cf, offset, length, observer);
- Annotations annotations =
+ Annotations annotations =
ap.parseAnnotationAttribute(AnnotationVisibility.RUNTIME);
return new AttRuntimeVisibleAnnotations(annotations, length);
@@ -730,7 +730,7 @@
/**
* Throws the right exception when a known attribute has a way too short
* length.
- *
+ *
* @return never
* @throws ParseException always thrown
*/
@@ -741,7 +741,7 @@
/**
* Throws the right exception when a known attribute has a too short
* length.
- *
+ *
* @return never
* @throws ParseException always thrown
*/
@@ -752,7 +752,7 @@
/**
* Throws the right exception when an attribute has an unexpected length
* (given its contents).
- *
+ *
* @param expected expected length
* @return never
* @throws ParseException always thrown
diff --git a/dx/src/com/android/dx/cf/iface/ClassFile.java b/dx/src/com/android/dx/cf/iface/ClassFile.java
index e37fec0..0f584ba 100644
--- a/dx/src/com/android/dx/cf/iface/ClassFile.java
+++ b/dx/src/com/android/dx/cf/iface/ClassFile.java
@@ -81,7 +81,7 @@
public ConstantPool getConstantPool();
/**
- * Gets the field {@code interfaces} (along with
+ * Gets the field {@code interfaces} (along with
* {@code interfaces_count}).
*
* @return {@code non-null;} the list of interfaces
diff --git a/dx/src/com/android/dx/cf/iface/StdAttributeList.java b/dx/src/com/android/dx/cf/iface/StdAttributeList.java
index dd5dfd7..287b8c7 100644
--- a/dx/src/com/android/dx/cf/iface/StdAttributeList.java
+++ b/dx/src/com/android/dx/cf/iface/StdAttributeList.java
@@ -26,7 +26,7 @@
implements AttributeList {
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public StdAttributeList(int size) {
@@ -94,7 +94,7 @@
/**
* Sets the attribute at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which attribute
* @param attribute {@code null-ok;} the attribute object
*/
diff --git a/dx/src/com/android/dx/cf/iface/StdField.java b/dx/src/com/android/dx/cf/iface/StdField.java
index c3a4da6..ef9873d 100644
--- a/dx/src/com/android/dx/cf/iface/StdField.java
+++ b/dx/src/com/android/dx/cf/iface/StdField.java
@@ -28,7 +28,7 @@
public final class StdField extends StdMember implements Field {
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the defining class
* @param accessFlags access flags
* @param nat {@code non-null;} member name and type (descriptor)
diff --git a/dx/src/com/android/dx/cf/iface/StdFieldList.java b/dx/src/com/android/dx/cf/iface/StdFieldList.java
index 044d6b7..f27bd22 100644
--- a/dx/src/com/android/dx/cf/iface/StdFieldList.java
+++ b/dx/src/com/android/dx/cf/iface/StdFieldList.java
@@ -25,7 +25,7 @@
public final class StdFieldList extends FixedSizeList implements FieldList {
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public StdFieldList(int size) {
@@ -39,7 +39,7 @@
/**
* Sets the field at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which field
* @param field {@code null-ok;} the field object
*/
diff --git a/dx/src/com/android/dx/cf/iface/StdMember.java b/dx/src/com/android/dx/cf/iface/StdMember.java
index dfe45c3..9f15585 100644
--- a/dx/src/com/android/dx/cf/iface/StdMember.java
+++ b/dx/src/com/android/dx/cf/iface/StdMember.java
@@ -39,7 +39,7 @@
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the defining class
* @param accessFlags access flags
* @param nat {@code non-null;} member name and type (descriptor)
diff --git a/dx/src/com/android/dx/cf/iface/StdMethod.java b/dx/src/com/android/dx/cf/iface/StdMethod.java
index 15fd6e1..c511d7d 100644
--- a/dx/src/com/android/dx/cf/iface/StdMethod.java
+++ b/dx/src/com/android/dx/cf/iface/StdMethod.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the defining class
* @param accessFlags access flags
* @param nat {@code non-null;} member name and type (descriptor)
diff --git a/dx/src/com/android/dx/cf/iface/StdMethodList.java b/dx/src/com/android/dx/cf/iface/StdMethodList.java
index 521021e..417cdee 100644
--- a/dx/src/com/android/dx/cf/iface/StdMethodList.java
+++ b/dx/src/com/android/dx/cf/iface/StdMethodList.java
@@ -25,7 +25,7 @@
public final class StdMethodList extends FixedSizeList implements MethodList {
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public StdMethodList(int size) {
@@ -39,7 +39,7 @@
/**
* Sets the method at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which method
* @param method {@code null-ok;} the method object
*/
diff --git a/dx/src/com/android/dx/command/Main.java b/dx/src/com/android/dx/command/Main.java
index 281a83e..626cf7a 100644
--- a/dx/src/com/android/dx/command/Main.java
+++ b/dx/src/com/android/dx/command/Main.java
@@ -50,7 +50,7 @@
" Dump classfiles, or transformations thereof, in a " +
"human-oriented format.\n" +
" dx --junit [-wait] <TestClass>\n" +
- " Run the indicated unit test.\n" +
+ " Run the indicated unit test.\n" +
" dx -J<option> ... <arguments, in one of the above " +
"forms>\n" +
" Pass VM-specific options to the virtual machine that " +
@@ -60,7 +60,7 @@
").\n" +
" dx --help\n" +
" Print this message.";
-
+
/**
* This class is uninstantiable.
*/
@@ -117,7 +117,7 @@
} catch (Throwable ex) {
System.err.println("\nUNEXPECTED TOP-LEVEL ERROR:");
ex.printStackTrace();
- if ((ex instanceof NoClassDefFoundError)
+ if ((ex instanceof NoClassDefFoundError)
|| (ex instanceof NoSuchMethodError)) {
System.err.println(
"Note: You may be using an incompatible " +
@@ -126,7 +126,7 @@
"with recent releases of GCJ.)");
}
System.exit(3);
- }
+ }
if (!gotCmd) {
System.err.println("error: no command specified");
diff --git a/dx/src/com/android/dx/command/annotool/AnnotationLister.java b/dx/src/com/android/dx/command/annotool/AnnotationLister.java
index d3fb27c..a29e5ba 100644
--- a/dx/src/com/android/dx/command/annotool/AnnotationLister.java
+++ b/dx/src/com/android/dx/command/annotool/AnnotationLister.java
@@ -202,7 +202,7 @@
case CLASS:
case INNERCLASS:
case METHOD:
- matchPackages.add(packageName);
+ matchPackages.add(packageName);
break;
case PACKAGE:
System.out.println(packageName.replace('/','.'));
diff --git a/dx/src/com/android/dx/command/annotool/Main.java b/dx/src/com/android/dx/command/annotool/Main.java
index 9fd1ac5..7661c3d 100644
--- a/dx/src/com/android/dx/command/annotool/Main.java
+++ b/dx/src/com/android/dx/command/annotool/Main.java
@@ -39,7 +39,7 @@
InvalidArgumentException() {
super();
}
-
+
InvalidArgumentException(String s) {
super(s);
}
@@ -49,7 +49,7 @@
CLASS,
INNERCLASS,
METHOD,
- PACKAGE
+ PACKAGE
}
diff --git a/dx/src/com/android/dx/command/dexer/Main.java b/dx/src/com/android/dx/command/dexer/Main.java
index 5a9f417..8df1bea 100644
--- a/dx/src/com/android/dx/command/dexer/Main.java
+++ b/dx/src/com/android/dx/command/dexer/Main.java
@@ -244,7 +244,7 @@
}
});
- return opener.process();
+ return opener.process();
}
/**
@@ -294,7 +294,7 @@
if (! args.coreLibrary) {
checkClassName(name);
}
-
+
try {
ClassDefItem clazz =
CfTranslator.translate(name, bytes, args.cfOptions);
@@ -317,13 +317,13 @@
* Check the class name to make sure it's not a "core library"
* class. If there is a problem, this updates the error count and
* throws an exception to stop processing.
- *
+ *
* @param name {@code non-null;} the fully-qualified internal-form
* class name
*/
private static void checkClassName(String name) {
boolean bogus = false;
-
+
if (name.startsWith("java/")) {
bogus = true;
} else if (name.startsWith("javax/")) {
@@ -348,7 +348,7 @@
*/
DxConsole.err.println("\ntrouble processing \"" + name + "\":");
- DxConsole.err.println("\n" +
+ DxConsole.err.println("\n" +
"Attempt to include a core class (java.* or javax.*) in " +
"something other\n" +
"than a core library. It is likely that you have " +
@@ -690,7 +690,7 @@
meth.debugPrint(pw, args.verboseDump);
/*
- * The (default) source file is an attribute of the class, but
+ * The (default) source file is an attribute of the class, but
* it's useful to see it in method dumps.
*/
CstUtf8 sourceFile = clazz.getSourceFile();
@@ -732,7 +732,7 @@
private static class StopProcessing extends RuntimeException {
// This space intentionally left blank.
}
-
+
/**
* Command-line argument parser and access.
*/
diff --git a/dx/src/com/android/dx/command/dump/BaseDumper.java b/dx/src/com/android/dx/command/dump/BaseDumper.java
index d2c1e13..ad6540b 100644
--- a/dx/src/com/android/dx/command/dump/BaseDumper.java
+++ b/dx/src/com/android/dx/command/dump/BaseDumper.java
@@ -48,7 +48,7 @@
/**
* {@code non-null;} the file path for the class, excluding any base
- * directory specification
+ * directory specification
*/
private final String filePath;
@@ -72,7 +72,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} bytes of the (alleged) class file
* on the left)
* @param out {@code non-null;} where to dump to
@@ -157,7 +157,7 @@
/**
* Gets the current dump cursor (that is, the offset of the expected
* next byte to dump).
- *
+ *
* @return {@code >= 0;} the dump cursor
*/
protected final int getAt() {
@@ -166,7 +166,7 @@
/**
* Sets the dump cursor to the indicated offset in the given array.
- *
+ *
* @param arr {@code non-null;} array in question
* @param offset {@code >= 0;} offset into the array
*/
@@ -176,7 +176,7 @@
/**
* Gets the array of {@code byte}s to process.
- *
+ *
* @return {@code non-null;} the bytes
*/
protected final byte[] getBytes() {
@@ -185,7 +185,7 @@
/**
* Gets the filesystem/jar path of the file being dumped.
- *
+ *
* @return {@code non-null;} the path
*/
protected final String getFilePath() {
@@ -194,7 +194,7 @@
/**
* Gets whether to be strict about parsing.
- *
+ *
* @return whether to be strict about parsing
*/
protected final boolean getStrictParse() {
@@ -203,7 +203,7 @@
/**
* Prints the given string to this instance's output stream.
- *
+ *
* @param s {@code null-ok;} string to print
*/
protected final void print(String s) {
@@ -213,7 +213,7 @@
/**
* Prints the given string to this instance's output stream, followed
* by a newline.
- *
+ *
* @param s {@code null-ok;} string to print
*/
protected final void println(String s) {
@@ -222,7 +222,7 @@
/**
* Gets whether this dump is to include raw bytes.
- *
+ *
* @return the raw bytes flag
*/
protected final boolean getRawBytes() {
@@ -232,7 +232,7 @@
/**
* Gets the width of the first column of output. This is {@code 0}
* unless raw bytes are being included in the output.
- *
+ *
* @return {@code >= 0;} the width of the first column
*/
protected final int getWidth1() {
@@ -245,7 +245,7 @@
/**
* Gets the width of the second column of output.
- *
+ *
* @return {@code >= 0;} the width of the second column
*/
protected final int getWidth2() {
@@ -255,7 +255,7 @@
/**
* Constructs a hex data dump of the given portion of {@link #bytes}.
- *
+ *
* @param offset offset to start dumping at
* @param len length to dump
* @return {@code non-null;} the dump
@@ -267,7 +267,7 @@
/**
* Combines a pair of strings as two columns, or if this is one-column
* output, format the otherwise-second column.
- *
+ *
* @param s1 {@code non-null;} the first column's string
* @param s2 {@code non-null;} the second column's string
* @return {@code non-null;} the combined output
diff --git a/dx/src/com/android/dx/command/dump/BlockDumper.java b/dx/src/com/android/dx/command/dump/BlockDumper.java
index 0858eab..7a11888 100644
--- a/dx/src/com/android/dx/command/dump/BlockDumper.java
+++ b/dx/src/com/android/dx/command/dump/BlockDumper.java
@@ -55,7 +55,7 @@
/**
* {@code null-ok;} the class file object being constructed;
- * becomes non-null during {@link #dump}
+ * becomes non-null during {@link #dump}
*/
protected DirectClassFile classFile;
@@ -71,7 +71,7 @@
/**
* Dumps the given array, interpreting it as a class file and dumping
* methods with indications of block-level stuff.
- *
+ *
* @param bytes {@code non-null;} bytes of the (alleged) class file
* @param out {@code non-null;} where to dump to
* @param filePath the file path for the class, excluding any base
@@ -189,7 +189,7 @@
if (!shouldDumpMethod(name)) {
return;
}
-
+
ConcreteMethod meth = new ConcreteMethod((Method) member, classFile,
true, true);
@@ -202,7 +202,7 @@
/**
* Does a regular basic block dump.
- *
+ *
* @param meth {@code non-null;} method data to dump
*/
private void regularDump(ConcreteMethod meth) {
@@ -257,7 +257,7 @@
CstType exceptionClass = one.getExceptionClass();
parsed(bytes, end, 0,
"catch " +
- ((exceptionClass == CstType.OBJECT) ? "<any>" :
+ ((exceptionClass == CstType.OBJECT) ? "<any>" :
exceptionClass.toHuman()) + " -> " +
Hex.u2(one.getHandlerPc()));
}
@@ -277,7 +277,7 @@
/**
* Does a registerizing dump.
- *
+ *
* @param meth {@code non-null;} method data to dump
*/
private void ropDump(ConcreteMethod meth) {
diff --git a/dx/src/com/android/dx/command/dump/SsaDumper.java b/dx/src/com/android/dx/command/dump/SsaDumper.java
index e5e9d97..de44c83 100644
--- a/dx/src/com/android/dx/command/dump/SsaDumper.java
+++ b/dx/src/com/android/dx/command/dump/SsaDumper.java
@@ -51,7 +51,7 @@
public class SsaDumper extends BlockDumper {
/**
* Does the dump.
- *
+ *
* @param bytes {@code non-null;} bytes of the original class file
* @param out {@code non-null;} where to dump to
* @param filePath the file path for the class, excluding any base
@@ -66,7 +66,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bytes {@code non-null;} bytes of the original class file
* @param out {@code non-null;} where to dump to
* @param filePath the file path for the class, excluding any base
@@ -124,10 +124,10 @@
sb.append('\n');
ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
- ArrayList<SsaBasicBlock> sortedBlocks =
+ ArrayList<SsaBasicBlock> sortedBlocks =
(ArrayList<SsaBasicBlock>) blocks.clone();
Collections.sort(sortedBlocks, SsaBasicBlock.LABEL_COMPARATOR);
-
+
for (SsaBasicBlock block : sortedBlocks) {
sb.append("block ")
.append(Hex.u2(block.getRopLabel())).append('\n');
@@ -164,7 +164,7 @@
sb.append(Hex.u2(succLabelList.get(i)));
if (szSuccLabels != 1 && primary == succLabelList.get(i)) {
- sb.append(" *");
+ sb.append(" *");
}
sb.append('\n');
}
diff --git a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
index cdd29d7..2508a59 100644
--- a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
+++ b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
@@ -84,7 +84,7 @@
* combines both visible and invisible annotations into a single
* result set and also adds in a system annotation for the
* {@code Signature} attribute if present.
- *
+ *
* @param attribs {@code non-null;} the attributes list to search in
* @return {@code non-null;} the set of annotations, which may be empty
*/
@@ -107,7 +107,7 @@
* class is an annotation class, then this also includes a
* representation of all the {@code AnnotationDefault}
* values.
- *
+ *
* @param cf {@code non-null;} the class in question
* @param args {@code non-null;} the high-level options
* @return {@code non-null;} the set of annotations, which may be empty
@@ -149,7 +149,7 @@
* Gets the annotations out of a given method, similar to {@link
* #getAnnotations}, also including an annotation for the translation
* of the method-specific attribute {@code Exceptions}.
- *
+ *
* @param method {@code non-null;} the method in question
* @return {@code non-null;} the set of annotations, which may be empty
*/
@@ -158,18 +158,18 @@
TypeList exceptions = getExceptions(method);
if (exceptions.size() != 0) {
- Annotation throwsAnnotation =
+ Annotation throwsAnnotation =
AnnotationUtils.makeThrows(exceptions);
result = Annotations.combine(result, throwsAnnotation);
}
return result;
}
-
+
/**
* Helper method for {@link #getAnnotations} which just gets the
* existing annotations, per se.
- *
+ *
* @param attribs {@code non-null;} the attributes list to search in
* @return {@code non-null;} the set of annotations, which may be empty
*/
@@ -201,7 +201,7 @@
/**
* Gets the {@code Signature} attribute out of a given
* {@link AttributeList}, if any, translating it to an annotation.
- *
+ *
* @param attribs {@code non-null;} the attributes list to search in
* @return {@code null-ok;} the converted {@code Signature} annotation,
* if there was an attribute to translate
@@ -223,7 +223,7 @@
* If the class really has an enclosing method, this returns an
* {@code EnclosingMethod} annotation; if not, this returns
* an {@code EnclosingClass} annotation.
- *
+ *
* @param attribs {@code non-null;} the attributes list to search in
* @return {@code null-ok;} the converted {@code EnclosingMethod} or
* {@code EnclosingClass} annotation, if there was an
@@ -260,8 +260,9 @@
* {@link AttributeList}, if any, translating it to one or more of an
* {@code InnerClass}, {@code EnclosingClass}, or
* {@code MemberClasses} annotation.
- *
- * @param thisClass {@code non-null;} type representing the class being processed
+ *
+ * @param thisClass {@code non-null;} type representing the class being
+ * processed
* @param attribs {@code non-null;} the attributes list to search in
* @param needEnclosingClass whether to include an
* {@code EnclosingClass} annotation
@@ -298,7 +299,7 @@
}
int membersSize = membersList.size();
-
+
if ((foundThisClass == null) && (membersSize == 0)) {
return null;
}
@@ -314,10 +315,20 @@
if (outer == null) {
throw new Warning(
"Ignoring InnerClasses attribute for an " +
- "anonymous inner class that doesn't come with " +
- "an associated EnclosingMethod attribute. " +
- "(This class was probably produced by a broken " +
- "compiler.)");
+ "anonymous inner class\n" +
+ "(" + thisClass.toHuman() +
+ ") that doesn't come with an\n" +
+ "associated EnclosingMethod attribute. " +
+ "This class was probably produced by a\n" +
+ "compiler that did not target the modern " +
+ ".class file format. The recommended\n" +
+ "solution is to recompile the class from " +
+ "source, using an up-to-date compiler\n" +
+ "and without specifying any \"-target\" type " +
+ "options. The consequence of ignoring\n" +
+ "this warning is that reflective operations " +
+ "on this class will incorrectly\n" +
+ "indicate that it is *not* an inner class.");
}
result.add(AnnotationUtils.makeEnclosingClass(
foundThisClass.getOuterClass()));
@@ -341,9 +352,10 @@
* Gets the parameter annotations out of a given method. This
* combines both visible and invisible annotations into a single
* result set.
- *
+ *
* @param method {@code non-null;} the method in question
- * @return {@code non-null;} the list of annotation sets, which may be empty
+ * @return {@code non-null;} the list of annotation sets, which may be
+ * empty
*/
public static AnnotationsList getParameterAnnotations(Method method) {
AttributeList attribs = method.getAttributes();
@@ -377,7 +389,7 @@
* Gets the {@code AnnotationDefault} attributes out of a
* given class, if any, reforming them as an
* {@code AnnotationDefault} annotation.
- *
+ *
* @param cf {@code non-null;} the class in question
* @return {@code null-ok;} an appropriately-constructed
* {@code AnnotationDefault} annotation, if there were any
diff --git a/dx/src/com/android/dx/dex/cf/CfOptions.java b/dx/src/com/android/dx/dex/cf/CfOptions.java
index 8726223..468f0be 100644
--- a/dx/src/com/android/dx/dex/cf/CfOptions.java
+++ b/dx/src/com/android/dx/dex/cf/CfOptions.java
@@ -32,7 +32,7 @@
/** whether strict file-name-vs-class-name checking should be done */
public boolean strictNameCheck = true;
-
+
/** whether to do SSA/register optimization */
public boolean optimize = false;
diff --git a/dx/src/com/android/dx/dex/cf/CfTranslator.java b/dx/src/com/android/dx/dex/cf/CfTranslator.java
index 8210e90..1a9aa47 100644
--- a/dx/src/com/android/dx/dex/cf/CfTranslator.java
+++ b/dx/src/com/android/dx/dex/cf/CfTranslator.java
@@ -126,7 +126,7 @@
if (classAnnotations.size() != 0) {
out.setClassAnnotations(classAnnotations);
}
-
+
processFields(cf, out);
processMethods(cf, args, out);
@@ -162,7 +162,7 @@
out.addInstanceField(fi);
}
- Annotations annotations =
+ Annotations annotations =
AttributeTranslator.getAnnotations(one.getAttributes());
if (annotations.size() != 0) {
out.addFieldAnnotations(field, annotations);
@@ -178,7 +178,7 @@
/**
* Helper for {@link #processFields}, which translates constants into
* more specific types if necessary.
- *
+ *
* @param constant {@code non-null;} the constant in question
* @param type {@code non-null;} the desired type
*/
@@ -254,8 +254,8 @@
int paramSize;
paramSize = meth.getParameterWordCount(isStatic);
-
- String canonicalName
+
+ String canonicalName
= thisClass.getClassType().getDescriptor()
+ "." + one.getName().getString();
@@ -307,7 +307,7 @@
accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED;
}
}
-
+
if (isConstructor) {
accessFlags |= AccessFlags.ACC_CONSTRUCTOR;
}
@@ -323,13 +323,13 @@
out.addVirtualMethod(mi);
}
- Annotations annotations =
+ Annotations annotations =
AttributeTranslator.getMethodAnnotations(one);
if (annotations.size() != 0) {
out.addMethodAnnotations(meth, annotations);
}
- AnnotationsList list =
+ AnnotationsList list =
AttributeTranslator.getParameterAnnotations(one);
if (list.size() != 0) {
out.addParameterAnnotations(meth, list);
@@ -366,7 +366,7 @@
* for the current purpose.
*/
- DalvCode.AssignIndicesCallback callback =
+ DalvCode.AssignIndicesCallback callback =
new DalvCode.AssignIndicesCallback() {
public int getIndex(Constant cst) {
// Everything is at index 0!
diff --git a/dx/src/com/android/dx/dex/cf/CodeStatistics.java b/dx/src/com/android/dx/dex/cf/CodeStatistics.java
index b692d77..33d03fd 100644
--- a/dx/src/com/android/dx/dex/cf/CodeStatistics.java
+++ b/dx/src/com/android/dx/dex/cf/CodeStatistics.java
@@ -75,7 +75,7 @@
/**
* Updates the number of original bytecode bytes processed.
- *
+ *
* @param count {@code >= 0;} the number of bytes to add
*/
public static void updateOriginalByteCount(int count) {
@@ -84,7 +84,7 @@
/**
* Updates the dex statistics.
- *
+ *
* @param nonOptCode non-optimized code block
* @param code optimized code block
*/
@@ -145,7 +145,7 @@
/**
* Prints out the collected statistics.
- *
+ *
* @param out {@code non-null;} where to output to
*/
public static void dumpStatistics(PrintStream out) {
diff --git a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
index fa606e3..a66421e 100644
--- a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
+++ b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
@@ -56,7 +56,7 @@
/**
* Loads the optimize/don't optimize lists from files.
- *
+ *
* @param optimizeListFile Pathname
* @param dontOptimizeListFile Pathname
*/
@@ -89,7 +89,7 @@
/**
* Loads a list of newline-separated strings into a new HashSet and returns
* the HashSet.
- *
+ *
* @param filename filename to process
* @return set of all unique lines in the file
*/
diff --git a/dx/src/com/android/dx/dex/code/ArrayData.java b/dx/src/com/android/dx/dex/code/ArrayData.java
index 7698de1..145f2c2 100644
--- a/dx/src/com/android/dx/dex/code/ArrayData.java
+++ b/dx/src/com/android/dx/dex/code/ArrayData.java
@@ -25,12 +25,12 @@
import java.util.ArrayList;
/**
- * Pseudo-instruction which holds fill array data.
+ * Pseudo-instruction which holds fill array data.
*/
public final class ArrayData extends VariableSizeInsn {
/**
* {@code non-null;} address representing the instruction that uses this
- * instance
+ * instance
*/
private final CodeAddress user;
@@ -49,7 +49,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param user {@code non-null;} address representing the instruction that
* uses this instance
diff --git a/dx/src/com/android/dx/dex/code/BlockAddresses.java b/dx/src/com/android/dx/dex/code/BlockAddresses.java
index e55f893..1a1d184 100644
--- a/dx/src/com/android/dx/dex/code/BlockAddresses.java
+++ b/dx/src/com/android/dx/dex/code/BlockAddresses.java
@@ -59,7 +59,7 @@
/**
* Gets the instance for the start of the given block.
- *
+ *
* @param block {@code non-null;} the block in question
* @return {@code non-null;} the appropriate instance
*/
@@ -69,7 +69,7 @@
/**
* Gets the instance for the start of the block with the given label.
- *
+ *
* @param label {@code non-null;} the label of the block in question
* @return {@code non-null;} the appropriate instance
*/
@@ -79,7 +79,7 @@
/**
* Gets the instance for the final instruction of the given block.
- *
+ *
* @param block {@code non-null;} the block in question
* @return {@code non-null;} the appropriate instance
*/
@@ -90,7 +90,7 @@
/**
* Gets the instance for the final instruction of the block with
* the given label.
- *
+ *
* @param label {@code non-null;} the label of the block in question
* @return {@code non-null;} the appropriate instance
*/
@@ -101,7 +101,7 @@
/**
* Gets the instance for the end (address after the final instruction)
* of the given block.
- *
+ *
* @param block {@code non-null;} the block in question
* @return {@code non-null;} the appropriate instance
*/
@@ -112,7 +112,7 @@
/**
* Gets the instance for the end (address after the final instruction)
* of the block with the given label.
- *
+ *
* @param label {@code non-null;} the label of the block in question
* @return {@code non-null;} the appropriate instance
*/
diff --git a/dx/src/com/android/dx/dex/code/CatchBuilder.java b/dx/src/com/android/dx/dex/code/CatchBuilder.java
index d2ec3d7..90d2e8d 100644
--- a/dx/src/com/android/dx/dex/code/CatchBuilder.java
+++ b/dx/src/com/android/dx/dex/code/CatchBuilder.java
@@ -26,7 +26,7 @@
public interface CatchBuilder {
/**
* Builds and returns the catch table for this instance.
- *
+ *
* @return {@code non-null;} the constructed table
*/
public CatchTable build();
@@ -34,14 +34,14 @@
/**
* Gets whether this instance has any catches at all (either typed
* or catch-all).
- *
+ *
* @return whether this instance has any catches at all
*/
public boolean hasAnyCatches();
-
+
/**
* Gets the set of catch types associated with this instance.
- *
+ *
* @return {@code non-null;} the set of catch types
*/
public HashSet<Type> getCatchTypes();
diff --git a/dx/src/com/android/dx/dex/code/CatchHandlerList.java b/dx/src/com/android/dx/dex/code/CatchHandlerList.java
index a8a97be..8472584 100644
--- a/dx/src/com/android/dx/dex/code/CatchHandlerList.java
+++ b/dx/src/com/android/dx/dex/code/CatchHandlerList.java
@@ -57,7 +57,7 @@
/**
* Get the human form of this instance, prefixed on each line
* with the string.
- *
+ *
* @param prefix {@code non-null;} the prefix for every line
* @param header {@code non-null;} the header for the first line (after the
* first prefix)
@@ -85,7 +85,7 @@
} else {
sb.append(entry.getExceptionType().toHuman());
}
-
+
sb.append(" -> ");
sb.append(Hex.u2or4(entry.getHandler()));
}
@@ -96,7 +96,7 @@
/**
* Returns whether or not this instance ends with a "catch-all"
* handler.
- *
+ *
* @return {@code true} if this instance ends with a "catch-all"
* handler or {@code false} if not
*/
@@ -205,7 +205,7 @@
return false;
}
-
+
/** {@inheritDoc} */
public int compareTo(Entry other) {
if (handler < other.handler) {
@@ -216,10 +216,10 @@
return exceptionType.compareTo(other.exceptionType);
}
-
+
/**
* Gets the exception type handled.
- *
+ *
* @return {@code non-null;} the exception type
*/
public CstType getExceptionType() {
@@ -228,7 +228,7 @@
/**
* Gets the handler address.
- *
+ *
* @return {@code >= 0;} the handler address
*/
public int getHandler() {
diff --git a/dx/src/com/android/dx/dex/code/CatchTable.java b/dx/src/com/android/dx/dex/code/CatchTable.java
index fd8e3a7..0ee890f 100644
--- a/dx/src/com/android/dx/dex/code/CatchTable.java
+++ b/dx/src/com/android/dx/dex/code/CatchTable.java
@@ -105,7 +105,7 @@
/**
* Constructs an instance.
*
- * @param start {@code >= 0;} start address
+ * @param start {@code >= 0;} start address
* @param end {@code > start;} end address (exclusive)
* @param handlers {@code non-null;} list of catch handlers
*/
@@ -144,7 +144,7 @@
return false;
}
-
+
/** {@inheritDoc} */
public int compareTo(Entry other) {
if (start < other.start) {
@@ -152,7 +152,7 @@
} else if (start > other.start) {
return 1;
}
-
+
if (end < other.end) {
return -1;
} else if (end > other.end) {
@@ -161,10 +161,10 @@
return handlers.compareTo(other.handlers);
}
-
+
/**
* Gets the start address.
- *
+ *
* @return {@code >= 0;} the start address
*/
public int getStart() {
@@ -173,7 +173,7 @@
/**
* Gets the end address (exclusive).
- *
+ *
* @return {@code > start;} the end address (exclusive)
*/
public int getEnd() {
@@ -182,7 +182,7 @@
/**
* Gets the handlers.
- *
+ *
* @return {@code non-null;} the handlers
*/
public CatchHandlerList getHandlers() {
diff --git a/dx/src/com/android/dx/dex/code/CodeAddress.java b/dx/src/com/android/dx/dex/code/CodeAddress.java
index f25718e..5d26bd1 100644
--- a/dx/src/com/android/dx/dex/code/CodeAddress.java
+++ b/dx/src/com/android/dx/dex/code/CodeAddress.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
*/
public CodeAddress(SourcePosition position) {
diff --git a/dx/src/com/android/dx/dex/code/CstInsn.java b/dx/src/com/android/dx/dex/code/CstInsn.java
index a579c5e..3f848c0 100644
--- a/dx/src/com/android/dx/dex/code/CstInsn.java
+++ b/dx/src/com/android/dx/dex/code/CstInsn.java
@@ -30,20 +30,20 @@
/**
* {@code >= -1;} the constant pool index for {@link #constant}, or
- * {@code -1} if not yet set
+ * {@code -1} if not yet set
*/
private int index;
/**
* {@code >= -1;} the constant pool index for the class reference in
- * {@link #constant} if any, or {@code -1} if not yet set
+ * {@link #constant} if any, or {@code -1} if not yet set
*/
private int classIndex;
/**
* Constructs an instance. The output address of this instance is
* initially unknown ({@code -1}) as is the constant pool index.
- *
+ *
* @param opcode the opcode; one of the constants from {@link Dops}
* @param position {@code non-null;} source position
* @param registers {@code non-null;} register list, including a
@@ -67,13 +67,13 @@
/** {@inheritDoc} */
@Override
public DalvInsn withOpcode(Dop opcode) {
- CstInsn result =
+ CstInsn result =
new CstInsn(opcode, getPosition(), getRegisters(), constant);
if (index >= 0) {
result.setIndex(index);
}
-
+
if (classIndex >= 0) {
result.setClassIndex(classIndex);
}
@@ -90,7 +90,7 @@
if (index >= 0) {
result.setIndex(index);
}
-
+
if (classIndex >= 0) {
result.setClassIndex(classIndex);
}
@@ -100,7 +100,7 @@
/**
* Gets the constant argument.
- *
+ *
* @return {@code non-null;} the constant argument
*/
public Constant getConstant() {
@@ -110,7 +110,7 @@
/**
* Gets the constant's index. It is only valid to call this after
* {@link #setIndex} has been called.
- *
+ *
* @return {@code >= 0;} the constant pool index
*/
public int getIndex() {
@@ -123,9 +123,9 @@
/**
* Returns whether the constant's index has been set for this instance.
- *
+ *
* @see #setIndex
- *
+ *
* @return {@code true} iff the index has been set
*/
public boolean hasIndex() {
@@ -135,7 +135,7 @@
/**
* Sets the constant's index. It is only valid to call this method once
* per instance.
- *
+ *
* @param index {@code >= 0;} the constant pool index
*/
public void setIndex(int index) {
@@ -153,7 +153,7 @@
/**
* Gets the constant's class index. It is only valid to call this after
* {@link #setClassIndex} has been called.
- *
+ *
* @return {@code >= 0;} the constant's class's constant pool index
*/
public int getClassIndex() {
@@ -167,9 +167,9 @@
/**
* Returns whether the constant's class index has been set for this
* instance.
- *
+ *
* @see #setClassIndex
- *
+ *
* @return {@code true} iff the index has been set
*/
public boolean hasClassIndex() {
@@ -182,7 +182,7 @@
* reference constants have a class, so it is only on instances
* with reference constants that this method should ever be
* called. It is only valid to call this method once per instance.
- *
+ *
* @param index {@code >= 0;} the constant's class's constant pool index
*/
public void setClassIndex(int index) {
diff --git a/dx/src/com/android/dx/dex/code/DalvCode.java b/dx/src/com/android/dx/dex/code/DalvCode.java
index f911912..58f191b 100644
--- a/dx/src/com/android/dx/dex/code/DalvCode.java
+++ b/dx/src/com/android/dx/dex/code/DalvCode.java
@@ -28,7 +28,7 @@
public final class DalvCode {
/**
* how much position info to preserve; one of the static
- * constants in {@link PositionList}
+ * constants in {@link PositionList}
*/
private final int positionInfo;
@@ -46,13 +46,13 @@
/**
* {@code null-ok;} catch table; set in
- * {@link #finishProcessingIfNecessary}
+ * {@link #finishProcessingIfNecessary}
*/
private CatchTable catches;
/**
* {@code null-ok;} source positions list; set in
- * {@link #finishProcessingIfNecessary}
+ * {@link #finishProcessingIfNecessary}
*/
private PositionList positions;
@@ -119,16 +119,16 @@
* Assign indices in all instructions that need them, using the
* given callback to perform lookups. This must be called before
* {@link #getInsns}.
- *
+ *
* @param callback {@code non-null;} callback object
*/
public void assignIndices(AssignIndicesCallback callback) {
unprocessedInsns.assignIndices(callback);
}
-
+
/**
* Gets whether this instance has any position data to represent.
- *
+ *
* @return {@code true} iff this instance has any position
* data to represent
*/
@@ -136,10 +136,10 @@
return (positionInfo != PositionList.NONE)
&& unprocessedInsns.hasAnyPositionInfo();
}
-
+
/**
* Gets whether this instance has any local variable data to represent.
- *
+ *
* @return {@code true} iff this instance has any local variable
* data to represent
*/
@@ -150,16 +150,16 @@
/**
* Gets whether this instance has any catches at all (either typed
* or catch-all).
- *
+ *
* @return whether this instance has any catches at all
*/
public boolean hasAnyCatches() {
return unprocessedCatches.hasAnyCatches();
}
-
+
/**
* Gets the set of catch types handled anywhere in the code.
- *
+ *
* @return {@code non-null;} the set of catch types
*/
public HashSet<Type> getCatchTypes() {
@@ -169,7 +169,7 @@
/**
* Gets the set of all constants referred to by instructions in
* the code.
- *
+ *
* @return {@code non-null;} the set of constants
*/
public HashSet<Constant> getInsnConstants() {
@@ -178,7 +178,7 @@
/**
* Gets the list of instructions.
- *
+ *
* @return {@code non-null;} the instruction list
*/
public DalvInsnList getInsns() {
@@ -188,7 +188,7 @@
/**
* Gets the catch (exception handler) table.
- *
+ *
* @return {@code non-null;} the catch table
*/
public CatchTable getCatches() {
@@ -198,7 +198,7 @@
/**
* Gets the source positions list.
- *
+ *
* @return {@code non-null;} the source positions list
*/
public PositionList getPositions() {
@@ -208,7 +208,7 @@
/**
* Gets the source positions list.
- *
+ *
* @return {@code non-null;} the source positions list
*/
public LocalList getLocals() {
@@ -222,7 +222,7 @@
public static interface AssignIndicesCallback {
/**
* Gets the index for the given constant.
- *
+ *
* @param cst {@code non-null;} the constant
* @return {@code >= -1;} the index or {@code -1} if the constant
* shouldn't actually be reified with an index
diff --git a/dx/src/com/android/dx/dex/code/DalvInsn.java b/dx/src/com/android/dx/dex/code/DalvInsn.java
index 11ee55d..f203817 100644
--- a/dx/src/com/android/dx/dex/code/DalvInsn.java
+++ b/dx/src/com/android/dx/dex/code/DalvInsn.java
@@ -29,7 +29,7 @@
public abstract class DalvInsn {
/**
* the actual output address of this instance, if known, or
- * {@code -1} if not
+ * {@code -1} if not
*/
private int address;
@@ -44,7 +44,7 @@
/**
* Makes a move instruction, appropriate and ideal for the given arguments.
- *
+ *
* @param position {@code non-null;} source position information
* @param dest {@code non-null;} destination register
* @param src {@code non-null;} source register
@@ -76,13 +76,13 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* <p><b>Note:</b> In the unlikely event that an instruction takes
* absolutely no registers (e.g., a {@code nop} or a
* no-argument no-result static method call), then the given
* register list may be passed as {@link
* RegisterSpecList#EMPTY}.</p>
- *
+ *
* @param opcode the opcode; one of the constants from {@link Dops}
* @param position {@code non-null;} source position
* @param registers {@code non-null;} register list, including a
@@ -141,7 +141,7 @@
/**
* Gets whether the address of this instruction is known.
- *
+ *
* @see #getAddress
* @see #setAddress
*/
@@ -152,9 +152,9 @@
/**
* Gets the output address of this instruction, if it is known. This throws
* a {@code RuntimeException} if it has not yet been set.
- *
+ *
* @see #setAddress
- *
+ *
* @return {@code >= 0;} the output address
*/
public final int getAddress() {
@@ -167,7 +167,7 @@
/**
* Gets the opcode.
- *
+ *
* @return {@code non-null;} the opcode
*/
public final Dop getOpcode() {
@@ -176,7 +176,7 @@
/**
* Gets the source position.
- *
+ *
* @return {@code non-null;} the source position
*/
public final SourcePosition getPosition() {
@@ -185,7 +185,7 @@
/**
* Gets the register list for this instruction.
- *
+ *
* @return {@code non-null;} the registers
*/
public final RegisterSpecList getRegisters() {
@@ -196,7 +196,7 @@
* Returns whether this instance's opcode uses a result register.
* This method is a convenient shorthand for
* {@code getOpcode().hasResult()}.
- *
+ *
* @return {@code true} iff this opcode uses a result register
*/
public final boolean hasResult() {
@@ -209,7 +209,7 @@
* sources (if any), that each source register is unique, and that
* (to be explicit here) category-2 values take up two consecutive
* registers.
- *
+ *
* @return {@code >= 0;} the minimum distinct register requirement
*/
public final int getMinimumRegisterRequirement() {
@@ -228,9 +228,9 @@
/**
* Gets the instruction prefix required, if any, to use in a high
* register transformed version of this instance.
- *
+ *
* @see #hrVersion
- *
+ *
* @return {@code null-ok;} the prefix, if any
*/
public DalvInsn hrPrefix() {
@@ -252,9 +252,9 @@
/**
* Gets the instruction suffix required, if any, to use in a high
* register transformed version of this instance.
- *
+ *
* @see #hrVersion
- *
+ *
* @return {@code null-ok;} the suffix, if any
*/
public DalvInsn hrSuffix() {
@@ -276,11 +276,11 @@
* instance, and it is guaranteed that the number of low registers
* used will be the number returned by {@link
* #getMinimumRegisterRequirement}.
- *
+ *
* @return {@code non-null;} the replacement
*/
public DalvInsn hrVersion() {
- RegisterSpecList regs =
+ RegisterSpecList regs =
registers.withSequentialRegisters(0, hasResult());
return withRegisters(regs);
}
@@ -288,7 +288,7 @@
/**
* Gets the short identifier for this instruction. This is its
* address, if assigned, or its identity hashcode if not.
- *
+ *
* @return {@code non-null;} the identifier
*/
public final String identifierString() {
@@ -303,7 +303,7 @@
* Returns the string form of this instance suitable for inclusion in
* a human-oriented listing dump. This method will return {@code null}
* if this instance should not appear in a listing.
- *
+ *
* @param prefix {@code non-null;} prefix before the address; each follow-on
* line will be indented to match as well
* @param width {@code >= 0;} the width of the output or {@code 0} for
@@ -330,7 +330,7 @@
/**
* Sets the output address.
- *
+ *
* @param address {@code >= 0;} the output address
*/
public final void setAddress(int address) {
@@ -346,7 +346,7 @@
* calculable if this instance's address is known, and it is equal
* to the address plus the length of the instruction format of this
* instance's opcode.
- *
+ *
* @return {@code >= 0;} the next address
*/
public final int getNextAddress() {
@@ -355,7 +355,7 @@
/**
* Gets the size of this instruction, in 16-bit code units.
- *
+ *
* @return {@code >= 0;} the code size of this instruction
*/
public abstract int codeSize();
@@ -363,7 +363,7 @@
/**
* Writes this instance to the given output. This method should
* never annotate the output.
- *
+ *
* @param out {@code non-null;} where to write to
*/
public abstract void writeTo(AnnotatedOutput out);
@@ -371,7 +371,7 @@
/**
* Returns an instance that is just like this one, except that its
* opcode is replaced by the one given, and its address is reset.
- *
+ *
* @param opcode {@code non-null;} the new opcode
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -381,7 +381,7 @@
* Returns an instance that is just like this one, except that all
* register references have been offset by the given delta, and its
* address is reset.
- *
+ *
* @param delta the amount to offset register references by
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -391,7 +391,7 @@
* Returns an instance that is just like this one, except that the
* register list is replaced by the given one, and its address is
* reset.
- *
+ *
* @param registers {@code non-null;} new register list
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -400,7 +400,7 @@
/**
* Gets the string form for any arguments to this instance. Subclasses
* must override this.
- *
+ *
* @return {@code null-ok;} the string version of any arguments or
* {@code null} if there are none
*/
@@ -413,7 +413,7 @@
* address and without respect for any output formatting. This
* method should return {@code null} if this instance should
* not appear in a listing.
- *
+ *
* @param noteIndices whether to include an explicit notation of
* constant pool indices
* @return {@code null-ok;} the listing string
diff --git a/dx/src/com/android/dx/dex/code/DalvInsnList.java b/dx/src/com/android/dx/dex/code/DalvInsnList.java
index 5cf22f2..0f8c23d 100644
--- a/dx/src/com/android/dx/dex/code/DalvInsnList.java
+++ b/dx/src/com/android/dx/dex/code/DalvInsnList.java
@@ -45,7 +45,7 @@
/**
* Constructs and returns an immutable instance whose elements are
* identical to the ones in the given list, in the same order.
- *
+ *
* @param list {@code non-null;} the list to use for elements
* @param regCount count, in register-units, of the number of registers
* this code block requires.
@@ -64,10 +64,10 @@
result.setImmutable();
return result;
}
-
+
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public DalvInsnList(int size, int regCount) {
@@ -79,7 +79,7 @@
* Gets the element at the given index. It is an error to call
* this with the index for an element which was never set; if you
* do that, this will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @return {@code non-null;} element at that index
*/
@@ -89,7 +89,7 @@
/**
* Sets the instruction at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @param insn {@code non-null;} the instruction to set at {@code n}
*/
@@ -101,7 +101,7 @@
* Gets the size of this instance, in 16-bit code units. This will only
* return a meaningful result if the instructions in this instance all
* have valid addresses.
- *
+ *
* @return {@code >= 0;} the size
*/
public int codeSize() {
@@ -118,7 +118,7 @@
/**
* Writes all the instructions in this instance to the given output
* destination.
- *
+ *
* @param out {@code non-null;} where to write to
*/
public void writeTo(AnnotatedOutput out) {
@@ -127,7 +127,7 @@
if (out.annotates()) {
boolean verbose = out.isVerbose();
-
+
for (int i = 0; i < sz; i++) {
DalvInsn insn = (DalvInsn) get0(i);
int codeBytes = insn.codeSize() * 2;
@@ -180,7 +180,7 @@
* Gets the size of the outgoing arguments area required by this
* method. This is equal to the largest argument word count of any
* method referred to by this instance.
- *
+ *
* @return {@code >= 0;} the required outgoing arguments size
*/
public int getOutsSize() {
@@ -215,7 +215,7 @@
/**
* Does a human-friendly dump of this instance.
- *
+ *
* @param out {@code non-null;} where to dump
* @param prefix {@code non-null;} prefix to attach to each line of output
* @param verbose whether to be verbose; verbose output includes
@@ -249,7 +249,7 @@
/**
* Does a human-friendly dump of this instance.
- *
+ *
* @param out {@code non-null;} where to dump
* @param prefix {@code non-null;} prefix to attach to each line of output
* @param verbose whether to be verbose; verbose output includes
diff --git a/dx/src/com/android/dx/dex/code/Dop.java b/dx/src/com/android/dx/dex/code/Dop.java
index d1f92bf..2b2a08f 100644
--- a/dx/src/com/android/dx/dex/code/Dop.java
+++ b/dx/src/com/android/dx/dex/code/Dop.java
@@ -37,7 +37,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode
* value itself
* @param family {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
@@ -79,7 +79,7 @@
/**
* Gets the opcode value.
- *
+ *
* @return {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode value
*/
public int getOpcode() {
@@ -89,7 +89,7 @@
/**
* Gets the opcode family. The opcode family is the unmarked (no
* "/...") opcode that has equivalent semantics to this one.
- *
+ *
* @return {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
*/
public int getFamily() {
@@ -98,7 +98,7 @@
/**
* Gets the instruction format.
- *
+ *
* @return {@code non-null;} the instruction format
*/
public InsnFormat getFormat() {
@@ -107,7 +107,7 @@
/**
* Returns whether this opcode uses a result register.
- *
+ *
* @return {@code true} iff this opcode uses a result register
*/
public boolean hasResult() {
@@ -116,7 +116,7 @@
/**
* Gets the opcode name.
- *
+ *
* @return {@code non-null;} the opcode name
*/
public String getName() {
@@ -126,7 +126,7 @@
/**
* Gets the opcode for the opposite test of this instance. This is only
* valid for opcodes which are in fact tests.
- *
+ *
* @return {@code non-null;} the opposite test
*/
public Dop getOppositeTest() {
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index dfdaa73..0211a40 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -51,9 +51,9 @@
private static final Dop[] DOPS;
/**
- * pseudo-opcode used for nonstandard formatted "instructions"
+ * pseudo-opcode used for nonstandard formatted "instructions"
* (which are mostly not actually instructions, though they do
- * appear in instruction lists)
+ * appear in instruction lists)
*/
public static final Dop SPECIAL_FORMAT =
new Dop(DalvOps.SPECIAL_FORMAT, DalvOps.SPECIAL_FORMAT,
@@ -1171,7 +1171,7 @@
/**
* Gets the {@link Dop} for the given opcode value.
- *
+ *
* @param opcode {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode value
* @return {@code non-null;} the associated opcode instance
*/
@@ -1193,7 +1193,7 @@
/**
* Gets the {@link Dop} with the given family/format combination, if
* any.
- *
+ *
* @param family {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
* @param format {@code non-null;} the opcode's instruction format
* @return {@code null-ok;} the corresponding opcode, or {@code null} if
@@ -1221,7 +1221,7 @@
/**
* Puts the given opcode into the table of all ops.
- *
+ *
* @param opcode {@code non-null;} the opcode
*/
private static void set(Dop opcode) {
diff --git a/dx/src/com/android/dx/dex/code/FixedSizeInsn.java b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
index 147937f..faed530 100644
--- a/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
+++ b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
@@ -29,13 +29,13 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* <p><b>Note:</b> In the unlikely event that an instruction takes
* absolutely no registers (e.g., a {@code nop} or a
* no-argument no-result * static method call), then the given
* register list may be passed as {@link
* RegisterSpecList#EMPTY}.</p>
- *
+ *
* @param opcode the opcode; one of the constants from {@link Dops}
* @param position {@code non-null;} source position
* @param registers {@code non-null;} register list, including a
diff --git a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
index 9155367..6fab094 100644
--- a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
+++ b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
@@ -32,11 +32,11 @@
public final class HighRegisterPrefix extends VariableSizeInsn {
/** {@code null-ok;} cached instructions, if constructed */
private SimpleInsn[] insns;
-
+
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param registers {@code non-null;} source registers
*/
@@ -83,12 +83,12 @@
if (insns != null) {
return;
}
-
+
RegisterSpecList registers = getRegisters();
int sz = registers.size();
insns = new SimpleInsn[sz];
-
+
for (int i = 0, outAt = 0; i < sz; i++) {
RegisterSpec src = registers.get(i);
insns[i] = moveInsnFor(src, outAt);
@@ -122,7 +122,7 @@
if (i != 0) {
sb.append('\n');
}
-
+
sb.append(insn.listingString0(noteIndices));
outAt += src.getCategory();
diff --git a/dx/src/com/android/dx/dex/code/InsnFormat.java b/dx/src/com/android/dx/dex/code/InsnFormat.java
index ca6688b..17c127f 100644
--- a/dx/src/com/android/dx/dex/code/InsnFormat.java
+++ b/dx/src/com/android/dx/dex/code/InsnFormat.java
@@ -290,7 +290,7 @@
if (! ci.hasIndex()) {
return "";
}
-
+
StringBuilder sb = new StringBuilder(20);
int index = ci.getIndex();
@@ -302,7 +302,7 @@
} else {
sb.append(Hex.u4(index));
}
-
+
return sb.toString();
}
@@ -484,7 +484,7 @@
/**
* Writes one code unit to the given output destination.
- *
+ *
* @param out {@code non-null;} where to write to
* @param c0 code unit to write
*/
@@ -494,7 +494,7 @@
/**
* Writes two code units to the given output destination.
- *
+ *
* @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
@@ -506,7 +506,7 @@
/**
* Writes three code units to the given output destination.
- *
+ *
* @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
@@ -521,7 +521,7 @@
/**
* Writes four code units to the given output destination.
- *
+ *
* @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
@@ -538,7 +538,7 @@
/**
* Writes five code units to the given output destination.
- *
+ *
* @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
@@ -557,7 +557,7 @@
/**
* Writes six code units to the given output destination.
- *
+ *
* @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
diff --git a/dx/src/com/android/dx/dex/code/LocalEnd.java b/dx/src/com/android/dx/dex/code/LocalEnd.java
index 360a55c..1c2bf89 100644
--- a/dx/src/com/android/dx/dex/code/LocalEnd.java
+++ b/dx/src/com/android/dx/dex/code/LocalEnd.java
@@ -39,7 +39,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param local {@code non-null;} register spec representing the local
* variable introduced by this instance
@@ -69,7 +69,7 @@
/**
* Gets the register spec representing the local variable ended
* by this instance.
- *
+ *
* @return {@code non-null;} the register spec
*/
public RegisterSpec getLocal() {
diff --git a/dx/src/com/android/dx/dex/code/LocalSnapshot.java b/dx/src/com/android/dx/dex/code/LocalSnapshot.java
index 409ad15..baeab4c 100644
--- a/dx/src/com/android/dx/dex/code/LocalSnapshot.java
+++ b/dx/src/com/android/dx/dex/code/LocalSnapshot.java
@@ -33,7 +33,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param locals {@code non-null;} associated local variable state
*/
@@ -61,7 +61,7 @@
/**
* Gets the local state associated with this instance.
- *
+ *
* @return {@code non-null;} the state
*/
public RegisterSpecSet getLocals() {
diff --git a/dx/src/com/android/dx/dex/code/LocalStart.java b/dx/src/com/android/dx/dex/code/LocalStart.java
index ec70e30..9a17c5b 100644
--- a/dx/src/com/android/dx/dex/code/LocalStart.java
+++ b/dx/src/com/android/dx/dex/code/LocalStart.java
@@ -29,13 +29,13 @@
public final class LocalStart extends ZeroSizeInsn {
/**
* {@code non-null;} register spec representing the local variable introduced
- * by this instance
+ * by this instance
*/
private final RegisterSpec local;
/**
* Returns the local variable listing string for a single register spec.
- *
+ *
* @param spec {@code non-null;} the spec to convert
* @return {@code non-null;} the string form
*/
@@ -47,7 +47,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param local {@code non-null;} register spec representing the local
* variable introduced by this instance
@@ -77,7 +77,7 @@
/**
* Gets the register spec representing the local variable introduced
* by this instance.
- *
+ *
* @return {@code non-null;} the register spec
*/
public RegisterSpec getLocal() {
diff --git a/dx/src/com/android/dx/dex/code/OddSpacer.java b/dx/src/com/android/dx/dex/code/OddSpacer.java
index 727def0..756a0e2 100644
--- a/dx/src/com/android/dx/dex/code/OddSpacer.java
+++ b/dx/src/com/android/dx/dex/code/OddSpacer.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
*/
public OddSpacer(SourcePosition position) {
diff --git a/dx/src/com/android/dx/dex/code/OutputCollector.java b/dx/src/com/android/dx/dex/code/OutputCollector.java
index 2643373..d78e5fc 100644
--- a/dx/src/com/android/dx/dex/code/OutputCollector.java
+++ b/dx/src/com/android/dx/dex/code/OutputCollector.java
@@ -41,7 +41,7 @@
/**
* Constructs an instance.
- *
+ *
* @param initialCapacity {@code >= 0;} initial capacity of the output list
* @param suffixInitialCapacity {@code >= 0;} initial capacity of the output
* suffix
@@ -55,8 +55,8 @@
/**
* Adds an instruction to the output.
- *
- * @param insn {@code non-null;} the instruction to add
+ *
+ * @param insn {@code non-null;} the instruction to add
*/
public void add(DalvInsn insn) {
finisher.add(insn);
@@ -66,7 +66,7 @@
* Reverses a branch which is buried a given number of instructions
* backward in the output. It is illegal to call this unless the
* indicated instruction really is a reversible branch.
- *
+ *
* @param which how many instructions back to find the branch;
* {@code 0} is the most recently added instruction,
* {@code 1} is the instruction before that, etc.
@@ -78,8 +78,8 @@
/**
* Adds an instruction to the output suffix.
- *
- * @param insn {@code non-null;} the instruction to add
+ *
+ * @param insn {@code non-null;} the instruction to add
*/
public void addSuffix(DalvInsn insn) {
suffix.add(insn);
@@ -97,7 +97,7 @@
if (suffix == null) {
throw new UnsupportedOperationException("already processed");
}
-
+
appendSuffixToOutput();
return finisher;
}
diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java
index 5b1d533..4a51198 100644
--- a/dx/src/com/android/dx/dex/code/OutputFinisher.java
+++ b/dx/src/com/android/dx/dex/code/OutputFinisher.java
@@ -61,7 +61,7 @@
/**
* Constructs an instance. It initially contains no instructions.
- *
+ *
* @param regCount {@code >= 0;} register count for the method
* @param initialCapacity {@code >= 0;} initial capacity of the instructions
* list
@@ -77,17 +77,17 @@
/**
* Returns whether any of the instructions added to this instance
* come with position info.
- *
+ *
* @return whether any of the instructions added to this instance
* come with position info
*/
public boolean hasAnyPositionInfo() {
return hasAnyPositionInfo;
}
-
+
/**
* Returns whether this instance has any local variable information.
- *
+ *
* @return whether this instance has any local variable information
*/
public boolean hasAnyLocalInfo() {
@@ -97,7 +97,7 @@
/**
* Helper for {@link #add} which scrutinizes a single
* instruction for local variable information.
- *
+ *
* @param insn {@code non-null;} instruction to scrutinize
* @return {@code true} iff the instruction refers to any
* named locals
@@ -124,7 +124,7 @@
/**
* Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
* register spec.
- *
+ *
* @param spec {@code non-null;} spec to scrutinize
* @return {@code true} iff the spec refers to any
* named locals
@@ -137,7 +137,7 @@
/**
* Returns the set of all constants referred to by instructions added
* to this instance.
- *
+ *
* @return {@code non-null;} the set of constants
*/
public HashSet<Constant> getAllConstants() {
@@ -153,7 +153,7 @@
/**
* Helper for {@link #getAllConstants} which adds all the info for
* a single instruction.
- *
+ *
* @param result {@code non-null;} result set to add to
* @param insn {@code non-null;} instruction to scrutinize
*/
@@ -186,7 +186,7 @@
if (spec == null) {
return;
}
-
+
LocalItem local = spec.getLocalItem();
CstUtf8 name = local.getName();
CstUtf8 signature = local.getSignature();
@@ -207,8 +207,8 @@
/**
* Adds an instruction to the output.
- *
- * @param insn {@code non-null;} the instruction to add
+ *
+ * @param insn {@code non-null;} the instruction to add
*/
public void add(DalvInsn insn) {
insns.add(insn);
@@ -217,7 +217,7 @@
/**
* Inserts an instruction in the output at the given offset.
- *
+ *
* @param at {@code >= 0;} what index to insert at
* @param insn {@code non-null;} the instruction to insert
*/
@@ -229,7 +229,7 @@
/**
* Helper for {@link #add} and {@link #insert},
* which updates the position and local info flags.
- *
+ *
* @param insn {@code non-null;} an instruction that was just introduced
*/
private void updateInfo(DalvInsn insn) {
@@ -251,7 +251,7 @@
* Reverses a branch which is buried a given number of instructions
* backward in the output. It is illegal to call this unless the
* indicated instruction really is a reversible branch.
- *
+ *
* @param which how many instructions back to find the branch;
* {@code 0} is the most recently added instruction,
* {@code 1} is the instruction before that, etc.
@@ -283,7 +283,7 @@
* Assigns indices in all instructions that need them, using the
* given callback to perform lookups. This should be called before
* calling {@link #finishProcessingAndGetList}.
- *
+ *
* @param callback {@code non-null;} callback object
*/
public void assignIndices(DalvCode.AssignIndicesCallback callback) {
@@ -297,7 +297,7 @@
/**
* Helper for {@link #assignIndices} which does assignment for one
* instruction.
- *
+ *
* @param insn {@code non-null;} the instruction
* @param callback {@code non-null;} the callback
*/
@@ -323,7 +323,7 @@
/**
* Does final processing on this instance and gets the output as
* a {@link DalvInsnList}. Final processing consists of:
- *
+ *
* <ul>
* <li>optionally renumbering registers (to make room as needed for
* expanded instructions)</li>
@@ -332,7 +332,7 @@
* constant pool index, or branch target size issues</li>
* <li>assigning final addresses</li>
* </ul>
- *
+ *
* <p><b>Note:</b> This method may only be called once per instance
* of this class.</p>
*
@@ -358,7 +358,7 @@
* Helper for {@link #finishProcessingAndGetList}, which extracts
* the format out of each instruction into a separate array, to be
* further manipulated as things progress.
- *
+ *
* @return {@code non-null;} the array of formats
*/
private InsnFormat[] makeFormatsArray() {
@@ -378,12 +378,12 @@
* them. It also updates the given {@code formats} array so
* as to avoid extra work when constructing the massaged
* instruction list.
- *
+ *
* @param formats {@code non-null;} array of per-instruction format selections
*/
private void reserveRegisters(InsnFormat[] formats) {
int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
-
+
/*
* Call calculateReservedCount() and then perform register
* reservation, repeatedly until no new reservations happen.
@@ -410,7 +410,7 @@
/*
* No need to call this.set() since the format and
* other info are the same.
- */
+ */
insns.set(i, insn.withRegisterOffset(reservedDifference));
}
}
@@ -427,7 +427,7 @@
* registers that need to be reserved. It also updates the
* {@code formats} list to help avoid extra work in future
* register reservation passes.
- *
+ *
* @param formats {@code non-null;} array of per-instruction format selections
* @return {@code >= 0;} the count of reserved registers
*/
@@ -450,7 +450,7 @@
if (originalFormat == newFormat) {
continue;
}
-
+
if (newFormat == null) {
/*
* The instruction will need to be expanded, so reserve
@@ -499,7 +499,7 @@
for (;;) {
format = format.nextUp();
if ((format == null) ||
- (format.isCompatible(insn) &&
+ (format.isCompatible(insn) &&
(Dops.getOrNull(family, format) != null))) {
break;
}
@@ -507,14 +507,14 @@
return format;
}
-
+
/**
* Helper for {@link #finishProcessingAndGetList}, which goes
* through each instruction in the output, making sure its opcode
* can accomodate its arguments. In cases where the opcode is
* unable to do so, this replaces the instruction with a larger
* instruction with identical semantics that <i>will</i> work.
- *
+ *
* <p>This method may also reserve a number of low-numbered
* registers, renumbering the instructions' original registers, in
* order to have register space available in which to move
@@ -522,11 +522,11 @@
* multi-instruction sequences. This expansion is done when no
* simple instruction format can be found for a given instruction that
* is able to accomodate that instruction's registers.</p>
- *
+ *
* <p>This method ignores issues of branch target size, since
* final addresses aren't known at the point that this method is
* called.</p>
- *
+ *
* @param formats {@code non-null;} array of per-instruction format selections
*/
private void massageInstructions(InsnFormat[] formats) {
@@ -565,7 +565,7 @@
* couldn't be represented simply (due to register representation
* problems) is expanded into a series of instances that together
* perform the proper function.
- *
+ *
* @param formats {@code non-null;} array of per-instruction format selections
* @return {@code non-null;} the replacement list
*/
@@ -602,7 +602,7 @@
if (prefix != null) {
result.add(prefix);
}
-
+
if (currentFormat != originalFormat) {
dop = Dops.getOrNull(dop.getFamily(), currentFormat);
insn = insn.withOpcode(dop);
@@ -613,7 +613,7 @@
result.add(suffix);
}
}
-
+
return result;
}
@@ -655,7 +655,7 @@
* case of a conditional branch that doesn't fit, the sense of the
* test is reversed in order to branch around a {@code goto}
* to the original target.
- *
+ *
* @return whether any branches had to be fixed
*/
private boolean fixBranches() {
@@ -696,13 +696,13 @@
* It is a conditional: Reverse its sense, and arrange for
* it to branch around an absolute goto to the original
* branch target.
- *
+ *
* Note: An invariant of the list being processed is
* that every TargetInsn is followed by a CodeAddress.
* Hence, it is always safe to get the next element
* after a TargetInsn and cast it to CodeAddress, as
* is happening a few lines down.
- *
+ *
* Also note: Size gets incremented by one here, as we
* have -- in the net -- added one additional element
* to the list, so we increment i to match. The added
diff --git a/dx/src/com/android/dx/dex/code/PositionList.java b/dx/src/com/android/dx/dex/code/PositionList.java
index 41e3667..1e07e46 100644
--- a/dx/src/com/android/dx/dex/code/PositionList.java
+++ b/dx/src/com/android/dx/dex/code/PositionList.java
@@ -29,27 +29,27 @@
/**
* constant for {@link #make} to indicate that no actual position
- * information should be returned
+ * information should be returned
*/
public static final int NONE = 1;
/**
* constant for {@link #make} to indicate that only line number
- * transitions should be returned
+ * transitions should be returned
*/
public static final int LINES = 2;
/**
* constant for {@link #make} to indicate that only "important" position
* information should be returned. This includes block starts and
- * instructions that might throw.
+ * instructions that might throw.
*/
public static final int IMPORTANT = 3;
/**
* Extracts and returns the source position information out of an
* instruction list.
- *
+ *
* @param insns {@code non-null;} instructions to convert
* @param howMuch how much information should be included; one of the
* static constants defined by this class
@@ -113,7 +113,7 @@
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size {@code >= 0;} the size of the list
*/
public PositionList(int size) {
@@ -124,7 +124,7 @@
* Gets the element at the given index. It is an error to call
* this with the index for an element which was never set; if you
* do that, this will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @return {@code non-null;} element at that index
*/
@@ -134,7 +134,7 @@
/**
* Sets the entry at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @param entry {@code non-null;} the entry to set at {@code n}
*/
@@ -154,7 +154,7 @@
/**
* Constructs an instance.
- *
+ *
* @param address {@code >= 0;} address of this entry
* @param position {@code non-null;} corresponding source position information
*/
@@ -173,7 +173,7 @@
/**
* Gets the address.
- *
+ *
* @return {@code >= 0;} the address
*/
public int getAddress() {
@@ -182,7 +182,7 @@
/**
* Gets the source position information.
- *
+ *
* @return {@code non-null;} the position information
*/
public SourcePosition getPosition() {
diff --git a/dx/src/com/android/dx/dex/code/RopToDop.java b/dx/src/com/android/dx/dex/code/RopToDop.java
index 0385467..d8fa1cc 100644
--- a/dx/src/com/android/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -277,7 +277,7 @@
/**
* Returns the dalvik opcode appropriate for the given register-based
* instruction.
- *
+ *
* @param insn {@code non-null;} the original instruction
* @return the corresponding dalvik opcode; one of the constants in
* {@link Dops}
@@ -297,16 +297,16 @@
/*
* There was no easy case for the rop, so look up the opcode, and
* do something special for each:
- *
+ *
* The move_exception, new_array, filled_new_array, and
* invoke* opcodes won't be found in MAP, since they'll each
* have different source and/or result register types / lists.
- *
+ *
* The get* and put* opcodes for (non-long) integral types
* aren't in the map, since the type signatures aren't
* sufficient to distinguish between the types (the salient
* source or result will always be just "int").
- *
+ *
* And const instruction need to distinguish between strings and
* classes.
*/
@@ -320,7 +320,7 @@
case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
case RegOps.NEW_ARRAY: return Dops.NEW_ARRAY;
case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
- case RegOps.FILL_ARRAY_DATA: return Dops.FILL_ARRAY_DATA;
+ case RegOps.FILL_ARRAY_DATA: return Dops.FILL_ARRAY_DATA;
case RegOps.MOVE_RESULT: {
RegisterSpec resultReg = insn.getResult();
diff --git a/dx/src/com/android/dx/dex/code/RopTranslator.java b/dx/src/com/android/dx/dex/code/RopTranslator.java
index 9f47b13..a38ea11 100644
--- a/dx/src/com/android/dx/dex/code/RopTranslator.java
+++ b/dx/src/com/android/dx/dex/code/RopTranslator.java
@@ -51,7 +51,7 @@
/**
* how much position info to preserve; one of the static
- * constants in {@link PositionList}
+ * constants in {@link PositionList}
*/
private final int positionInfo;
@@ -85,7 +85,7 @@
/**
* Translates a {@link RopMethod}. This may modify the given
* input.
- *
+ *
* @param method {@code non-null;} the original method
* @param positionInfo how much position info to preserve; one of the
* static constants in {@link PositionList}
@@ -104,7 +104,7 @@
/**
* Constructs an instance. This method is private. Use {@link #translate}.
- *
+ *
* @param method {@code non-null;} the original method
* @param positionInfo how much position info to preserve; one of the
* static constants in {@link PositionList}
@@ -166,7 +166,7 @@
* stack frame that matches dalvik's calling conventions. This will
* alway result in "true" for methods that have run through the
* SSA optimizer.
- *
+ *
* @param paramSize size, in register units, of all the parameters
* to this method
*/
@@ -198,7 +198,7 @@
/**
* Does the translation and returns the result.
- *
+ *
* @return {@code non-null;} the result
*/
private DalvCode translateAndGetResult() {
@@ -231,7 +231,7 @@
/**
* Helper for {@link #outputInstructions}, which does the processing
* and output of one block.
- *
+ *
* @param block {@code non-null;} the block to process and output
* @param nextLabel {@code >= -1;} the next block that will be processed, or
* {@code -1} if there is no next block
@@ -258,7 +258,7 @@
// Insert the block end code address.
output.add(addresses.getEnd(block));
- // Set up for end-of-block activities.
+ // Set up for end-of-block activities.
int succ = block.getPrimarySuccessor();
Insn lastInsn = block.getLastInsn();
@@ -391,7 +391,7 @@
if (preferredBlock == null) {
break;
}
-
+
int preferred = preferredBlock.getLabel();
int primary = one.getPrimarySuccessor();
@@ -424,7 +424,7 @@
}
}
}
- }
+ }
if (at != sz) {
// There was a duplicate block label.
@@ -494,13 +494,13 @@
/**
* {@code null-ok;} code address for the salient last instruction of the
- * block (used before switches and throwing instructions)
+ * block (used before switches and throwing instructions)
*/
private CodeAddress lastAddress;
/**
* Constructs an instance.
- *
+ *
* @param output {@code non-null;} destination for instruction output
*/
public TranslationVisitor(OutputCollector output) {
@@ -509,7 +509,7 @@
/**
* Sets the block currently being worked on.
- *
+ *
* @param block {@code non-null;} the block
* @param lastAddress {@code non-null;} code address for the salient
* last instruction of the block
@@ -672,7 +672,7 @@
return null;
} else {
return insn.getResult();
- }
+ }
}
/** {@inheritDoc} */
@@ -707,7 +707,7 @@
"Insn with result/move-result-pseudo mismatch " +
insn);
}
-
+
if ((rop.getOpcode() == RegOps.NEW_ARRAY) &&
(opcode.getOpcode() != DalvOps.NEW_ARRAY)) {
/*
@@ -745,7 +745,7 @@
throw new RuntimeException(
"Insn with result/move-result-pseudo mismatch" + insn);
}
-
+
addOutput(lastAddress);
DalvInsn di = new SimpleInsn(opcode, pos,
@@ -767,7 +767,7 @@
CodeAddress dataAddress = new CodeAddress(pos);
ArrayData dataInsn =
new ArrayData(pos, lastAddress, values, cst);
-
+
TargetInsn fillArrayDataInsn =
new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn),
dataAddress);
@@ -779,10 +779,10 @@
addOutputSuffix(dataAddress);
addOutputSuffix(dataInsn);
}
-
+
/**
* Adds to the output.
- *
+ *
* @param insn {@code non-null;} instruction to add
*/
protected void addOutput(DalvInsn insn) {
@@ -791,7 +791,7 @@
/**
* Adds to the output suffix.
- *
+ *
* @param insn {@code non-null;} instruction to add
*/
protected void addOutputSuffix(DalvInsn insn) {
@@ -810,7 +810,7 @@
/**
* Constructs an instance.
- *
+ *
* @param output {@code non-null;} destination for instruction output
* @param locals {@code non-null;} the local variable info
*/
@@ -858,7 +858,7 @@
/**
* Adds a {@link LocalStart} to the output if the given
* instruction in fact introduces a local variable.
- *
+ *
* @param insn {@code non-null;} instruction in question
*/
public void addIntroductionIfNecessary(Insn insn) {
@@ -868,5 +868,5 @@
addOutput(new LocalStart(insn.getPosition(), spec));
}
}
- }
+ }
}
diff --git a/dx/src/com/android/dx/dex/code/SimpleInsn.java b/dx/src/com/android/dx/dex/code/SimpleInsn.java
index 5e7b259..8cdcc55 100644
--- a/dx/src/com/android/dx/dex/code/SimpleInsn.java
+++ b/dx/src/com/android/dx/dex/code/SimpleInsn.java
@@ -27,7 +27,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param opcode the opcode; one of the constants from {@link Dops}
* @param position {@code non-null;} source position
* @param registers {@code non-null;} register list, including a
diff --git a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
index 6e3a169..1e7612e 100644
--- a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
+++ b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
@@ -34,7 +34,7 @@
public final class StdCatchBuilder implements CatchBuilder {
/** the maximum range of a single catch handler, in code units */
private static final int MAX_CATCH_RANGE = 65535;
-
+
/** {@code non-null;} method to build the list for */
private final RopMethod method;
@@ -43,11 +43,11 @@
/** {@code non-null;} address objects for each block */
private final BlockAddresses addresses;
-
+
/**
* Constructs an instance. It merely holds onto its parameters for
* a subsequent call to {@link #build}.
- *
+ *
* @param method {@code non-null;} method to build the list for
* @param order {@code non-null;} block output order
* @param addresses {@code non-null;} address objects for each block
@@ -80,7 +80,7 @@
public boolean hasAnyCatches() {
BasicBlockList blocks = method.getBlocks();
int size = blocks.size();
-
+
for (int i = 0; i < size; i++) {
BasicBlock block = blocks.get(i);
TypeList catches = block.getLastInsn().getCatches();
@@ -91,13 +91,13 @@
return false;
}
-
+
/** {@inheritDoc} */
public HashSet<Type> getCatchTypes() {
HashSet<Type> result = new HashSet<Type>(20);
BasicBlockList blocks = method.getBlocks();
int size = blocks.size();
-
+
for (int i = 0; i < size; i++) {
BasicBlock block = blocks.get(i);
TypeList catches = block.getLastInsn().getCatches();
@@ -113,7 +113,7 @@
/**
* Builds and returns the catch table for a given method.
- *
+ *
* @param method {@code non-null;} method to build the list for
* @param order {@code non-null;} block output order
* @param addresses {@code non-null;} address objects for each block
@@ -128,7 +128,7 @@
CatchHandlerList currentHandlers = CatchHandlerList.EMPTY;
BasicBlock currentStartBlock = null;
BasicBlock currentEndBlock = null;
-
+
for (int i = 0; i < len; i++) {
BasicBlock block = blocks.labelToBlock(order[i]);
@@ -187,11 +187,11 @@
currentHandlers, addresses);
resultList.add(entry);
}
-
+
// Construct the final result.
int resultSz = resultList.size();
-
+
if (resultSz == 0) {
return CatchTable.EMPTY;
}
@@ -208,7 +208,7 @@
/**
* Makes the {@link CatchHandlerList} for the given basic block.
- *
+ *
* @param block {@code non-null;} block to get entries for
* @param addresses {@code non-null;} address objects for each block
* @return {@code non-null;} array of entries
@@ -249,7 +249,7 @@
break;
}
}
-
+
CatchHandlerList result = new CatchHandlerList(catchSize);
for (int i = 0; i < catchSize; i++) {
@@ -291,7 +291,7 @@
* Gets whether the address range for the given two blocks is valid
* for a catch handler. This is true as long as the covered range is
* under 65536 code units.
- *
+ *
* @param start {@code non-null;} the start block for the range (inclusive)
* @param end {@code non-null;} the start block for the range (also inclusive)
* @param addresses {@code non-null;} address objects for each block
@@ -306,7 +306,7 @@
if (end == null) {
throw new NullPointerException("end == null");
}
-
+
// See above about selection of instructions.
int startAddress = addresses.getLast(start).getAddress();
int endAddress = addresses.getEnd(end).getAddress();
diff --git a/dx/src/com/android/dx/dex/code/SwitchData.java b/dx/src/com/android/dx/dex/code/SwitchData.java
index e5a8da4..27a6342 100644
--- a/dx/src/com/android/dx/dex/code/SwitchData.java
+++ b/dx/src/com/android/dx/dex/code/SwitchData.java
@@ -30,7 +30,7 @@
public final class SwitchData extends VariableSizeInsn {
/**
* {@code non-null;} address representing the instruction that uses this
- * instance
+ * instance
*/
private final CodeAddress user;
@@ -39,7 +39,7 @@
/**
* {@code non-null;} corresponding list of code addresses; the branch
- * target for each case
+ * target for each case
*/
private final CodeAddress[] targets;
@@ -49,7 +49,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param user {@code non-null;} address representing the instruction that
* uses this instance
@@ -150,7 +150,7 @@
/**
* Returns whether or not this instance's data will be output as packed.
- *
+ *
* @return {@code true} iff the data is to be packed
*/
public boolean isPacked() {
@@ -201,7 +201,7 @@
/**
* Gets the size of a packed table for the given cases, in 16-bit code
* units.
- *
+ *
* @param cases {@code non-null;} sorted list of cases
* @return {@code >= -1;} the packed table size or {@code -1} if the
* cases couldn't possibly be represented as a packed table
@@ -218,7 +218,7 @@
/**
* Gets the size of a sparse table for the given cases, in 16-bit code
* units.
- *
+ *
* @param cases {@code non-null;} sorted list of cases
* @return {@code > 0;} the sparse table size
*/
@@ -230,7 +230,7 @@
/**
* Determines whether the given list of cases warrant being packed.
- *
+ *
* @param cases {@code non-null;} sorted list of cases
* @return {@code true} iff the table encoding the cases
* should be packed
diff --git a/dx/src/com/android/dx/dex/code/TargetInsn.java b/dx/src/com/android/dx/dex/code/TargetInsn.java
index 0faaada..cbb5ff9 100644
--- a/dx/src/com/android/dx/dex/code/TargetInsn.java
+++ b/dx/src/com/android/dx/dex/code/TargetInsn.java
@@ -30,7 +30,7 @@
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}), and the target is initially
* {@code null}.
- *
+ *
* @param opcode the opcode; one of the constants from {@link Dops}
* @param position {@code non-null;} source position
* @param registers {@code non-null;} register list, including a
@@ -67,7 +67,7 @@
* {@code lt} test becomes a {@code ge}), and its branch
* target is replaced by the one given, and all set-once values
* associated with the class (such as its address) are reset.
- *
+ *
* @param target {@code non-null;} the new branch target
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -79,7 +79,7 @@
/**
* Gets the unique branch target of this instruction.
- *
+ *
* @return {@code non-null;} the branch target
*/
public CodeAddress getTarget() {
@@ -91,7 +91,7 @@
* to call if the target instruction has been assigned an address,
* and it is merely a convenient shorthand for
* {@code getTarget().getAddress()}.
- *
+ *
* @return {@code >= 0;} the target address
*/
public int getTargetAddress() {
@@ -103,7 +103,7 @@
* call if both this and the target instruction each has been assigned
* an address, and it is merely a convenient shorthand for
* {@code getTargetAddress() - getAddress()}.
- *
+ *
* @return the branch offset
*/
public int getTargetOffset() {
@@ -112,7 +112,7 @@
/**
* Returns whether the target offset is known.
- *
+ *
* @return {@code true} if the target offset is known or
* {@code false} if not
*/
diff --git a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
index 889a50c..06b40f7 100644
--- a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
+++ b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
@@ -26,7 +26,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
* @param registers {@code non-null;} source registers
*/
diff --git a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
index 198bebf..2cc157b 100644
--- a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
+++ b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
@@ -29,7 +29,7 @@
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
- *
+ *
* @param position {@code non-null;} source position
*/
public ZeroSizeInsn(SourcePosition position) {
diff --git a/dx/src/com/android/dx/dex/code/form/Form22c.java b/dx/src/com/android/dx/dex/code/form/Form22c.java
index e77677f..423ccc8 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22c.java
@@ -83,7 +83,7 @@
if (! unsignedFitsInShort(cpi)) {
return false;
}
-
+
Constant cst = ci.getConstant();
return (cst instanceof CstType) ||
(cst instanceof CstFieldRef);
diff --git a/dx/src/com/android/dx/dex/code/form/Form35c.java b/dx/src/com/android/dx/dex/code/form/Form35c.java
index 411e3c3..31b127d 100644
--- a/dx/src/com/android/dx/dex/code/form/Form35c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form35c.java
@@ -112,7 +112,7 @@
int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
write(out,
- opcodeUnit(insn,
+ opcodeUnit(insn,
makeByte(r4, sz)), // encode the fifth operand here
(short) cpi,
codeUnit(r0, r1, r2, r3));
@@ -123,9 +123,9 @@
* category-2 values count as two words. Return {@code -1} if the
* list requires more than five words or contains registers that need
* more than a nibble to identify them.
- *
+ *
* @param regs {@code non-null;} the register list in question
- * @return {@code >= -1;} the number of words required, or {@code -1}
+ * @return {@code >= -1;} the number of words required, or {@code -1}
* if the list couldn't possibly fit in this format
*/
private static int wordCount(RegisterSpecList regs) {
@@ -160,7 +160,7 @@
* except that it splits category-2 registers into two explicit
* entries. This returns the original list if no modification is
* required
- *
+ *
* @param orig {@code non-null;} the original list
* @return {@code non-null;} the list with the described transformation
*/
diff --git a/dx/src/com/android/dx/dex/code/form/Form3rc.java b/dx/src/com/android/dx/dex/code/form/Form3rc.java
index 2d185cf..755ad76 100644
--- a/dx/src/com/android/dx/dex/code/form/Form3rc.java
+++ b/dx/src/com/android/dx/dex/code/form/Form3rc.java
@@ -69,7 +69,7 @@
*/
lastReg = lastReg.withOffset(1);
}
-
+
sb.append(regs.get(0).regString());
sb.append("..");
sb.append(lastReg.regString());
@@ -78,7 +78,7 @@
sb.append("}, ");
sb.append(cstString(insn));
-
+
return sb.toString();
}
diff --git a/dx/src/com/android/dx/dex/file/AnnotationItem.java b/dx/src/com/android/dx/dex/file/AnnotationItem.java
index 08422bc..1febd9e 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationItem.java
@@ -36,19 +36,19 @@
public final class AnnotationItem extends OffsettedItem {
/** annotation visibility constant: visible at build time only */
private static final int VISIBILITY_BUILD = 0;
-
+
/** annotation visibility constant: visible at runtime */
private static final int VISIBILITY_RUNTIME = 1;
/** annotation visibility constant: visible at runtime only to system */
private static final int VISIBILITY_SYSTEM = 2;
-
+
/** the required alignment for instances of this class */
private static final int ALIGNMENT = 1;
/** {@code non-null;} unique instance of {@link #TypeIdSorter} */
private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
-
+
/** {@code non-null;} the annotation to represent */
private final Annotation annotation;
@@ -87,7 +87,7 @@
* Sorts an array of instances, in place, by type id index,
* ignoring all other aspects of the elements. This is only valid
* to use after type id indices are known.
- *
+ *
* @param array {@code non-null;} array to sort
*/
public static void sortByTypeIdIndex(AnnotationItem[] array) {
@@ -96,7 +96,7 @@
/**
* Constructs an instance.
- *
+ *
* @param annotation {@code non-null;} annotation to represent
*/
public AnnotationItem(Annotation annotation) {
@@ -166,7 +166,7 @@
* Write a (listing file) annotation for this instance to the given
* output, that consumes no bytes of output. This is for annotating
* a reference to this instance at the point of the reference.
- *
+ *
* @param out {@code non-null;} where to output to
* @param prefix {@code non-null;} prefix for each line of output
*/
@@ -204,7 +204,7 @@
throw new RuntimeException("shouldn't happen");
}
}
-
+
if (annotates) {
/*
* The output is to be annotated, so redo the work previously
diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
index 2ff005a..2187700 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
@@ -33,7 +33,7 @@
/** {@code non-null;} the set of annotations */
private final Annotations annotations;
-
+
/**
* {@code non-null;} set of annotations as individual items in an array.
* <b>Note:</b> The contents have to get sorted by type id before
@@ -43,7 +43,7 @@
/**
* Constructs an instance.
- *
+ *
* @param annotations {@code non-null;} set of annotations
*/
public AnnotationSetItem(Annotations annotations) {
@@ -61,7 +61,7 @@
/**
* Gets the write size for the given set.
- *
+ *
* @param annotations {@code non-null;} the set
* @return {@code > 0;} the write size
*/
@@ -78,13 +78,13 @@
/**
* Gets the underlying annotations of this instance
- *
+ *
* @return {@code non-null;} the annotations
*/
public Annotations getAnnotations() {
return annotations;
}
-
+
/** {@inheritDoc} */
@Override
public int hashCode() {
@@ -140,11 +140,11 @@
}
out.writeInt(size);
-
+
for (int i = 0; i < size; i++) {
AnnotationItem item = items[i];
int offset = item.getAbsoluteOffset();
-
+
if (annotates) {
out.annotate(4, " entries[" + Integer.toHexString(i) + "]: " +
Hex.u4(offset));
diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
index 1427e6a..53072d8 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
@@ -34,7 +34,7 @@
/**
* Constructs an instance.
- *
+ *
* @param annotations {@code non-null;} the annotation set to refer to
*/
public AnnotationSetRefItem(AnnotationSetItem annotations) {
diff --git a/dx/src/com/android/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
index 8431d35..d500ec4 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationUtils.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
@@ -39,31 +39,31 @@
*/
public final class AnnotationUtils {
/** {@code non-null;} type for {@code AnnotationDefault} annotations */
- private static final CstType ANNOTATION_DEFAULT_TYPE =
+ private static final CstType ANNOTATION_DEFAULT_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
/** {@code non-null;} type for {@code EnclosingClass} annotations */
- private static final CstType ENCLOSING_CLASS_TYPE =
+ private static final CstType ENCLOSING_CLASS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
/** {@code non-null;} type for {@code EnclosingMethod} annotations */
- private static final CstType ENCLOSING_METHOD_TYPE =
+ private static final CstType ENCLOSING_METHOD_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
/** {@code non-null;} type for {@code InnerClass} annotations */
- private static final CstType INNER_CLASS_TYPE =
+ private static final CstType INNER_CLASS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
/** {@code non-null;} type for {@code MemberClasses} annotations */
- private static final CstType MEMBER_CLASSES_TYPE =
+ private static final CstType MEMBER_CLASSES_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
/** {@code non-null;} type for {@code Signature} annotations */
- private static final CstType SIGNATURE_TYPE =
+ private static final CstType SIGNATURE_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
/** {@code non-null;} type for {@code Throws} annotations */
- private static final CstType THROWS_TYPE =
+ private static final CstType THROWS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
/** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
@@ -84,7 +84,7 @@
/**
* Constructs a standard {@code AnnotationDefault} annotation.
- *
+ *
* @param defaults {@code non-null;} the defaults, itself as an annotation
* @return {@code non-null;} the constructed annotation
*/
@@ -98,7 +98,7 @@
/**
* Constructs a standard {@code EnclosingClass} annotation.
- *
+ *
* @param clazz {@code non-null;} the enclosing class
* @return {@code non-null;} the annotation
*/
@@ -112,7 +112,7 @@
/**
* Constructs a standard {@code EnclosingMethod} annotation.
- *
+ *
* @param method {@code non-null;} the enclosing method
* @return {@code non-null;} the annotation
*/
@@ -126,7 +126,7 @@
/**
* Constructs a standard {@code InnerClass} annotation.
- *
+ *
* @param name {@code null-ok;} the original name of the class, or
* {@code null} to represent an anonymous class
* @param accessFlags the original access flags
@@ -146,7 +146,7 @@
/**
* Constructs a standard {@code MemberClasses} annotation.
- *
+ *
* @param types {@code non-null;} the list of (the types of) the member classes
* @return {@code non-null;} the annotation
*/
@@ -160,7 +160,7 @@
/**
* Constructs a standard {@code Signature} annotation.
- *
+ *
* @param signature {@code non-null;} the signature string
* @return {@code non-null;} the annotation
*/
@@ -171,7 +171,7 @@
* Split the string into pieces that are likely to be common
* across many signatures and the rest of the file.
*/
-
+
String raw = signature.getString();
int rawLength = raw.length();
ArrayList<String> pieces = new ArrayList<String>(20);
@@ -214,7 +214,7 @@
}
list.setImmutable();
-
+
result.put(new NameValuePair(VALUE_UTF, new CstArray(list)));
result.setImmutable();
return result;
@@ -222,7 +222,7 @@
/**
* Constructs a standard {@code Throws} annotation.
- *
+ *
* @param types {@code non-null;} the list of thrown types
* @return {@code non-null;} the annotation
*/
@@ -236,7 +236,7 @@
/**
* Converts a {@link TypeList} to a {@link CstArray}.
- *
+ *
* @param types {@code non-null;} the type list
* @return {@code non-null;} the corresponding array constant
*/
diff --git a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
index d55195f..972d4e6 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
@@ -42,7 +42,7 @@
/** {@code null-ok;} the class-level annotations, if any */
private AnnotationSetItem classAnnotations;
-
+
/** {@code null-ok;} the annotated fields, if any */
private ArrayList<FieldAnnotationStruct> fieldAnnotations;
@@ -63,7 +63,7 @@
methodAnnotations = null;
parameterAnnotations = null;
}
-
+
/** {@inheritDoc} */
@Override
public ItemType itemType() {
@@ -72,7 +72,7 @@
/**
* Returns whether this item is empty (has no contents).
- *
+ *
* @return {@code true} if this item is empty, or {@code false}
* if not
*/
@@ -104,16 +104,16 @@
if (classAnnotations == null) {
return 0;
}
-
+
return classAnnotations.hashCode();
}
-
+
/**
* {@inheritDoc}
- *
+ *
* <p><b>Note:</b>: This throws an exception if this item is not
* internable.</p>
- *
+ *
* @see #isInternable
*/
@Override
@@ -131,14 +131,14 @@
* Sets the direct annotations on this instance. These are annotations
* made on the class, per se, as opposed to on one of its members.
* It is only valid to call this method at most once per instance.
- *
+ *
* @param annotations {@code non-null;} annotations to set for this class
*/
public void setClassAnnotations(Annotations annotations) {
if (annotations == null) {
throw new NullPointerException("annotations == null");
}
-
+
if (classAnnotations != null) {
throw new UnsupportedOperationException(
"class annotations already set");
@@ -149,7 +149,7 @@
/**
* Adds a field annotations item to this instance.
- *
+ *
* @param field {@code non-null;} field in question
* @param annotations {@code non-null;} associated annotations to add
*/
@@ -158,14 +158,14 @@
if (fieldAnnotations == null) {
fieldAnnotations = new ArrayList<FieldAnnotationStruct>();
}
-
+
fieldAnnotations.add(new FieldAnnotationStruct(field,
new AnnotationSetItem(annotations)));
}
/**
* Adds a method annotations item to this instance.
- *
+ *
* @param method {@code non-null;} method in question
* @param annotations {@code non-null;} associated annotations to add
*/
@@ -181,7 +181,7 @@
/**
* Adds a parameter annotations item to this instance.
- *
+ *
* @param method {@code non-null;} method in question
* @param list {@code non-null;} associated list of annotation sets to add
*/
@@ -197,7 +197,7 @@
/**
* Gets the method annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
- *
+ *
* @param method {@code non-null;} the method
* @return {@code null-ok;} the method annotations, if any
*/
@@ -205,7 +205,7 @@
if (methodAnnotations == null) {
return null;
}
-
+
for (MethodAnnotationStruct item : methodAnnotations) {
if (item.getMethod().equals(method)) {
return item.getAnnotations();
@@ -218,7 +218,7 @@
/**
* Gets the parameter annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
- *
+ *
* @param method {@code non-null;} the method
* @return {@code null-ok;} the parameter annotations, if any
*/
@@ -235,7 +235,7 @@
return null;
}
-
+
/** {@inheritDoc} */
public void addContents(DexFile file) {
MixedItemSection wordData = file.getWordData();
@@ -255,7 +255,7 @@
item.addContents(file);
}
}
-
+
if (parameterAnnotations != null) {
for (ParameterAnnotationStruct item : parameterAnnotations) {
item.addContents(file);
@@ -338,7 +338,7 @@
/**
* Gets the list size of the given list, or {@code 0} if given
* {@code null}.
- *
+ *
* @param list {@code null-ok;} the list in question
* @return {@code >= 0;} its size
*/
@@ -353,7 +353,7 @@
/**
* Prints out the contents of this instance, in a debugging-friendly
* way. This is meant to be called from {@link ClassDefItem#debugPrint}.
- *
+ *
* @param out {@code non-null;} where to output to
*/
/*package*/ void debugPrint(PrintWriter out) {
@@ -374,12 +374,12 @@
out.println(" " + item.toHuman());
}
}
-
+
if (parameterAnnotations != null) {
out.println(" parameter annotations:");
for (ParameterAnnotationStruct item : parameterAnnotations) {
out.println(" " + item.toHuman());
}
}
- }
+ }
}
diff --git a/dx/src/com/android/dx/dex/file/CatchStructs.java b/dx/src/com/android/dx/dex/file/CatchStructs.java
index 3412015..e07ec29 100644
--- a/dx/src/com/android/dx/dex/file/CatchStructs.java
+++ b/dx/src/com/android/dx/dex/file/CatchStructs.java
@@ -38,13 +38,13 @@
public final class CatchStructs {
/**
* the size of a {@code try_item}: a {@code uint}
- * and two {@code ushort}s
+ * and two {@code ushort}s
*/
private static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2);
/** {@code non-null;} code that contains the catches */
private final DalvCode code;
-
+
/**
* {@code null-ok;} the underlying table; set in
* {@link #finishProcessingIfNecessary}
@@ -71,7 +71,7 @@
/**
* Constructs an instance.
- *
+ *
* @param code {@code non-null;} code that contains the catches
*/
public CatchStructs(DalvCode code) {
@@ -93,7 +93,7 @@
/**
* Gets the size of the tries list, in entries.
- *
+ *
* @return {@code >= 0;} the tries list size
*/
public int triesSize() {
@@ -103,7 +103,7 @@
/**
* Does a human-friendly dump of this instance.
- *
+ *
* @param out {@code non-null;} where to dump
* @param prefix {@code non-null;} prefix to attach to each line of output
*/
@@ -113,7 +113,7 @@
/**
* Encodes the handler lists.
- *
+ *
* @param file {@code non-null;} file this instance is part of
*/
public void encode(DexFile file) {
@@ -136,13 +136,13 @@
throw new UnsupportedOperationException(
"too many catch handlers");
}
-
+
ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
// Write out the handlers "header" consisting of its size in entries.
encodedHandlerHeaderSize =
out.writeUnsignedLeb128(handlerOffsets.size());
-
+
// Now write the lists out in order, noting the offset of each.
for (Map.Entry<CatchHandlerList, Integer> mapping :
handlerOffsets.entrySet()) {
@@ -178,17 +178,17 @@
/**
* Gets the write size of this instance, in bytes.
- *
+ *
* @return {@code >= 0;} the write size
*/
public int writeSize() {
return (triesSize() * TRY_ITEM_WRITE_SIZE) +
+ encodedHandlers.length;
}
-
+
/**
* Writes this instance to the given stream.
- *
+ *
* @param file {@code non-null;} file this instance is part of
* @param out {@code non-null;} where to write to
*/
@@ -216,7 +216,7 @@
out.writeShort(insnCount);
out.writeShort(handlerOffsets.get(one.getHandlers()));
}
-
+
out.write(encodedHandlers);
}
@@ -224,7 +224,7 @@
* Helper method to annotate or simply print the exception handlers.
* Only one of {@code printTo} or {@code annotateTo} should
* be non-null.
- *
+ *
* @param prefix {@code non-null;} prefix for each line
* @param printTo {@code null-ok;} where to print to
* @param annotateTo {@code null-ok;} where to consume bytes and annotate to
@@ -272,7 +272,7 @@
int lastOffset = 0;
CatchHandlerList lastList = null;
-
+
for (Map.Entry<CatchHandlerList, Integer> mapping :
handlerOffsets.entrySet()) {
CatchHandlerList list = mapping.getKey();
@@ -295,7 +295,7 @@
/**
* Helper for {@link #annotateEntries} to annotate a catch handler list
* while consuming it.
- *
+ *
* @param handlers {@code non-null;} handlers to annotate
* @param offset {@code >= 0;} the offset of this handler
* @param size {@code >= 1;} the number of bytes the handlers consume
diff --git a/dx/src/com/android/dx/dex/file/ClassDataItem.java b/dx/src/com/android/dx/dex/file/ClassDataItem.java
index 4823f9f..275ae99 100644
--- a/dx/src/com/android/dx/dex/file/ClassDataItem.java
+++ b/dx/src/com/android/dx/dex/file/ClassDataItem.java
@@ -43,7 +43,7 @@
public final class ClassDataItem extends OffsettedItem {
/** {@code non-null;} what class this data is for, just for listing generation */
private final CstType thisClass;
-
+
/** {@code non-null;} list of static fields */
private final ArrayList<EncodedField> staticFields;
@@ -71,7 +71,7 @@
/**
* Constructs an instance. Its sets of members are initially
* empty.
- *
+ *
* @param thisClass {@code non-null;} what class this data is for, just
* for listing generation
*/
@@ -105,7 +105,7 @@
/**
* Returns whether this instance is empty.
- *
+ *
* @return {@code true} if this instance is empty or
* {@code false} if at least one element has been added to it
*/
@@ -116,7 +116,7 @@
/**
* Adds a static field.
- *
+ *
* @param field {@code non-null;} the field to add
* @param value {@code null-ok;} initial value for the field, if any
*/
@@ -136,7 +136,7 @@
/**
* Adds an instance field.
- *
+ *
* @param field {@code non-null;} the field to add
*/
public void addInstanceField(EncodedField field) {
@@ -149,7 +149,7 @@
/**
* Adds a direct ({@code static} and/or {@code private}) method.
- *
+ *
* @param method {@code non-null;} the method to add
*/
public void addDirectMethod(EncodedMethod method) {
@@ -162,7 +162,7 @@
/**
* Adds a virtual method.
- *
+ *
* @param method {@code non-null;} the method to add
*/
public void addVirtualMethod(EncodedMethod method) {
@@ -177,7 +177,7 @@
* Gets all the methods in this class. The returned list is not linked
* in any way to the underlying lists contained in this instance, but
* the objects contained in the list are shared.
- *
+ *
* @return {@code non-null;} list of all methods
*/
public ArrayList<EncodedMethod> getMethods() {
@@ -194,7 +194,7 @@
/**
* Prints out the contents of this instance, in a debugging-friendly
* way.
- *
+ *
* @param out {@code non-null;} where to output to
* @param verbose whether to be verbose with the output
*/
@@ -259,7 +259,7 @@
/**
* Gets a {@link CstArray} corresponding to {@link #staticValues} if
* it contains any non-zero non-{@code null} values.
- *
+ *
* @return {@code null-ok;} the corresponding constant or {@code null} if
* there are no values to encode
*/
@@ -274,14 +274,14 @@
/**
* Gets a {@link CstArray} corresponding to {@link #staticValues} if
* it contains any non-zero non-{@code null} values.
- *
+ *
* @return {@code null-ok;} the corresponding constant or {@code null} if
* there are no values to encode
*/
private CstArray makeStaticValuesConstant() {
// First sort the statics into their final order.
Collections.sort(staticFields);
-
+
/*
* Get the size of staticValues minus any trailing zeros/nulls (both
* nulls per se as well as instances of CstKnownNull).
@@ -305,9 +305,9 @@
if (size == 0) {
return null;
}
-
+
// There is something worth encoding, so build up a result.
-
+
CstArray.List list = new CstArray.List(size);
for (int i = 0; i < size; i++) {
EncodedField field = staticFields.get(i);
@@ -336,7 +336,7 @@
/**
* Writes out the encoded form of this instance.
- *
+ *
* @param file {@code non-null;} file this instance is part of
* @param out {@code non-null;} where to write to
*/
@@ -362,11 +362,11 @@
out.endAnnotation();
}
}
-
+
/**
* Helper for {@link #encodeOutput}, which writes out the given
* size value, annotating it as well (if annotations are enabled).
- *
+ *
* @param file {@code non-null;} file this instance is part of
* @param out {@code non-null;} where to write to
* @param label {@code non-null;} the label for the purposes of annotation
@@ -386,7 +386,7 @@
* Helper for {@link #encodeOutput}, which writes out the given
* list. It also annotates the items (if any and if annotations
* are enabled).
- *
+ *
* @param file {@code non-null;} file this instance is part of
* @param out {@code non-null;} where to write to
* @param label {@code non-null;} the label for the purposes of annotation
@@ -400,7 +400,7 @@
if (size == 0) {
return;
}
-
+
if (out.annotates()) {
out.annotate(0, " " + label + ":");
}
diff --git a/dx/src/com/android/dx/dex/file/ClassDefItem.java b/dx/src/com/android/dx/dex/file/ClassDefItem.java
index acd8cf5..4d1719b 100644
--- a/dx/src/com/android/dx/dex/file/ClassDefItem.java
+++ b/dx/src/com/android/dx/dex/file/ClassDefItem.java
@@ -53,7 +53,7 @@
/**
* {@code null-ok;} superclass or {@code null} if this class is a/the
- * root class
+ * root class
*/
private final CstType superclass;
@@ -78,7 +78,7 @@
/**
* Constructs an instance. Its sets of members and annotations are
* initially empty.
- *
+ *
* @param thisClass {@code non-null;} type constant for this class
* @param accessFlags access flags
* @param superclass {@code null-ok;} superclass or {@code null} if
@@ -105,7 +105,7 @@
this.thisClass = thisClass;
this.accessFlags = accessFlags;
this.superclass = superclass;
- this.interfaces =
+ this.interfaces =
(interfaces.size() == 0) ? null : new TypeListItem(interfaces);
this.sourceFile = sourceFile;
this.classData = new ClassDataItem(thisClass);
@@ -188,7 +188,7 @@
if (annotates) {
out.annotate(0, indexString() + ' ' + thisClass.toHuman());
out.annotate(4, " class_idx: " + Hex.u4(classIdx));
- out.annotate(4, " access_flags: " +
+ out.annotate(4, " access_flags: " +
AccessFlags.classString(accessFlags));
out.annotate(4, " superclass_idx: " + Hex.u4(superIdx) +
" // " + ((superclass == null) ? "<none>" :
@@ -222,7 +222,7 @@
/**
* Gets the constant corresponding to this class.
- *
+ *
* @return {@code non-null;} the constant
*/
public CstType getThisClass() {
@@ -231,7 +231,7 @@
/**
* Gets the access flags.
- *
+ *
* @return the access flags
*/
public int getAccessFlags() {
@@ -240,7 +240,7 @@
/**
* Gets the superclass.
- *
+ *
* @return {@code null-ok;} the superclass or {@code null} if
* this class is a/the root class
*/
@@ -250,7 +250,7 @@
/**
* Gets the list of interfaces implemented.
- *
+ *
* @return {@code non-null;} the interfaces list
*/
public TypeList getInterfaces() {
@@ -263,7 +263,7 @@
/**
* Gets the source file name.
- *
+ *
* @return {@code null-ok;} the source file name or {@code null} if unknown
*/
public CstUtf8 getSourceFile() {
@@ -272,7 +272,7 @@
/**
* Adds a static field.
- *
+ *
* @param field {@code non-null;} the field to add
* @param value {@code null-ok;} initial value for the field, if any
*/
@@ -282,7 +282,7 @@
/**
* Adds an instance field.
- *
+ *
* @param field {@code non-null;} the field to add
*/
public void addInstanceField(EncodedField field) {
@@ -291,7 +291,7 @@
/**
* Adds a direct ({@code static} and/or {@code private}) method.
- *
+ *
* @param method {@code non-null;} the method to add
*/
public void addDirectMethod(EncodedMethod method) {
@@ -300,7 +300,7 @@
/**
* Adds a virtual method.
- *
+ *
* @param method {@code non-null;} the method to add
*/
public void addVirtualMethod(EncodedMethod method) {
@@ -311,7 +311,7 @@
* Gets all the methods in this class. The returned list is not linked
* in any way to the underlying lists contained in this instance, but
* the objects contained in the list are shared.
- *
+ *
* @return {@code non-null;} list of all methods
*/
public ArrayList<EncodedMethod> getMethods() {
@@ -322,7 +322,7 @@
* Sets the direct annotations on this class. These are annotations
* made on the class, per se, as opposed to on one of its members.
* It is only valid to call this method at most once per instance.
- *
+ *
* @param annotations {@code non-null;} annotations to set for this class
*/
public void setClassAnnotations(Annotations annotations) {
@@ -331,7 +331,7 @@
/**
* Adds a field annotations item to this class.
- *
+ *
* @param field {@code non-null;} field in question
* @param annotations {@code non-null;} associated annotations to add
*/
@@ -342,7 +342,7 @@
/**
* Adds a method annotations item to this class.
- *
+ *
* @param method {@code non-null;} method in question
* @param annotations {@code non-null;} associated annotations to add
*/
@@ -353,7 +353,7 @@
/**
* Adds a parameter annotations item to this class.
- *
+ *
* @param method {@code non-null;} method in question
* @param list {@code non-null;} associated list of annotation sets to add
*/
@@ -365,7 +365,7 @@
/**
* Gets the method annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
- *
+ *
* @param method {@code non-null;} the method
* @return {@code null-ok;} the method annotations, if any
*/
@@ -376,18 +376,18 @@
/**
* Gets the parameter annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
- *
+ *
* @param method {@code non-null;} the method
* @return {@code null-ok;} the parameter annotations, if any
*/
public AnnotationsList getParameterAnnotations(CstMethodRef method) {
return annotationsDirectory.getParameterAnnotations(method);
}
-
+
/**
* Prints out the contents of this instance, in a debugging-friendly
* way.
- *
+ *
* @param out {@code non-null;} where to output to
* @param verbose whether to be verbose with the output
*/
@@ -404,7 +404,7 @@
classData.debugPrint(out, verbose);
annotationsDirectory.debugPrint(pw);
-
+
pw.println("}");
}
}
diff --git a/dx/src/com/android/dx/dex/file/ClassDefsSection.java b/dx/src/com/android/dx/dex/file/ClassDefsSection.java
index e8efd57..1ca391f 100644
--- a/dx/src/com/android/dx/dex/file/ClassDefsSection.java
+++ b/dx/src/com/android/dx/dex/file/ClassDefsSection.java
@@ -42,7 +42,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public ClassDefsSection(DexFile file) {
@@ -58,7 +58,7 @@
if (orderedDefs != null) {
return orderedDefs;
}
-
+
return classDefs.values();
}
@@ -83,7 +83,7 @@
/**
* Writes the portion of the file header that refers to this instance.
- *
+ *
* @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
@@ -104,7 +104,7 @@
/**
* Adds an element to this instance. It is illegal to attempt to add more
* than one class with the same name.
- *
+ *
* @param clazz {@code non-null;} the class def to add
*/
public void add(ClassDefItem clazz) {
@@ -148,7 +148,7 @@
/**
* Helper for {@link #orderItems}, which recursively assigns indices
* to classes.
- *
+ *
* @param type {@code null-ok;} type ref to assign, if any
* @param idx {@code >= 0;} the next index to assign
* @param maxDepth maximum recursion depth; if negative, this will
diff --git a/dx/src/com/android/dx/dex/file/CodeItem.java b/dx/src/com/android/dx/dex/file/CodeItem.java
index ab7abbe..a47f68a 100644
--- a/dx/src/com/android/dx/dex/file/CodeItem.java
+++ b/dx/src/com/android/dx/dex/file/CodeItem.java
@@ -62,7 +62,7 @@
/**
* {@code non-null;} list of possibly-thrown exceptions; just used in
- * generating debugging output (listings)
+ * generating debugging output (listings)
*/
private final TypeList throwsList;
@@ -74,7 +74,7 @@
/**
* Constructs an instance.
- *
+ *
* @param ref {@code non-null;} method that this code implements
* @param code {@code non-null;} the underlying code
* @param isStatic whether this instance is for a {@code static}
@@ -148,7 +148,7 @@
/**
* Gets the reference to the method this instance implements.
- *
+ *
* @return {@code non-null;} the method reference
*/
public CstMethodRef getRef() {
@@ -157,7 +157,7 @@
/**
* Does a human-friendly dump of this instance.
- *
+ *
* @param out {@code non-null;} where to dump
* @param prefix {@code non-null;} per-line prefix to use
* @param verbose whether to be verbose with the output
@@ -192,7 +192,7 @@
protected void place0(Section addedTo, int offset) {
final DexFile file = addedTo.getFile();
int catchesSize;
-
+
/*
* In order to get the catches and insns, all the code's
* constants need to be assigned indices.
@@ -307,7 +307,7 @@
/**
* Get the in registers count.
- *
+ *
* @return the count
*/
private int getInsSize() {
@@ -316,7 +316,7 @@
/**
* Get the out registers count.
- *
+ *
* @return the count
*/
private int getOutsSize() {
@@ -325,7 +325,7 @@
/**
* Get the total registers count.
- *
+ *
* @return the count
*/
private int getRegistersSize() {
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
index cd20055..e823816 100644
--- a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
+++ b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
@@ -73,7 +73,7 @@
/** current decoding state: line number */
private int line = 1;
-
+
/** current decoding state: bytecode address */
private int address = 0;
@@ -102,7 +102,7 @@
this.desc = ref.getPrototype();
this.file = file;
this.regSize = regSize;
-
+
positions = new ArrayList<PositionEntry>();
locals = new ArrayList<LocalEntry>();
this.codesize = codesize;
@@ -248,7 +248,7 @@
throw new RuntimeException(
"Mismatch between parameters_size and prototype");
}
-
+
if (!isStatic) {
// Start off with implicit 'this' entry
LocalEntry thisEntry =
@@ -353,7 +353,7 @@
throw new RuntimeException("nonsensical "
+ "END_LOCAL on dead register v" + reg);
}
-
+
le = new LocalEntry(address, false, reg,
prevle.nameIndex, prevle.typeIndex,
prevle.signatureIndex);
@@ -428,7 +428,7 @@
DalvInsnList insns = code.getInsns();
int codeSize = insns.codeSize();
int countRegisters = insns.getRegistersSize();
-
+
try {
validateEncode0(info, codeSize, countRegisters,
isStatic, ref, file, pl, ll);
@@ -441,7 +441,7 @@
"while processing " + ref.toHuman());
}
}
-
+
private static void validateEncode0(byte[] info, int codeSize,
int countRegisters, boolean isStatic, CstMethodRef ref,
DexFile file, PositionList pl, LocalList ll) {
@@ -516,7 +516,7 @@
}
}
}
-
+
int origSz = ll.size();
int decodeAt = 0;
boolean problem = false;
@@ -556,7 +556,7 @@
problem = true;
break;
}
-
+
if (decodedEntry.isStart != origEntry.isStart()) {
System.err.println("local start/end mismatch at orig " + i +
" / decoded " + decodeAt);
@@ -569,7 +569,7 @@
* parameter might not be marked as starting at 0 in the
* original list.
*/
- if ((decodedAddress != origEntry.getAddress())
+ if ((decodedAddress != origEntry.getAddress())
&& !((decodedAddress == 0)
&& (decodedEntry.reg >= paramBase))) {
System.err.println("local address mismatch at orig " + i +
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoItem.java b/dx/src/com/android/dx/dex/file/DebugInfoItem.java
index 1c32bd7..6a41b18 100644
--- a/dx/src/com/android/dx/dex/file/DebugInfoItem.java
+++ b/dx/src/com/android/dx/dex/file/DebugInfoItem.java
@@ -36,7 +36,7 @@
/** {@code non-null;} the code this item represents */
private final DalvCode code;
-
+
private byte[] encoded;
private final boolean isStatic;
@@ -80,7 +80,7 @@
"...while placing debug info for " + ref.toHuman());
}
}
-
+
/** {@inheritDoc} */
@Override
public String toHuman() {
@@ -99,7 +99,7 @@
*/
public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) {
encode(file, prefix, null, out, false);
- }
+ }
/**
* Does a human-friendly dump of this instance.
diff --git a/dx/src/com/android/dx/dex/file/DexFile.java b/dx/src/com/android/dx/dex/file/DexFile.java
index a829fed..1cc9358 100644
--- a/dx/src/com/android/dx/dex/file/DexFile.java
+++ b/dx/src/com/android/dx/dex/file/DexFile.java
@@ -45,7 +45,7 @@
/** {@code non-null;} word data section */
private final MixedItemSection wordData;
- /**
+ /**
* {@code non-null;} type lists section. This is word data, but separating
* it from {@link #wordData} helps break what would otherwise be a
* circular dependency between the that and {@link #protoIds}.
@@ -120,15 +120,15 @@
classDefs = new ClassDefsSection(this);
map = new MixedItemSection("map", this, 4, SortType.NONE);
- /*
+ /*
* This is the list of sections in the order they appear in
* the final output.
*/
sections = new Section[] {
header, stringIds, typeIds, protoIds, fieldIds, methodIds,
- classDefs, wordData, typeLists, stringData, byteData,
+ classDefs, wordData, typeLists, stringData, byteData,
classData, map };
-
+
fileSize = -1;
dumpWidth = 79;
}
@@ -136,7 +136,7 @@
/**
* Adds a class to this instance. It is illegal to attempt to add more
* than one class with the same name.
- *
+ *
* @param clazz {@code non-null;} the class to add
*/
public void add(ClassDefItem clazz) {
@@ -145,7 +145,7 @@
/**
* Gets the class definition with the given name, if any.
- *
+ *
* @param name {@code non-null;} the class name to look for
* @return {@code null-ok;} the class with the given name, or {@code null}
* if there is no such class
@@ -163,7 +163,7 @@
/**
* Writes the contents of this instance as either a binary or a
* human-readable form, or both.
- *
+ *
* @param out {@code null-ok;} where to write to
* @param humanOut {@code null-ok;} where to write human-oriented output to
* @param verbose whether to be verbose when writing human-oriented output
@@ -185,12 +185,12 @@
/**
* Returns the contents of this instance as a {@code .dex} file,
* in {@code byte[]} form.
- *
+ *
* @param humanOut {@code null-ok;} where to write human-oriented output to
* @param verbose whether to be verbose when writing human-oriented output
* @return {@code non-null;} a {@code .dex} file for this instance
*/
- public byte[] toDex(Writer humanOut, boolean verbose)
+ public byte[] toDex(Writer humanOut, boolean verbose)
throws IOException {
boolean annotate = (humanOut != null);
ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
@@ -204,7 +204,7 @@
/**
* Sets the maximum width of the human-oriented dump of the instance.
- *
+ *
* @param dumpWidth {@code >= 40;} the width
*/
public void setDumpWidth(int dumpWidth) {
@@ -217,10 +217,10 @@
/**
* Gets the total file size, if known.
- *
+ *
* <p>This is package-scope in order to allow
* the {@link HeaderSection} to set itself up properly.</p>
- *
+ *
* @return {@code >= 0;} the total file size
* @throws RuntimeException thrown if the file size is not yet known
*/
@@ -234,11 +234,11 @@
/**
* Gets the string data section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the string data section
*/
/*package*/ MixedItemSection getStringData() {
@@ -247,11 +247,11 @@
/**
* Gets the word data section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the word data section
*/
/*package*/ MixedItemSection getWordData() {
@@ -260,11 +260,11 @@
/**
* Gets the type lists section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the word data section
*/
/*package*/ MixedItemSection getTypeLists() {
@@ -273,10 +273,10 @@
/**
* Gets the map section.
- *
+ *
* <p>This is package-scope in order to allow the header section
* to query it.</p>
- *
+ *
* @return {@code non-null;} the map section
*/
/*package*/ MixedItemSection getMap() {
@@ -285,11 +285,11 @@
/**
* Gets the string identifiers section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the string identifiers section
*/
/*package*/ StringIdsSection getStringIds() {
@@ -298,11 +298,11 @@
/**
* Gets the class definitions section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the class definitions section
*/
/*package*/ ClassDefsSection getClassDefs() {
@@ -311,11 +311,11 @@
/**
* Gets the class data section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the class data section
*/
/*package*/ MixedItemSection getClassData() {
@@ -324,11 +324,11 @@
/**
* Gets the type identifiers section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the class identifiers section
*/
/*package*/ TypeIdsSection getTypeIds() {
@@ -337,11 +337,11 @@
/**
* Gets the prototype identifiers section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the prototype identifiers section
*/
/*package*/ ProtoIdsSection getProtoIds() {
@@ -350,11 +350,11 @@
/**
* Gets the field identifiers section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the field identifiers section
*/
/*package*/ FieldIdsSection getFieldIds() {
@@ -363,11 +363,11 @@
/**
* Gets the method identifiers section.
- *
+ *
* <p>This is package-scope in order to allow
* the various {@link Item} instances to add items to the
* instance.</p>
- *
+ *
* @return {@code non-null;} the method identifiers section
*/
/*package*/ MethodIdsSection getMethodIds() {
@@ -390,10 +390,10 @@
/**
* Gets the first section of the file that is to be considered
* part of the data section.
- *
+ *
* <p>This is package-scope in order to allow the header section
* to query it.</p>
- *
+ *
* @return {@code non-null;} the section
*/
/*package*/ Section getFirstDataSection() {
@@ -403,21 +403,21 @@
/**
* Gets the last section of the file that is to be considered
* part of the data section.
- *
+ *
* <p>This is package-scope in order to allow the header section
* to query it.</p>
- *
+ *
* @return {@code non-null;} the section
*/
/*package*/ Section getLastDataSection() {
return map;
}
-
+
/**
* Interns the given constant in the appropriate section of this
* instance, or do nothing if the given constant isn't the sort
* that should be interned.
- *
+ *
* @param cst {@code non-null;} constant to possibly intern
*/
/*package*/ void internIfAppropriate(Constant cst) {
@@ -444,7 +444,7 @@
* {@code null} if it isn't such a constant. This will throw
* an exception if the given constant <i>should</i> have been found
* but wasn't.
- *
+ *
* @param cst {@code non-null;} the constant to look up
* @return {@code null-ok;} its corresponding item, if it has a corresponding
* item, or {@code null} if it's not that sort of constant
@@ -468,7 +468,7 @@
/**
* Returns the contents of this instance as a {@code .dex} file,
* in a {@link ByteArrayAnnotatedOutput} instance.
- *
+ *
* @param annotate whether or not to keep annotations
* @param verbose if annotating, whether to be verbose
* @return {@code non-null;} a {@code .dex} file for this instance
@@ -524,7 +524,7 @@
*/
((MixedItemSection) one).placeItems();
}
-
+
offset = placedAt + one.writeSize();
} catch (RuntimeException ex) {
throw ExceptionWithContext.withContext(ex,
@@ -569,7 +569,7 @@
}
// Perform final bookkeeping.
-
+
calcSignature(barr);
calcChecksum(barr);
@@ -585,7 +585,7 @@
/**
* Generates and returns statistics for all the items in the file.
- *
+ *
* @return {@code non-null;} the statistics
*/
public Statistics getStatistics() {
@@ -601,7 +601,7 @@
/**
* Calculates the signature for the {@code .dex} file in the
* given array, and modify the array to contain it.
- *
+ *
* @param bytes {@code non-null;} the bytes of the file
*/
private static void calcSignature(byte[] bytes) {
@@ -629,7 +629,7 @@
/**
* Calculates the checksum for the {@code .dex} file in the
* given array, and modify the array to contain it.
- *
+ *
* @param bytes {@code non-null;} the bytes of the file
*/
private static void calcChecksum(byte[] bytes) {
diff --git a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
index c55c6f5..4d904e7 100644
--- a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
+++ b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
@@ -47,7 +47,7 @@
/**
* Constructs an instance.
- *
+ *
* @param array {@code non-null;} array to represent
*/
public EncodedArrayItem(CstArray array) {
diff --git a/dx/src/com/android/dx/dex/file/EncodedField.java b/dx/src/com/android/dx/dex/file/EncodedField.java
index 146a604..f2a8184 100644
--- a/dx/src/com/android/dx/dex/file/EncodedField.java
+++ b/dx/src/com/android/dx/dex/file/EncodedField.java
@@ -35,7 +35,7 @@
/**
* Constructs an instance.
- *
+ *
* @param field {@code non-null;} constant for the field
* @param accessFlags access flags
*/
@@ -70,7 +70,7 @@
/**
* {@inheritDoc}
- *
+ *
* <p><b>Note:</b> This compares the method constants only,
* ignoring any associated code, because it should never be the
* case that two different items with the same method constant
@@ -121,7 +121,7 @@
/**
* Gets the constant for the field.
- *
+ *
* @return {@code non-null;} the constant
*/
public CstFieldRef getRef() {
@@ -130,7 +130,7 @@
/** {@inheritDoc} */
@Override
- public int encode(DexFile file, AnnotatedOutput out,
+ public int encode(DexFile file, AnnotatedOutput out,
int lastIndex, int dumpSeq) {
int fieldIdx = file.getFieldIds().indexOf(field);
int diff = fieldIdx - lastIndex;
diff --git a/dx/src/com/android/dx/dex/file/EncodedMember.java b/dx/src/com/android/dx/dex/file/EncodedMember.java
index 68119f3..5099325 100644
--- a/dx/src/com/android/dx/dex/file/EncodedMember.java
+++ b/dx/src/com/android/dx/dex/file/EncodedMember.java
@@ -65,14 +65,14 @@
/**
* Populates a {@link DexFile} with items from within this instance.
- *
+ *
* @param file {@code non-null;} the file to populate
*/
public abstract void addContents(DexFile file);
/**
* Encodes this instance to the given output.
- *
+ *
* @param file {@code non-null;} file this instance is part of
* @param out {@code non-null;} where to write to
* @param lastIndex {@code >= 0;} the previous member index value encoded, or
@@ -81,6 +81,6 @@
* annotation purposes
* @return {@code >= 0;} the member index value that was encoded
*/
- public abstract int encode(DexFile file, AnnotatedOutput out,
+ public abstract int encode(DexFile file, AnnotatedOutput out,
int lastIndex, int dumpSeq);
}
diff --git a/dx/src/com/android/dx/dex/file/EncodedMethod.java b/dx/src/com/android/dx/dex/file/EncodedMethod.java
index dff1a07..1b0770f 100644
--- a/dx/src/com/android/dx/dex/file/EncodedMethod.java
+++ b/dx/src/com/android/dx/dex/file/EncodedMethod.java
@@ -30,20 +30,20 @@
/**
* Class that representats a method of a class.
*/
-public final class EncodedMethod extends EncodedMember
+public final class EncodedMethod extends EncodedMember
implements Comparable<EncodedMethod> {
/** {@code non-null;} constant for the method */
private final CstMethodRef method;
/**
* {@code null-ok;} code for the method, if the method is neither
- * {@code abstract} nor {@code native}
+ * {@code abstract} nor {@code native}
*/
private final CodeItem code;
/**
* Constructs an instance.
- *
+ *
* @param method {@code non-null;} constant for the method
* @param accessFlags access flags
* @param code {@code null-ok;} code for the method, if it is neither
@@ -80,7 +80,7 @@
/**
* {@inheritDoc}
- *
+ *
* <p><b>Note:</b> This compares the method constants only,
* ignoring any associated code, because it should never be the
* case that two different items with the same method constant
@@ -147,7 +147,7 @@
/**
* Gets the constant for the method.
- *
+ *
* @return {@code non-null;} the constant
*/
public final CstMethodRef getRef() {
@@ -156,14 +156,14 @@
/** {@inheritDoc} */
@Override
- public int encode(DexFile file, AnnotatedOutput out,
+ public int encode(DexFile file, AnnotatedOutput out,
int lastIndex, int dumpSeq) {
int methodIdx = file.getMethodIds().indexOf(method);
int diff = methodIdx - lastIndex;
int accessFlags = getAccessFlags();
int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code);
boolean hasCode = (codeOff != 0);
- boolean shouldHaveCode = (accessFlags &
+ boolean shouldHaveCode = (accessFlags &
(AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0;
/*
diff --git a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
index 6a76ca9..f363d41 100644
--- a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
+++ b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
@@ -35,7 +35,7 @@
/**
* Constructs an instance.
- *
+ *
* @param field {@code non-null;} the field in question
* @param annotations {@code non-null;} the associated annotations
*/
@@ -57,13 +57,13 @@
public int hashCode() {
return field.hashCode();
}
-
+
/** {@inheritDoc} */
public boolean equals(Object other) {
if (! (other instanceof FieldAnnotationStruct)) {
return false;
}
-
+
return field.equals(((FieldAnnotationStruct) other).field);
}
@@ -104,7 +104,7 @@
/**
* Gets the field this item is for.
- *
+ *
* @return {@code non-null;} the field
*/
public CstFieldRef getField() {
@@ -113,7 +113,7 @@
/**
* Gets the associated annotations.
- *
+ *
* @return {@code non-null;} the annotations
*/
public Annotations getAnnotations() {
diff --git a/dx/src/com/android/dx/dex/file/FieldIdItem.java b/dx/src/com/android/dx/dex/file/FieldIdItem.java
index d6d01d5..ecb1d3d 100644
--- a/dx/src/com/android/dx/dex/file/FieldIdItem.java
+++ b/dx/src/com/android/dx/dex/file/FieldIdItem.java
@@ -24,7 +24,7 @@
public final class FieldIdItem extends MemberIdItem {
/**
* Constructs an instance.
- *
+ *
* @param field {@code non-null;} the constant for the field
*/
public FieldIdItem(CstFieldRef field) {
@@ -48,7 +48,7 @@
/**
* Gets the field constant.
- *
+ *
* @return {@code non-null;} the constant
*/
public CstFieldRef getFieldRef() {
@@ -61,10 +61,10 @@
TypeIdsSection typeIds = file.getTypeIds();
return typeIds.indexOf(getFieldRef().getType());
}
-
+
/** {@inheritDoc} */
@Override
protected String getTypoidName() {
return "type_idx";
- }
+ }
}
diff --git a/dx/src/com/android/dx/dex/file/FieldIdsSection.java b/dx/src/com/android/dx/dex/file/FieldIdsSection.java
index 59ef229..c320731 100644
--- a/dx/src/com/android/dx/dex/file/FieldIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/FieldIdsSection.java
@@ -30,13 +30,13 @@
public final class FieldIdsSection extends MemberIdsSection {
/**
* {@code non-null;} map from field constants to {@link
- * FieldIdItem} instances
+ * FieldIdItem} instances
*/
private final TreeMap<CstFieldRef, FieldIdItem> fieldIds;
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public FieldIdsSection(DexFile file) {
@@ -71,7 +71,7 @@
/**
* Writes the portion of the file header that refers to this instance.
- *
+ *
* @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
@@ -91,7 +91,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param field {@code non-null;} the reference to intern
* @return {@code non-null;} the interned reference
*/
@@ -115,7 +115,7 @@
/**
* Gets the index of the given reference, which must have been added
* to this instance.
- *
+ *
* @param ref {@code non-null;} the reference to look up
* @return {@code >= 0;} the reference's index
*/
diff --git a/dx/src/com/android/dx/dex/file/HeaderItem.java b/dx/src/com/android/dx/dex/file/HeaderItem.java
index 6593859..f95ff44 100644
--- a/dx/src/com/android/dx/dex/file/HeaderItem.java
+++ b/dx/src/com/android/dx/dex/file/HeaderItem.java
@@ -48,7 +48,7 @@
public ItemType itemType() {
return ItemType.TYPE_HEADER_ITEM;
}
-
+
/** {@inheritDoc} */
@Override
public int writeSize() {
@@ -70,7 +70,7 @@
int dataOff = firstDataSection.getFileOffset();
int dataSize = lastDataSection.getFileOffset() +
lastDataSection.writeSize() - dataOff;
-
+
if (out.annotates()) {
out.annotate(8, "magic: " + new CstUtf8(MAGIC).toQuoted());
out.annotate(4, "checksum");
@@ -103,7 +103,7 @@
out.writeZeroes(8);
out.writeInt(mapOff);
-
+
// Write out each section's respective header part.
file.getStringIds().writeHeaderPart(out);
file.getTypeIds().writeHeaderPart(out);
diff --git a/dx/src/com/android/dx/dex/file/HeaderSection.java b/dx/src/com/android/dx/dex/file/HeaderSection.java
index 5bc6278..21da488 100644
--- a/dx/src/com/android/dx/dex/file/HeaderSection.java
+++ b/dx/src/com/android/dx/dex/file/HeaderSection.java
@@ -28,10 +28,10 @@
public final class HeaderSection extends UniformItemSection {
/** {@code non-null;} the list of the one item in the section */
private final List<HeaderItem> list;
-
+
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public HeaderSection(DexFile file) {
diff --git a/dx/src/com/android/dx/dex/file/IdItem.java b/dx/src/com/android/dx/dex/file/IdItem.java
index 5d7c9e3..1bd2b5f 100644
--- a/dx/src/com/android/dx/dex/file/IdItem.java
+++ b/dx/src/com/android/dx/dex/file/IdItem.java
@@ -24,13 +24,13 @@
public abstract class IdItem extends IndexedItem {
/**
* {@code non-null;} the type constant for the defining class of
- * the reference
+ * the reference
*/
private final CstType type;
/**
* Constructs an instance.
- *
+ *
* @param type {@code non-null;} the type constant for the defining
* class of the reference
*/
@@ -52,7 +52,7 @@
/**
* Gets the type constant for the defining class of the
* reference.
- *
+ *
* @return {@code non-null;} the type constant
*/
public final CstType getDefiningClass() {
diff --git a/dx/src/com/android/dx/dex/file/IndexedItem.java b/dx/src/com/android/dx/dex/file/IndexedItem.java
index 32d69ea..9ba4783 100644
--- a/dx/src/com/android/dx/dex/file/IndexedItem.java
+++ b/dx/src/com/android/dx/dex/file/IndexedItem.java
@@ -33,7 +33,7 @@
/**
* Gets whether or not this instance has been assigned an index.
- *
+ *
* @return {@code true} iff this instance has been assigned an index
*/
public final boolean hasIndex() {
@@ -72,7 +72,7 @@
/**
* Gets the index of this item as a string, suitable for including in
* annotations.
- *
+ *
* @return {@code non-null;} the index string
*/
public final String indexString() {
diff --git a/dx/src/com/android/dx/dex/file/Item.java b/dx/src/com/android/dx/dex/file/Item.java
index 057f218..cf2b380 100644
--- a/dx/src/com/android/dx/dex/file/Item.java
+++ b/dx/src/com/android/dx/dex/file/Item.java
@@ -32,15 +32,15 @@
/**
* Returns the item type for this instance.
- *
+ *
* @return {@code non-null;} the item type
*/
public abstract ItemType itemType();
-
+
/**
* Returns the human name for the particular type of item this
* instance is.
- *
+ *
* @return {@code non-null;} the name
*/
public final String typeName() {
@@ -49,7 +49,7 @@
/**
* Gets the size of this instance when written, in bytes.
- *
+ *
* @return {@code >= 0;} the write size
*/
public abstract int writeSize();
@@ -58,10 +58,10 @@
* Populates a {@link DexFile} with items from within this instance.
* This will <i>not</i> add an item to the file for this instance itself
* (which should have been done by whatever refers to this instance).
- *
+ *
* <p><b>Note:</b> Subclasses must override this to do something
* appropriate.</p>
- *
+ *
* @param file {@code non-null;} the file to populate
*/
public abstract void addContents(DexFile file);
@@ -72,7 +72,7 @@
* If this instance keeps track of its offset, then this method will
* note the written offset and will also throw an exception if this
* instance has already been written.
- *
+ *
* @param file {@code non-null;} the file to use for reference
* @param out {@code non-null;} where to write to
*/
diff --git a/dx/src/com/android/dx/dex/file/ItemType.java b/dx/src/com/android/dx/dex/file/ItemType.java
index 83843b7..2fe97ab 100644
--- a/dx/src/com/android/dx/dex/file/ItemType.java
+++ b/dx/src/com/android/dx/dex/file/ItemType.java
@@ -44,7 +44,7 @@
TYPE_TYPE_ITEM( -1, "type_item"),
TYPE_EXCEPTION_HANDLER_ITEM( -1, "exception_handler_item"),
TYPE_ANNOTATION_SET_REF_ITEM( -1, "annotation_set_ref_item");
-
+
/** value when represented in a {@link MapItem} */
private final int mapValue;
@@ -53,10 +53,10 @@
/** {@code non-null;} the short human name */
private final String humanName;
-
+
/**
* Constructs an instance.
- *
+ *
* @param mapValue value when represented in a {@link MapItem}
* @param typeName {@code non-null;} name of the type
*/
@@ -74,16 +74,16 @@
/**
* Gets the map value.
- *
+ *
* @return the map value
*/
public int getMapValue() {
return mapValue;
}
-
+
/**
* Gets the type name.
- *
+ *
* @return {@code non-null;} the type name
*/
public String getTypeName() {
diff --git a/dx/src/com/android/dx/dex/file/MapItem.java b/dx/src/com/android/dx/dex/file/MapItem.java
index c728dd7..d78dc91 100644
--- a/dx/src/com/android/dx/dex/file/MapItem.java
+++ b/dx/src/com/android/dx/dex/file/MapItem.java
@@ -74,7 +74,7 @@
throw new IllegalArgumentException(
"mapSection.items().size() != 0");
}
-
+
ArrayList<MapItem> items = new ArrayList<MapItem>(50);
for (Section section : sections) {
@@ -111,10 +111,10 @@
mapSection.add(
new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items));
}
-
+
/**
* Constructs an instance.
- *
+ *
* @param type {@code non-null;} item type this instance covers
* @param section {@code non-null;} section this instance covers
* @param firstItem {@code non-null;} first item covered
@@ -155,7 +155,7 @@
/**
* Constructs a self-referential instance. This instance is meant to
* represent the section containing the {@code map_list}.
- *
+ *
* @param section {@code non-null;} section this instance covers
*/
private MapItem(Section section) {
@@ -231,5 +231,5 @@
out.writeShort(0); // unused
out.writeInt(itemCount);
out.writeInt(offset);
- }
+ }
}
diff --git a/dx/src/com/android/dx/dex/file/MemberIdItem.java b/dx/src/com/android/dx/dex/file/MemberIdItem.java
index 574d413..d3a61d4 100644
--- a/dx/src/com/android/dx/dex/file/MemberIdItem.java
+++ b/dx/src/com/android/dx/dex/file/MemberIdItem.java
@@ -34,7 +34,7 @@
/**
* Constructs an instance.
- *
+ *
* @param cst {@code non-null;} the constant for the member
*/
public MemberIdItem(CstMemberRef cst) {
@@ -74,7 +74,7 @@
out.annotate(2, String.format(" %-10s %s", getTypoidName() + ':',
Hex.u2(typoidIdx)));
out.annotate(4, " name_idx: " + Hex.u4(nameIdx));
- }
+ }
out.writeShort(classIdx);
out.writeShort(typoidIdx);
@@ -85,24 +85,24 @@
* Returns the index of the type-like thing associated with
* this item, in order that it may be written out. Subclasses must
* override this to get whatever it is they need to store.
- *
+ *
* @param file {@code non-null;} the file being written
* @return the index in question
*/
protected abstract int getTypoidIdx(DexFile file);
-
+
/**
* Returns the field name of the type-like thing associated with
* this item, for listing-generating purposes. Subclasses must override
* this.
- *
+ *
* @return {@code non-null;} the name in question
*/
protected abstract String getTypoidName();
/**
* Gets the member constant.
- *
+ *
* @return {@code non-null;} the constant
*/
public final CstMemberRef getRef() {
diff --git a/dx/src/com/android/dx/dex/file/MemberIdsSection.java b/dx/src/com/android/dx/dex/file/MemberIdsSection.java
index 20b1605..ef0d8cd 100644
--- a/dx/src/com/android/dx/dex/file/MemberIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/MemberIdsSection.java
@@ -22,7 +22,7 @@
public abstract class MemberIdsSection extends UniformItemSection {
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param name {@code null-ok;} the name of this instance, for annotation
* purposes
* @param file {@code non-null;} file that this instance is part of
diff --git a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
index 3c254a1..38f7ce4 100644
--- a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
+++ b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
@@ -35,7 +35,7 @@
/**
* Constructs an instance.
- *
+ *
* @param method {@code non-null;} the method in question
* @param annotations {@code non-null;} the associated annotations
*/
@@ -57,13 +57,13 @@
public int hashCode() {
return method.hashCode();
}
-
+
/** {@inheritDoc} */
public boolean equals(Object other) {
if (! (other instanceof MethodAnnotationStruct)) {
return false;
}
-
+
return method.equals(((MethodAnnotationStruct) other).method);
}
@@ -104,7 +104,7 @@
/**
* Gets the method this item is for.
- *
+ *
* @return {@code non-null;} the method
*/
public CstMethodRef getMethod() {
@@ -113,7 +113,7 @@
/**
* Gets the associated annotations.
- *
+ *
* @return {@code non-null;} the annotations
*/
public Annotations getAnnotations() {
diff --git a/dx/src/com/android/dx/dex/file/MethodIdItem.java b/dx/src/com/android/dx/dex/file/MethodIdItem.java
index bbd6c93..f2ff4f9 100644
--- a/dx/src/com/android/dx/dex/file/MethodIdItem.java
+++ b/dx/src/com/android/dx/dex/file/MethodIdItem.java
@@ -24,7 +24,7 @@
public final class MethodIdItem extends MemberIdItem {
/**
* Constructs an instance.
- *
+ *
* @param method {@code non-null;} the constant for the method
*/
public MethodIdItem(CstBaseMethodRef method) {
@@ -48,7 +48,7 @@
/**
* Gets the method constant.
- *
+ *
* @return {@code non-null;} the constant
*/
public CstBaseMethodRef getMethodRef() {
@@ -61,10 +61,10 @@
ProtoIdsSection protoIds = file.getProtoIds();
return protoIds.indexOf(getMethodRef().getPrototype());
}
-
+
/** {@inheritDoc} */
@Override
protected String getTypoidName() {
return "proto_idx";
- }
+ }
}
diff --git a/dx/src/com/android/dx/dex/file/MethodIdsSection.java b/dx/src/com/android/dx/dex/file/MethodIdsSection.java
index f3e7dee..fa0cd3c 100644
--- a/dx/src/com/android/dx/dex/file/MethodIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/MethodIdsSection.java
@@ -30,13 +30,13 @@
public final class MethodIdsSection extends MemberIdsSection {
/**
* {@code non-null;} map from method constants to {@link
- * MethodIdItem} instances
+ * MethodIdItem} instances
*/
private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds;
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public MethodIdsSection(DexFile file) {
@@ -71,7 +71,7 @@
/**
* Writes the portion of the file header that refers to this instance.
- *
+ *
* @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
@@ -91,7 +91,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param method {@code non-null;} the reference to intern
* @return {@code non-null;} the interned reference
*/
@@ -115,7 +115,7 @@
/**
* Gets the index of the given reference, which must have been added
* to this instance.
- *
+ *
* @param ref {@code non-null;} the reference to look up
* @return {@code >= 0;} the reference's index
*/
diff --git a/dx/src/com/android/dx/dex/file/MixedItemSection.java b/dx/src/com/android/dx/dex/file/MixedItemSection.java
index 0929fe7..b885306 100644
--- a/dx/src/com/android/dx/dex/file/MixedItemSection.java
+++ b/dx/src/com/android/dx/dex/file/MixedItemSection.java
@@ -34,7 +34,7 @@
* A section of a {@code .dex} file which consists of a sequence of
* {@link OffsettedItem} objects, which may each be of a different concrete
* class and/or size.
- *
+ *
* <b>Note:</b> It is invalid for an item in an instance of this class to
* have a larger alignment requirement than the alignment of this instance.
*/
@@ -59,7 +59,7 @@
return type1.compareTo(type2);
}
};
-
+
/** {@code non-null;} the items in this part */
private final ArrayList<OffsettedItem> items;
@@ -77,7 +77,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param name {@code null-ok;} the name of this instance, for annotation
* purposes
* @param file {@code non-null;} file that this instance is part of
@@ -117,7 +117,7 @@
/**
* Gets the size of this instance, in items.
- *
+ *
* @return {@code >= 0;} the size
*/
public int size() {
@@ -133,7 +133,7 @@
throwIfNotPrepared();
if (writeSize == -1) {
- throw new RuntimeException("write size not yet set");
+ throw new RuntimeException("write size not yet set");
}
int sz = writeSize;
@@ -163,7 +163,7 @@
* that it has been added to this instance. It is invalid to add the
* same item to more than one instance, nor to add the same items
* multiple times to a single instance.
- *
+ *
* @param item {@code non-null;} the item to add
*/
public void add(OffsettedItem item) {
@@ -186,7 +186,7 @@
* Interns an item in this instance, returning the interned instance
* (which may not be the one passed in). This will add the item if no
* equal item has been added.
- *
+ *
* @param item {@code non-null;} the item to intern
* @return {@code non-null;} the equivalent interned instance
*/
@@ -194,7 +194,7 @@
throwIfPrepared();
OffsettedItem result = interns.get(item);
-
+
if (result != null) {
return (T) result;
}
@@ -206,7 +206,7 @@
/**
* Gets an item which was previously interned.
- *
+ *
* @param item {@code non-null;} the item to look for
* @return {@code non-null;} the equivalent already-interned instance
*/
@@ -214,7 +214,7 @@
throwIfNotPrepared();
OffsettedItem result = interns.get(item);
-
+
if (result != null) {
return (T) result;
}
@@ -226,7 +226,7 @@
* Writes an index of contents of the items in this instance of the
* given type. If there are none, this writes nothing. If there are any,
* then the index is preceded by the given intro string.
- *
+ *
* @param out {@code non-null;} where to write to
* @param itemType {@code non-null;} the item type of interest
* @param intro {@code non-null;} the introductory string for non-empty indices
@@ -250,7 +250,7 @@
}
out.annotate(0, intro);
-
+
for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
String label = entry.getKey();
OffsettedItem item = entry.getValue();
diff --git a/dx/src/com/android/dx/dex/file/OffsettedItem.java b/dx/src/com/android/dx/dex/file/OffsettedItem.java
index c8e2d74..7721470 100644
--- a/dx/src/com/android/dx/dex/file/OffsettedItem.java
+++ b/dx/src/com/android/dx/dex/file/OffsettedItem.java
@@ -33,20 +33,20 @@
/**
* {@code null-ok;} section the item was added to, or {@code null} if
- * not yet added
+ * not yet added
*/
private Section addedTo;
/**
* {@code >= -1;} assigned offset of the item from the start of its section,
- * or {@code -1} if not yet assigned
+ * or {@code -1} if not yet assigned
*/
private int offset;
/**
* Gets the absolute offset of the given item, returning {@code 0}
* if handed {@code null}.
- *
+ *
* @param item {@code null-ok;} the item in question
* @return {@code >= 0;} the item's absolute offset, or {@code 0}
* if {@code item == null}
@@ -61,7 +61,7 @@
/**
* Constructs an instance. The offset is initially unassigned.
- *
+ *
* @param alignment {@code > 0;} output alignment requirement; must be a
* power of 2
* @param writeSize {@code >= -1;} the size of this instance when written,
@@ -82,7 +82,7 @@
/**
* {@inheritDoc}
- *
+ *
* Comparisons for this class are defined to be type-major (if the
* types don't match then the objects are not equal), with
* {@link #compareTo0} deciding same-type comparisons.
@@ -106,7 +106,7 @@
/**
* {@inheritDoc}
- *
+ *
* Comparisons for this class are defined to be class-major (if the
* classes don't match then the objects are not equal), with
* {@link #compareTo0} deciding same-class comparisons.
@@ -130,7 +130,7 @@
* Sets the write size of this item. This may only be called once
* per instance, and only if the size was unknown upon instance
* creation.
- *
+ *
* @param writeSize {@code > 0;} the write size, in bytes
*/
public final void setWriteSize(int writeSize) {
@@ -144,9 +144,9 @@
this.writeSize = writeSize;
}
-
- /** {@inheritDoc}
- *
+
+ /** {@inheritDoc}
+ *
* @throws UnsupportedOperationException thrown if the write size
* is not yet known
*/
@@ -155,7 +155,7 @@
if (writeSize < 0) {
throw new UnsupportedOperationException("writeSize is unknown");
}
-
+
return writeSize;
}
@@ -181,7 +181,7 @@
/**
* Gets the relative item offset. The offset is from the start of
* the section which the instance was written to.
- *
+ *
* @return {@code >= 0;} the offset
* @throws RuntimeException thrown if the offset is not yet known
*/
@@ -196,7 +196,7 @@
/**
* Gets the absolute item offset. The offset is from the start of
* the file which the instance was written to.
- *
+ *
* @return {@code >= 0;} the offset
* @throws RuntimeException thrown if the offset is not yet known
*/
@@ -212,7 +212,7 @@
* Indicates that this item has been added to the given section at
* the given offset. It is only valid to call this method once per
* instance.
- *
+ *
* @param addedTo {@code non-null;} the section this instance has
* been added to
* @param offset {@code >= 0;} the desired offset from the start of the
@@ -247,7 +247,7 @@
/**
* Gets the alignment requirement of this instance. An instance should
* only be written when so aligned.
- *
+ *
* @return {@code > 0;} the alignment requirement; must be a power of 2
*/
public final int getAlignment() {
@@ -257,7 +257,7 @@
/**
* Gets the absolute offset of this item as a string, suitable for
* including in annotations.
- *
+ *
* @return {@code non-null;} the offset string
*/
public final String offsetString() {
@@ -266,7 +266,7 @@
/**
* Gets a short human-readable string representing this instance.
- *
+ *
* @return {@code non-null;} the human form
*/
public abstract String toHuman();
@@ -277,7 +277,7 @@
* throw an exception (unsupported operation). If a particular
* class needs to actually sort, then it should override this
* method.
- *
+ *
* @param other {@code non-null;} instance to compare to
* @return {@code -1}, {@code 0}, or {@code 1}, depending
* on the sort order of this instance and the other
@@ -293,7 +293,7 @@
* override this method. In particular, if this instance did not
* know its write size up-front, then this method is responsible
* for setting it.
- *
+ *
* @param addedTo {@code non-null;} the section this instance has been added to
* @param offset {@code >= 0;} the offset from the start of the
* section where this instance was placed
@@ -306,7 +306,7 @@
* Performs the actual write of the contents of this instance to
* the given data section. This is called by {@link #writeTo},
* which will have taken care of ensuring alignment.
- *
+ *
* @param file {@code non-null;} the file to use for reference
* @param out {@code non-null;} where to write to
*/
diff --git a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
index 46d0450..078c219 100644
--- a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
+++ b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
@@ -41,7 +41,7 @@
/**
* Constructs an instance.
- *
+ *
* @param method {@code non-null;} the method in question
* @param annotationsList {@code non-null;} the associated annotations list
*/
@@ -72,7 +72,7 @@
AnnotationSetItem item = new AnnotationSetItem(annotations);
arrayList.add(new AnnotationSetRefItem(item));
}
-
+
this.annotationsItem = new UniformListItem<AnnotationSetRefItem>(
ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList);
}
@@ -81,13 +81,13 @@
public int hashCode() {
return method.hashCode();
}
-
+
/** {@inheritDoc} */
public boolean equals(Object other) {
if (! (other instanceof ParameterAnnotationStruct)) {
return false;
}
-
+
return method.equals(((ParameterAnnotationStruct) other).method);
}
@@ -143,7 +143,7 @@
/**
* Gets the method this item is for.
- *
+ *
* @return {@code non-null;} the method
*/
public CstMethodRef getMethod() {
@@ -152,7 +152,7 @@
/**
* Gets the associated annotations list.
- *
+ *
* @return {@code non-null;} the annotations list
*/
public AnnotationsList getAnnotationsList() {
diff --git a/dx/src/com/android/dx/dex/file/ProtoIdItem.java b/dx/src/com/android/dx/dex/file/ProtoIdItem.java
index afc227c..31cf8fb 100644
--- a/dx/src/com/android/dx/dex/file/ProtoIdItem.java
+++ b/dx/src/com/android/dx/dex/file/ProtoIdItem.java
@@ -45,7 +45,7 @@
/**
* Constructs an instance.
- *
+ *
* @param prototype {@code non-null;} the constant for the prototype
*/
public ProtoIdItem(Prototype prototype) {
@@ -57,13 +57,13 @@
this.shortForm = makeShortForm(prototype);
StdTypeList parameters = prototype.getParameterTypes();
- this.parameterTypes = (parameters.size() == 0) ? null
+ this.parameterTypes = (parameters.size() == 0) ? null
: new TypeListItem(parameters);
}
/**
* Creates the short-form of the given prototype.
- *
+ *
* @param prototype {@code non-null;} the prototype
* @return {@code non-null;} the short form
*/
@@ -83,7 +83,7 @@
/**
* Gets the short-form character for the given type.
- *
+ *
* @param type {@code non-null;} the type
* @return the corresponding short-form character
*/
@@ -130,7 +130,7 @@
int shortyIdx = file.getStringIds().indexOf(shortForm);
int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType());
int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes);
-
+
if (out.annotates()) {
StringBuilder sb = new StringBuilder();
sb.append(prototype.getReturnType().toHuman());
@@ -145,7 +145,7 @@
}
sb.append(params.getType(i).toHuman());
}
-
+
sb.append(")");
out.annotate(0, indexString() + ' ' + sb.toString());
out.annotate(4, " shorty_idx: " + Hex.u4(shortyIdx) +
diff --git a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
index 8a95434..dc6e8ad 100644
--- a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
@@ -36,7 +36,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public ProtoIdsSection(DexFile file) {
@@ -59,7 +59,7 @@
/**
* Writes the portion of the file header that refers to this instance.
- *
+ *
* @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
@@ -83,7 +83,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param prototype {@code non-null;} the prototype to intern
* @return {@code non-null;} the interned reference
*/
@@ -107,7 +107,7 @@
/**
* Gets the index of the given prototype, which must have
* been added to this instance.
- *
+ *
* @param prototype {@code non-null;} the prototype to look up
* @return {@code >= 0;} the reference's index
*/
diff --git a/dx/src/com/android/dx/dex/file/Section.java b/dx/src/com/android/dx/dex/file/Section.java
index f5b43af..3f04216 100644
--- a/dx/src/com/android/dx/dex/file/Section.java
+++ b/dx/src/com/android/dx/dex/file/Section.java
@@ -45,7 +45,7 @@
/**
* Validates an alignment.
- *
+ *
* @param alignment the alignment
* @throws IllegalArgumentException thrown if {@code alignment}
* isn't a positive power of 2
@@ -89,9 +89,9 @@
return file;
}
- /**
+ /**
* Gets the alignment for this instance's final output.
- *
+ *
* @return {@code > 0;} the alignment
*/
public final int getAlignment() {
@@ -144,7 +144,7 @@
* @param out {@code non-null;} where to write to
*/
public final void writeTo(AnnotatedOutput out) {
- throwIfNotPrepared();
+ throwIfNotPrepared();
align(out);
int cursor = out.getCursor();
@@ -173,7 +173,7 @@
* start of this instance's output. This is only valid to call
* once this instance has been assigned a file offset (via {@link
* #setFileOffset}).
- *
+ *
* @param relative {@code >= 0;} the relative offset
* @return {@code >= 0;} the corresponding absolute file offset
*/
@@ -194,10 +194,10 @@
* be contained in this section. This is only valid to call
* once this instance has been assigned a file offset (via {@link
* #setFileOffset}).
- *
+ *
* <p><b>Note:</b> Subclasses must implement this as appropriate for
* their contents.</p>
- *
+ *
* @param item {@code non-null;} the item in question
* @return {@code >= 0;} the item's absolute file offset
*/
@@ -257,7 +257,7 @@
/**
* Aligns the output of the given data to the alignment of this instance.
- *
+ *
* @param out {@code non-null;} the output to align
*/
protected final void align(AnnotatedOutput out) {
@@ -271,14 +271,14 @@
* offset matches the actual cursor {@code out} or that the
* file offset was not previously assigned, in which case it gets
* assigned to {@code out}'s cursor.
- *
+ *
* @param out {@code non-null;} where to write to
*/
protected abstract void writeTo0(AnnotatedOutput out);
/**
* Returns the name of this section, for annotation purposes.
- *
+ *
* @return {@code null-ok;} name of this part, for annotation purposes
*/
protected final String getName() {
diff --git a/dx/src/com/android/dx/dex/file/Statistics.java b/dx/src/com/android/dx/dex/file/Statistics.java
index 9a2efb3..62e1832 100644
--- a/dx/src/com/android/dx/dex/file/Statistics.java
+++ b/dx/src/com/android/dx/dex/file/Statistics.java
@@ -38,7 +38,7 @@
/**
* Adds the given item to the statistics.
- *
+ *
* @param item {@code non-null;} the item to add
*/
public void add(Item item) {
@@ -54,7 +54,7 @@
/**
* Adds the given list of items to the statistics.
- *
+ *
* @param list {@code non-null;} the list of items to add
*/
public void addAll(Section list) {
@@ -66,7 +66,7 @@
/**
* Writes the statistics as an annotation.
- *
+ *
* @param out {@code non-null;} where to write to
*/
public final void writeAnnotation(AnnotatedOutput out) {
@@ -126,7 +126,7 @@
/**
* Constructs an instance for the given item.
- *
+ *
* @param item {@code non-null;} item in question
* @param name {@code non-null;} type name to use
*/
@@ -142,7 +142,7 @@
/**
* Incorporates a new item. This assumes the type name matches.
- *
+ *
* @param item {@code non-null;} item to incorporate
*/
public void add(Item item) {
@@ -162,7 +162,7 @@
/**
* Writes this instance as an annotation.
- *
+ *
* @param out {@code non-null;} where to write to
*/
public void writeAnnotation(AnnotatedOutput out) {
diff --git a/dx/src/com/android/dx/dex/file/StringDataItem.java b/dx/src/com/android/dx/dex/file/StringDataItem.java
index b9eeb9b..80dbced 100644
--- a/dx/src/com/android/dx/dex/file/StringDataItem.java
+++ b/dx/src/com/android/dx/dex/file/StringDataItem.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param value {@code non-null;} the string value
*/
public StringDataItem(CstUtf8 value) {
@@ -42,13 +42,13 @@
/**
* Gets the write size for a given value.
- *
+ *
* @param value {@code non-null;} the string value
* @return {@code >= 2}; the write size, in bytes
*/
private static int writeSize(CstUtf8 value) {
int utf16Size = value.getUtf16Size();
-
+
// The +1 is for the '\0' termination byte.
return Leb128Utils.unsignedLeb128Size(utf16Size)
+ value.getUtf8Size() + 1;
@@ -73,7 +73,7 @@
int utf16Size = value.getUtf16Size();
if (out.annotates()) {
- out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size),
+ out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size),
"utf16_size: " + Hex.u4(utf16Size));
out.annotate(bytes.size() + 1, value.toQuoted());
}
diff --git a/dx/src/com/android/dx/dex/file/StringIdItem.java b/dx/src/com/android/dx/dex/file/StringIdItem.java
index 401a0be..cd0d57b 100644
--- a/dx/src/com/android/dx/dex/file/StringIdItem.java
+++ b/dx/src/com/android/dx/dex/file/StringIdItem.java
@@ -36,7 +36,7 @@
/**
* Constructs an instance.
- *
+ *
* @param value {@code non-null;} the string value
*/
public StringIdItem(CstUtf8 value) {
@@ -109,7 +109,7 @@
/**
* Gets the string value.
- *
+ *
* @return {@code non-null;} the value
*/
public CstUtf8 getValue() {
@@ -118,7 +118,7 @@
/**
* Gets the associated data object for this instance, if known.
- *
+ *
* @return {@code null-ok;} the associated data object or {@code null}
* if not yet known
*/
diff --git a/dx/src/com/android/dx/dex/file/StringIdsSection.java b/dx/src/com/android/dx/dex/file/StringIdsSection.java
index b2e8683..9039f43 100644
--- a/dx/src/com/android/dx/dex/file/StringIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/StringIdsSection.java
@@ -33,13 +33,13 @@
extends UniformItemSection {
/**
* {@code non-null;} map from string constants to {@link
- * StringIdItem} instances
+ * StringIdItem} instances
*/
private final TreeMap<CstUtf8, StringIdItem> strings;
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public StringIdsSection(DexFile file) {
@@ -78,7 +78,7 @@
/**
* Writes the portion of the file header that refers to this instance.
- *
+ *
* @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
@@ -98,7 +98,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param string {@code non-null;} the string to intern, as a regular Java
* {@code String}
* @return {@code non-null;} the interned string
@@ -110,7 +110,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param string {@code non-null;} the string to intern, as a {@link CstString}
* @return {@code non-null;} the interned string
*/
@@ -121,7 +121,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param string {@code non-null;} the string to intern, as a constant
* @return {@code non-null;} the interned string
*/
@@ -131,7 +131,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param string {@code non-null;} the string to intern
* @return {@code non-null;} the interned string
*/
@@ -155,7 +155,7 @@
/**
* Interns the components of a name-and-type into this instance.
- *
+ *
* @param nat {@code non-null;} the name-and-type
*/
public void intern(CstNat nat) {
@@ -166,7 +166,7 @@
/**
* Gets the index of the given string, which must have been added
* to this instance.
- *
+ *
* @param string {@code non-null;} the string to look up
* @return {@code >= 0;} the string's index
*/
@@ -189,7 +189,7 @@
/**
* Gets the index of the given string, which must have been added
* to this instance.
- *
+ *
* @param string {@code non-null;} the string to look up
* @return {@code >= 0;} the string's index
*/
diff --git a/dx/src/com/android/dx/dex/file/TypeIdItem.java b/dx/src/com/android/dx/dex/file/TypeIdItem.java
index 01b1417..c257e00 100644
--- a/dx/src/com/android/dx/dex/file/TypeIdItem.java
+++ b/dx/src/com/android/dx/dex/file/TypeIdItem.java
@@ -30,7 +30,7 @@
/**
* Constructs an instance.
- *
+ *
* @param type {@code non-null;} the constant for the type
*/
public TypeIdItem(CstType type) {
diff --git a/dx/src/com/android/dx/dex/file/TypeIdsSection.java b/dx/src/com/android/dx/dex/file/TypeIdsSection.java
index b1b9c58..bcc8250 100644
--- a/dx/src/com/android/dx/dex/file/TypeIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/TypeIdsSection.java
@@ -36,7 +36,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param file {@code non-null;} file that this instance is part of
*/
public TypeIdsSection(DexFile file) {
@@ -72,7 +72,7 @@
/**
* Writes the portion of the file header that refers to this instance.
- *
+ *
* @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
@@ -96,7 +96,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param type {@code non-null;} the type to intern
* @return {@code non-null;} the interned reference
*/
@@ -119,7 +119,7 @@
/**
* Interns an element into this instance.
- *
+ *
* @param type {@code non-null;} the type to intern
* @return {@code non-null;} the interned reference
*/
@@ -144,7 +144,7 @@
/**
* Gets the index of the given type, which must have
* been added to this instance.
- *
+ *
* @param type {@code non-null;} the type to look up
* @return {@code >= 0;} the reference's index
*/
@@ -167,7 +167,7 @@
/**
* Gets the index of the given type, which must have
* been added to this instance.
- *
+ *
* @param type {@code non-null;} the type to look up
* @return {@code >= 0;} the reference's index
*/
diff --git a/dx/src/com/android/dx/dex/file/TypeListItem.java b/dx/src/com/android/dx/dex/file/TypeListItem.java
index 3278aef..b815dd3 100644
--- a/dx/src/com/android/dx/dex/file/TypeListItem.java
+++ b/dx/src/com/android/dx/dex/file/TypeListItem.java
@@ -41,7 +41,7 @@
/**
* Constructs an instance.
- *
+ *
* @param list {@code non-null;} the actual list
*/
public TypeListItem(TypeList list) {
@@ -80,7 +80,7 @@
/**
* Gets the underlying list.
- *
+ *
* @return {@code non-null;} the list
*/
public TypeList getList() {
@@ -109,7 +109,7 @@
for (int i = 0; i < sz; i++) {
out.writeShort(typeIds.indexOf(list.getType(i)));
}
- }
+ }
/** {@inheritDoc} */
@Override
diff --git a/dx/src/com/android/dx/dex/file/UniformItemSection.java b/dx/src/com/android/dx/dex/file/UniformItemSection.java
index e182438..d8c09ab 100644
--- a/dx/src/com/android/dx/dex/file/UniformItemSection.java
+++ b/dx/src/com/android/dx/dex/file/UniformItemSection.java
@@ -29,7 +29,7 @@
public abstract class UniformItemSection extends Section {
/**
* Constructs an instance. The file offset is initially unknown.
- *
+ *
* @param name {@code null-ok;} the name of this instance, for annotation
* purposes
* @param file {@code non-null;} file that this instance is part of
@@ -59,7 +59,7 @@
* will throw an exception if the constant is not found, including
* if this instance isn't the sort that maps constants to {@link
* IndexedItem} instances.
- *
+ *
* @param cst {@code non-null;} constant to look for
* @return {@code non-null;} the corresponding item found in this instance
*/
diff --git a/dx/src/com/android/dx/dex/file/UniformListItem.java b/dx/src/com/android/dx/dex/file/UniformListItem.java
index 3c1f4d3..88919c7 100644
--- a/dx/src/com/android/dx/dex/file/UniformListItem.java
+++ b/dx/src/com/android/dx/dex/file/UniformListItem.java
@@ -26,12 +26,12 @@
* Class that represents a contiguous list of uniform items. Each
* item in the list, in particular, must have the same write size and
* alignment.
- *
+ *
* <p>This class inherits its alignment from its items, bumped up to
* {@code 4} if the items have a looser alignment requirement. If
* it is more than {@code 4}, then there will be a gap after the
* output list size (which is four bytes) and before the first item.</p>
- *
+ *
* @param <T> type of element contained in an instance
*/
public final class UniformListItem<T extends OffsettedItem>
@@ -41,14 +41,14 @@
/** {@code non-null;} the item type */
private final ItemType itemType;
-
+
/** {@code non-null;} the contents */
private final List<T> items;
/**
* Constructs an instance. It is illegal to modify the given list once
* it is used to construct an instance of this class.
- *
+ *
* @param itemType {@code non-null;} the type of the item
* @param items {@code non-null and non-empty;} list of items to represent
*/
@@ -67,7 +67,7 @@
* Helper for {@link #UniformListItem}, which returns the alignment
* requirement implied by the given list. See the header comment for
* more details.
- *
+ *
* @param items {@code non-null;} list of items being represented
* @return {@code >= 4;} the alignment requirement
*/
@@ -81,12 +81,12 @@
} catch (NullPointerException ex) {
// Translate the exception.
throw new NullPointerException("items == null");
- }
+ }
}
/**
* Calculates the write size for the given list.
- *
+ *
* @param items {@code non-null;} the list in question
* @return {@code >= 0;} the write size
*/
@@ -147,7 +147,7 @@
/**
* Gets the underlying list of items.
- *
+ *
* @return {@code non-null;} the list
*/
public final List<T> getItems() {
@@ -179,7 +179,7 @@
"item alignment mismatch");
}
}
-
+
offset = i.place(addedTo, offset) + size;
}
}
@@ -203,7 +203,7 @@
/**
* Get the size of the header of this list.
- *
+ *
* @return {@code >= 0;} the header size
*/
private int headerSize() {
diff --git a/dx/src/com/android/dx/dex/file/ValueEncoder.java b/dx/src/com/android/dx/dex/file/ValueEncoder.java
index f7e364a..fba64a7 100644
--- a/dx/src/com/android/dx/dex/file/ValueEncoder.java
+++ b/dx/src/com/android/dx/dex/file/ValueEncoder.java
@@ -100,10 +100,10 @@
/** {@code non-null;} output stream to write to */
private final AnnotatedOutput out;
-
+
/**
* Construct an instance.
- *
+ *
* @param file {@code non-null;} file being written
* @param out {@code non-null;} output stream to write to
*/
@@ -122,7 +122,7 @@
/**
* Writes out the encoded form of the given constant.
- *
+ *
* @param cst {@code non-null;} the constant to write
*/
public void writeConstant(Constant cst) {
@@ -208,7 +208,7 @@
/**
* Gets the value type for the given constant.
- *
+ *
* @param cst {@code non-null;} the constant
* @return the value type; one of the {@code VALUE_*} constants
* defined by this class
@@ -276,7 +276,7 @@
if (annotates) {
out.annotate(" size: " + Hex.u4(size));
}
-
+
out.writeUnsignedLeb128(size);
for (int i = 0; i < size; i++) {
@@ -300,7 +300,7 @@
* (debugging) annotations and {@code topLevel} is
* {@code true}, then this method will write (debugging)
* annotations.
- *
+ *
* @param annotation {@code non-null;} annotation instance to write
* @param topLevel {@code true} iff the given annotation is the
* top-level annotation or {@code false} if it is a sub-annotation
@@ -318,7 +318,7 @@
out.annotate(" type_idx: " + Hex.u4(typeIdx) + " // " +
type.toHuman());
}
-
+
out.writeUnsignedLeb128(typeIds.indexOf(annotation.getType()));
Collection<NameValuePair> pairs = annotation.getNameValuePairs();
@@ -335,7 +335,7 @@
CstUtf8 name = pair.getName();
int nameIdx = stringIds.indexOf(name);
Constant value = pair.getValue();
-
+
if (annotates) {
out.annotate(0, " elements[" + at + "]:");
at++;
@@ -356,11 +356,11 @@
out.endAnnotation();
}
}
-
+
/**
* Gets the colloquial type name and human form of the type of the
* given constant, when used as an encoded value.
- *
+ *
* @param cst {@code non-null;} the constant
* @return {@code non-null;} its type name and human form
*/
@@ -383,7 +383,7 @@
/**
* Helper for {@link #writeConstant}, which writes out the value
* for any signed integral type.
- *
+ *
* @param type the type constant
* @param value {@code long} bits of the value
*/
@@ -420,7 +420,7 @@
/**
* Helper for {@link #writeConstant}, which writes out the value
* for any unsigned integral type.
- *
+ *
* @param type the type constant
* @param value {@code long} bits of the value
*/
@@ -430,7 +430,7 @@
if (requiredBits == 0) {
requiredBits = 1;
}
-
+
// Round up the requiredBits to a number of bytes.
int requiredBytes = (requiredBits + 0x07) >> 3;
@@ -451,7 +451,7 @@
/**
* Helper for {@link #writeConstant}, which writes out a
* right-zero-extended value.
- *
+ *
* @param type the type constant
* @param value {@code long} bits of the value
*/
@@ -461,7 +461,7 @@
if (requiredBits == 0) {
requiredBits = 1;
}
-
+
// Round up the requiredBits to a number of bytes.
int requiredBytes = (requiredBits + 0x07) >> 3;
@@ -488,7 +488,7 @@
* contents for a particular {@link Annotation}, calling itself
* recursively should it encounter a nested annotation.
*
- * @param file {@code non-null;} the file to add to
+ * @param file {@code non-null;} the file to add to
* @param annotation {@code non-null;} the annotation to add contents for
*/
public static void addContents(DexFile file, Annotation annotation) {
@@ -496,7 +496,7 @@
StringIdsSection stringIds = file.getStringIds();
typeIds.intern(annotation.getType());
-
+
for (NameValuePair pair : annotation.getNameValuePairs()) {
stringIds.intern(pair.getName());
addContents(file, pair.getValue());
@@ -509,8 +509,8 @@
* should it encounter a {@link CstArray} and calling {@link
* #addContents(DexFile,Annotation)} recursively should it
* encounter a {@link CstAnnotation}.
- *
- * @param file {@code non-null;} the file to add to
+ *
+ * @param file {@code non-null;} the file to add to
* @param cst {@code non-null;} the constant to add contents for
*/
public static void addContents(DexFile file, Constant cst) {
diff --git a/dx/src/com/android/dx/rop/annotation/Annotation.java b/dx/src/com/android/dx/rop/annotation/Annotation.java
index 6154c61..ad6d67e 100644
--- a/dx/src/com/android/dx/rop/annotation/Annotation.java
+++ b/dx/src/com/android/dx/rop/annotation/Annotation.java
@@ -39,7 +39,7 @@
* associated type and additionally consist of a set of (name, value)
* pairs, where the names are unique.
*/
-public final class Annotation extends MutabilityControl
+public final class Annotation extends MutabilityControl
implements Comparable<Annotation>, ToHuman {
/** {@code non-null;} type of the annotation */
private final CstType type;
@@ -49,10 +49,10 @@
/** {@code non-null;} map from names to {@link NameValuePair} instances */
private final TreeMap<CstUtf8, NameValuePair> elements;
-
+
/**
* Construct an instance. It initially contains no elements.
- *
+ *
* @param type {@code non-null;} type of the annotation
* @param visibility {@code non-null;} the visibility of the annotation
*/
@@ -136,7 +136,7 @@
public String toString() {
return toHuman();
}
-
+
/** {@inheritDoc} */
public String toHuman() {
StringBuilder sb = new StringBuilder();
@@ -164,7 +164,7 @@
/**
* Gets the type of this instance.
- *
+ *
* @return {@code non-null;} the type
*/
public CstType getType() {
@@ -173,7 +173,7 @@
/**
* Gets the visibility of this instance.
- *
+ *
* @return {@code non-null;} the visibility
*/
public AnnotationVisibility getVisibility() {
@@ -184,12 +184,12 @@
* Put an element into the set of (name, value) pairs for this instance.
* If there is a preexisting element with the same name, it will be
* replaced by this method.
- *
+ *
* @param pair {@code non-null;} the (name, value) pair to place into this instance
*/
public void put(NameValuePair pair) {
throwIfImmutable();
-
+
if (pair == null) {
throw new NullPointerException("pair == null");
}
@@ -201,12 +201,12 @@
* Add an element to the set of (name, value) pairs for this instance.
* It is an error to call this method if there is a preexisting element
* with the same name.
- *
+ *
* @param pair {@code non-null;} the (name, value) pair to add to this instance
*/
public void add(NameValuePair pair) {
throwIfImmutable();
-
+
if (pair == null) {
throw new NullPointerException("pair == null");
}
@@ -216,14 +216,14 @@
if (elements.get(name) != null) {
throw new IllegalArgumentException("name already added: " + name);
}
-
+
elements.put(name, pair);
}
/**
* Gets the set of name-value pairs contained in this instance. The
* result is always unmodifiable.
- *
+ *
* @return {@code non-null;} the set of name-value pairs
*/
public Collection<NameValuePair> getNameValuePairs() {
diff --git a/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java b/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
index 26246bb..c717b8c 100644
--- a/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
+++ b/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
@@ -32,7 +32,7 @@
/**
* Constructs an instance.
- *
+ *
* @param human {@code non-null;} the human-oriented string representation
*/
private AnnotationVisibility(String human) {
diff --git a/dx/src/com/android/dx/rop/annotation/Annotations.java b/dx/src/com/android/dx/rop/annotation/Annotations.java
index dcb74a1..807d5d4 100644
--- a/dx/src/com/android/dx/rop/annotation/Annotations.java
+++ b/dx/src/com/android/dx/rop/annotation/Annotations.java
@@ -27,7 +27,7 @@
/**
* List of {@link Annotation} instances.
*/
-public final class Annotations extends MutabilityControl
+public final class Annotations extends MutabilityControl
implements Comparable<Annotations> {
/** {@code non-null;} immutable empty instance */
public static final Annotations EMPTY = new Annotations();
@@ -35,7 +35,7 @@
static {
EMPTY.setImmutable();
}
-
+
/** {@code non-null;} map from types to annotations */
private final TreeMap<CstType, Annotation> annotations;
@@ -43,7 +43,7 @@
* Constructs an immutable instance which is the combination of the
* two given instances. The two instances must contain disjoint sets
* of types.
- *
+ *
* @param a1 {@code non-null;} an instance
* @param a2 {@code non-null;} the other instance
* @return {@code non-null;} the combination
@@ -58,12 +58,12 @@
return result;
}
-
+
/**
* Constructs an immutable instance which is the combination of the
* given instance with the given additional annotation. The latter's
* type must not already appear in the former.
- *
+ *
* @param annotations {@code non-null;} the instance to augment
* @param annotation {@code non-null;} the additional annotation
* @return {@code non-null;} the combination
@@ -79,7 +79,7 @@
return result;
}
-
+
/**
* Constructs an empty instance.
*/
@@ -148,10 +148,10 @@
sb.append("}");
return sb.toString();
}
-
+
/**
* Gets the number of elements in this instance.
- *
+ *
* @return {@code >= 0;} the size
*/
public int size() {
@@ -161,7 +161,7 @@
/**
* Adds an element to this instance. There must not already be an
* element of the same type.
- *
+ *
* @param annotation {@code non-null;} the element to add
* @throws IllegalArgumentException thrown if there is a duplicate type
*/
@@ -173,7 +173,7 @@
}
CstType type = annotation.getType();
-
+
if (annotations.containsKey(type)) {
throw new IllegalArgumentException("duplicate type: " +
type.toHuman());
@@ -185,7 +185,7 @@
/**
* Adds all of the elements of the given instance to this one. The
* instances must not have any duplicate types.
- *
+ *
* @param toAdd {@code non-null;} the annotations to add
* @throws IllegalArgumentException thrown if there is a duplicate type
*/
@@ -204,7 +204,7 @@
/**
* Gets the set of annotations contained in this instance. The
* result is always unmodifiable.
- *
+ *
* @return {@code non-null;} the set of annotations
*/
public Collection<Annotation> getAnnotations() {
diff --git a/dx/src/com/android/dx/rop/annotation/AnnotationsList.java b/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
index 0f4207b..b97b385 100644
--- a/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
+++ b/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
@@ -25,13 +25,13 @@
extends FixedSizeList {
/** {@code non-null;} immutable empty instance */
public static final AnnotationsList EMPTY = new AnnotationsList(0);
-
+
/**
* Constructs an immutable instance which is the combination of
* the two given instances. The two instances must each have the
* same number of elements, and each pair of elements must contain
* disjoint sets of types.
- *
+ *
* @param list1 {@code non-null;} an instance
* @param list2 {@code non-null;} the other instance
* @return {@code non-null;} the combination
@@ -58,7 +58,7 @@
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public AnnotationsList(int size) {
@@ -69,7 +69,7 @@
* Gets the element at the given index. It is an error to call
* this with the index for an element which was never set; if you
* do that, this will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @return {@code non-null;} element at that index
*/
@@ -80,7 +80,7 @@
/**
* Sets the element at the given index. The given element must be
* immutable.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @param a {@code null-ok;} the element to set at {@code n}
*/
diff --git a/dx/src/com/android/dx/rop/annotation/NameValuePair.java b/dx/src/com/android/dx/rop/annotation/NameValuePair.java
index 7137a60..39a9dfd 100644
--- a/dx/src/com/android/dx/rop/annotation/NameValuePair.java
+++ b/dx/src/com/android/dx/rop/annotation/NameValuePair.java
@@ -29,10 +29,10 @@
/** {@code non-null;} the value */
private final Constant value;
-
+
/**
* Construct an instance.
- *
+ *
* @param name {@code non-null;} the name
* @param value {@code non-null;} the value
*/
@@ -49,7 +49,7 @@
if (value instanceof CstUtf8) {
throw new IllegalArgumentException("bad value: " + value);
}
-
+
this.name = name;
this.value = value;
}
@@ -63,7 +63,7 @@
public int hashCode() {
return name.hashCode() * 31 + value.hashCode();
}
-
+
/** {@inheritDoc} */
public boolean equals(Object other) {
if (! (other instanceof NameValuePair)) {
@@ -78,7 +78,7 @@
/**
* {@inheritDoc}
- *
+ *
* <p>Instances of this class compare in name-major and value-minor
* order.</p>
*/
@@ -90,20 +90,20 @@
}
return value.compareTo(other.value);
- }
+ }
/**
* Gets the name.
- *
+ *
* @return {@code non-null;} the name
*/
public CstUtf8 getName() {
return name;
}
-
+
/**
* Gets the value.
- *
+ *
* @return {@code non-null;} the value
*/
public Constant getValue() {
diff --git a/dx/src/com/android/dx/rop/code/AccessFlags.java b/dx/src/com/android/dx/rop/code/AccessFlags.java
index b76b610..2d84fe8 100644
--- a/dx/src/com/android/dx/rop/code/AccessFlags.java
+++ b/dx/src/com/android/dx/rop/code/AccessFlags.java
@@ -51,7 +51,7 @@
/**
* class with new-style {@code invokespecial} for superclass
- * method access
+ * method access
*/
public static final int ACC_SUPER = 0x0020;
@@ -78,7 +78,7 @@
/**
* method with strict floating point ({@code strictfp})
- * behavior
+ * behavior
*/
public static final int ACC_STRICT = 0x0800;
@@ -90,7 +90,7 @@
/**
* class is an enumerated type; field is an element of an enumerated
- * type
+ * type
*/
public static final int ACC_ENUM = 0x4000;
@@ -145,7 +145,7 @@
/**
* Returns a human-oriented string representing the given access flags,
* as defined on classes (not fields or methods).
- *
+ *
* @param flags the flags
* @return {@code non-null;} human-oriented string
*/
@@ -156,7 +156,7 @@
/**
* Returns a human-oriented string representing the given access flags,
* as defined on inner classes.
- *
+ *
* @param flags the flags
* @return {@code non-null;} human-oriented string
*/
@@ -167,7 +167,7 @@
/**
* Returns a human-oriented string representing the given access flags,
* as defined on fields (not classes or methods).
- *
+ *
* @param flags the flags
* @return {@code non-null;} human-oriented string
*/
@@ -178,7 +178,7 @@
/**
* Returns a human-oriented string representing the given access flags,
* as defined on methods (not classes or fields).
- *
+ *
* @param flags the flags
* @return {@code non-null;} human-oriented string
*/
@@ -189,7 +189,7 @@
/**
* Returns whether the flag {@code ACC_PUBLIC} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_PUBLIC} flag
*/
@@ -200,7 +200,7 @@
/**
* Returns whether the flag {@code ACC_PROTECTED} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_PROTECTED} flag
*/
@@ -211,7 +211,7 @@
/**
* Returns whether the flag {@code ACC_PRIVATE} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_PRIVATE} flag
*/
@@ -222,18 +222,18 @@
/**
* Returns whether the flag {@code ACC_STATIC} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_STATIC} flag
*/
public static boolean isStatic(int flags) {
return (flags & ACC_STATIC) != 0;
}
-
+
/**
* Returns whether the flag {@code ACC_SYNCHRONIZED} is on in
* the given flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_SYNCHRONIZED} flag
*/
@@ -244,7 +244,7 @@
/**
* Returns whether the flag {@code ACC_ABSTRACT} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_ABSTRACT} flag
*/
@@ -255,7 +255,7 @@
/**
* Returns whether the flag {@code ACC_NATIVE} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_NATIVE} flag
*/
@@ -266,7 +266,7 @@
/**
* Returns whether the flag {@code ACC_ANNOTATION} is on in the given
* flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_ANNOTATION} flag
*/
@@ -277,7 +277,7 @@
/**
* Returns whether the flag {@code ACC_DECLARED_SYNCHRONIZED} is
* on in the given flags.
- *
+ *
* @param flags the flags to check
* @return the value of the {@code ACC_DECLARED_SYNCHRONIZED} flag
*/
@@ -288,7 +288,7 @@
/**
* Helper to return a human-oriented string representing the given
* access flags.
- *
+ *
* @param flags the defined flags
* @param mask mask for the "defined" bits
* @param what what the flags represent (one of {@code CONV_*})
diff --git a/dx/src/com/android/dx/rop/code/BasicBlock.java b/dx/src/com/android/dx/rop/code/BasicBlock.java
index 7bb2d9b..d6ee886 100644
--- a/dx/src/com/android/dx/rop/code/BasicBlock.java
+++ b/dx/src/com/android/dx/rop/code/BasicBlock.java
@@ -33,20 +33,20 @@
/**
* {@code non-null;} full list of successors that this block may
- * branch to
+ * branch to
*/
private final IntList successors;
/**
* {@code >= -1;} the primary / standard-flow / "default" successor, or
* {@code -1} if this block has no successors (that is, it
- * exits the function/method)
+ * exits the function/method)
*/
private final int primarySuccessor;
/**
* Constructs an instance. The predecessor set is set to {@code null}.
- *
+ *
* @param label {@code >= 0;} target label for this block
* @param insns {@code non-null;} list of instructions in this block
* @param successors {@code non-null;} full list of successors that this
@@ -114,7 +114,7 @@
/**
* {@inheritDoc}
- *
+ *
* Instances of this class compare by identity. That is,
* {@code x.equals(y)} is only true if {@code x == y}.
*/
@@ -125,7 +125,7 @@
/**
* {@inheritDoc}
- *
+ *
* Return the identity hashcode of this instance. This is proper,
* since instances of this class compare by identity (see {@link #equals}).
*/
@@ -136,7 +136,7 @@
/**
* Gets the target label of this block.
- *
+ *
* @return {@code >= 0;} the label
*/
public int getLabel() {
@@ -145,7 +145,7 @@
/**
* Gets the list of instructions inside this block.
- *
+ *
* @return {@code non-null;} the instruction list
*/
public InsnList getInsns() {
@@ -154,7 +154,7 @@
/**
* Gets the list of successors that this block may branch to.
- *
+ *
* @return {@code non-null;} the successors list
*/
public IntList getSuccessors() {
@@ -163,7 +163,7 @@
/**
* Gets the primary successor of this block.
- *
+ *
* @return {@code >= -1;} the primary successor, or {@code -1} if this
* block has no successors at all
*/
@@ -174,7 +174,7 @@
/**
* Gets the secondary successor of this block. It is only valid to call
* this method on blocks that have exactly two successors.
- *
+ *
* @return {@code >= 0;} the secondary successor
*/
public int getSecondarySuccessor() {
@@ -194,7 +194,7 @@
/**
* Gets the first instruction of this block. This is just a
* convenient shorthand for {@code getInsns().get(0)}.
- *
+ *
* @return {@code non-null;} the first instruction
*/
public Insn getFirstInsn() {
@@ -204,7 +204,7 @@
/**
* Gets the last instruction of this block. This is just a
* convenient shorthand for {@code getInsns().getLast()}.
- *
+ *
* @return {@code non-null;} the last instruction
*/
public Insn getLastInsn() {
@@ -214,7 +214,7 @@
/**
* Returns whether this block might throw an exception. This is
* just a convenient shorthand for {@code getLastInsn().canThrow()}.
- *
+ *
* @return {@code true} iff this block might throw an
* exception
*/
@@ -227,7 +227,7 @@
* This is just a shorthand for inspecting the last instruction in
* the block to see if it could throw, and if so, whether it in fact
* has any associated handlers.
- *
+ *
* @return {@code true} iff this block has any associated
* exception handlers
*/
@@ -255,7 +255,7 @@
* Returns an instance that is identical to this one, except that
* the registers in each instruction are offset by the given
* amount.
- *
+ *
* @param delta the amount to offset register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
diff --git a/dx/src/com/android/dx/rop/code/BasicBlockList.java b/dx/src/com/android/dx/rop/code/BasicBlockList.java
index 0627425..ea7b497 100644
--- a/dx/src/com/android/dx/rop/code/BasicBlockList.java
+++ b/dx/src/com/android/dx/rop/code/BasicBlockList.java
@@ -28,14 +28,14 @@
public final class BasicBlockList extends LabeledList {
/**
* {@code >= -1;} the count of registers required by this method or
- * {@code -1} if not yet calculated
+ * {@code -1} if not yet calculated
*/
private int regCount;
/**
* Constructs an instance. All indices initially contain {@code null},
* and the first-block label is initially {@code -1}.
- *
+ *
* @param size the size of the list
*/
public BasicBlockList(int size) {
@@ -46,7 +46,7 @@
/**
* Constructs a mutable copy for {@code getMutableCopy()}.
- *
+ *
* @param old block to copy
*/
private BasicBlockList (BasicBlockList old) {
@@ -59,7 +59,7 @@
* Gets the element at the given index. It is an error to call
* this with the index for an element which was never set; if you
* do that, this will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @return {@code non-null;} element at that index
*/
@@ -69,13 +69,13 @@
/**
* Sets the basic block at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @param bb {@code null-ok;} the element to set at {@code n}
*/
public void set(int n, BasicBlock bb) {
super.set(n, bb);
-
+
// Reset regCount, since it will need to be recalculated.
regCount = -1;
}
@@ -85,7 +85,7 @@
* the maximum of register-number-plus-category referred to by this
* instance's instructions (indirectly through {@link BasicBlock}
* instances).
- *
+ *
* @return {@code >= 0;} the register count
*/
public int getRegCount() {
@@ -101,7 +101,7 @@
/**
* Gets the total instruction count for this instance. This is the
* sum of the instruction counts of each block.
- *
+ *
* @return {@code >= 0;} the total instruction count
*/
public int getInstructionCount() {
@@ -168,7 +168,7 @@
/**
* Visits each instruction of each block in the list, in order.
- *
+ *
* @param visitor {@code non-null;} visitor to use
*/
public void forEachInsn(Insn.Visitor visitor) {
@@ -186,7 +186,7 @@
* the registers in each instruction are offset by the given
* amount. Mutability of the result is inherited from the
* original.
- *
+ *
* @param delta the amount to offset register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -223,7 +223,7 @@
* Otherwise, if the block has a primay successor, then that is
* the preferred successor. If the block has no successors, then
* this returns {@code null}.
- *
+ *
* @param block {@code non-null;} the block in question
* @return {@code null-ok;} the preferred successor, if any
*/
@@ -251,7 +251,7 @@
/**
* Compares the catches of two blocks for equality. This includes
* both the catch types and target labels.
- *
+ *
* @param block1 {@code non-null;} one block to compare
* @param block2 {@code non-null;} the other block to compare
* @return {@code true} if the two blocks' non-primary successors
@@ -283,7 +283,7 @@
*/
return false;
}
-
+
for (int i = 0; i < size; i++) {
int label1 = succ1.get(i);
int label2 = succ2.get(i);
@@ -325,7 +325,7 @@
/**
* Gets the register count.
- *
+ *
* @return {@code >= 0;} the count
*/
public int getRegCount() {
@@ -364,7 +364,7 @@
/**
* Helper for all the {@code visit*} methods.
- *
+ *
* @param insn {@code non-null;} instruction being visited
*/
private void visit(Insn insn) {
@@ -384,7 +384,7 @@
/**
* Processes the given register spec.
- *
+ *
* @param spec {@code non-null;} the register spec
*/
private void processReg(RegisterSpec spec) {
@@ -394,5 +394,5 @@
regCount = reg;
}
}
- }
+ }
}
diff --git a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
index 1ecf02c..6c48acf 100644
--- a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
+++ b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
@@ -32,7 +32,7 @@
private ConservativeTranslationAdvice() {
// This space intentionally left blank.
}
-
+
/** {@inheritDoc} */
public boolean hasConstantOperation(Rop opcode,
RegisterSpec sourceA, RegisterSpec sourceB) {
diff --git a/dx/src/com/android/dx/rop/code/CstInsn.java b/dx/src/com/android/dx/rop/code/CstInsn.java
index 26df1a9..d7de2f4 100644
--- a/dx/src/com/android/dx/rop/code/CstInsn.java
+++ b/dx/src/com/android/dx/rop/code/CstInsn.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param result {@code null-ok;} spec for the result, if any
@@ -54,7 +54,7 @@
/**
* Gets the constant.
- *
+ *
* @return {@code non-null;} the constant
*/
public Constant getConstant() {
diff --git a/dx/src/com/android/dx/rop/code/Exceptions.java b/dx/src/com/android/dx/rop/code/Exceptions.java
index f99a760..1e27a8c 100644
--- a/dx/src/com/android/dx/rop/code/Exceptions.java
+++ b/dx/src/com/android/dx/rop/code/Exceptions.java
@@ -29,7 +29,7 @@
/**
* {@code non-null;} the type
- * {@code java.lang.ArrayIndexOutOfBoundsException}
+ * {@code java.lang.ArrayIndexOutOfBoundsException}
*/
public static final Type TYPE_ArrayIndexOutOfBoundsException =
Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;");
@@ -47,7 +47,7 @@
/**
* {@code non-null;} the type
- * {@code java.lang.IllegalMonitorStateException}
+ * {@code java.lang.IllegalMonitorStateException}
*/
public static final Type TYPE_IllegalMonitorStateException =
Type.intern("Ljava/lang/IllegalMonitorStateException;");
@@ -79,7 +79,7 @@
/**
* {@code non-null;} the list {@code [java.lang.Error,
- * java.lang.NegativeArraySizeException]}
+ * java.lang.NegativeArraySizeException]}
*/
public static final StdTypeList LIST_Error_NegativeArraySizeException =
StdTypeList.make(TYPE_Error, TYPE_NegativeArraySizeException);
diff --git a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
index 0fc7d2b..ed9345d 100644
--- a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
+++ b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
@@ -41,7 +41,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param sources {@code non-null;} specs for all the sources
diff --git a/dx/src/com/android/dx/rop/code/Insn.java b/dx/src/com/android/dx/rop/code/Insn.java
index 77ab9c0..dad2852 100644
--- a/dx/src/com/android/dx/rop/code/Insn.java
+++ b/dx/src/com/android/dx/rop/code/Insn.java
@@ -44,7 +44,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param result {@code null-ok;} spec for the result, if any
@@ -72,7 +72,7 @@
/**
* {@inheritDoc}
- *
+ *
* Instances of this class compare by identity. That is,
* {@code x.equals(y)} is only true if {@code x == y}.
*/
@@ -83,7 +83,7 @@
/**
* {@inheritDoc}
- *
+ *
* This implementation returns the identity hashcode of this
* instance. This is proper, since instances of this class compare
* by identity (see {@link #equals}).
@@ -101,7 +101,7 @@
/**
* Gets a human-oriented (and slightly lossy) string for this instance.
- *
+ *
* @return {@code non-null;} the human string form
*/
public String toHuman() {
@@ -111,7 +111,7 @@
/**
* Gets an "inline" string portion for toHuman(), if available. This
* is the portion that appears after the Rop opcode
- *
+ *
* @return {@code null-ok;} if non-null, the inline text for toHuman()
*/
public String getInlineString() {
@@ -120,7 +120,7 @@
/**
* Gets the opcode.
- *
+ *
* @return {@code non-null;} the opcode
*/
public final Rop getOpcode() {
@@ -129,7 +129,7 @@
/**
* Gets the source position.
- *
+ *
* @return {@code non-null;} the source position
*/
public final SourcePosition getPosition() {
@@ -139,7 +139,7 @@
/**
* Gets the result spec, if any. A return value of {@code null}
* means this instruction returns nothing.
- *
+ *
* @return {@code null-ok;} the result spec, if any
*/
public final RegisterSpec getResult() {
@@ -151,7 +151,7 @@
* instruction, or null if no local variable assignment occurs. This
* may be the result register, or for {@code mark-local} insns
* it may be the source.
- *
+ *
* @return {@code null-ok;} a named register spec or null
*/
public final RegisterSpec getLocalAssignment() {
@@ -177,7 +177,7 @@
/**
* Gets the source specs.
- *
+ *
* @return {@code non-null;} the source specs
*/
public final RegisterSpecList getSources() {
@@ -187,7 +187,7 @@
/**
* Gets whether this instruction can possibly throw an exception. This
* is just a convenient wrapper for {@code getOpcode().canThrow()}.
- *
+ *
* @return {@code true} iff this instruction can possibly throw
*/
public final boolean canThrow() {
@@ -201,7 +201,7 @@
* throw or if it merely doesn't handle any of its possible
* exceptions. To determine whether this instruction can throw,
* use {@link #canThrow}.
- *
+ *
* @return {@code non-null;} the catches list
*/
public abstract TypeList getCatches();
@@ -209,7 +209,7 @@
/**
* Calls the appropriate method on the given visitor, depending on the
* class of this instance. Subclasses must override this.
- *
+ *
* @param visitor {@code non-null;} the visitor to call on
*/
public abstract void accept(Visitor visitor);
@@ -220,7 +220,7 @@
* method throws an exception if this instance can't possibly
* throw. To determine whether this instruction can throw, use
* {@link #canThrow}.
- *
+ *
* @param type {@code non-null;} type to append to the catch list
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -229,7 +229,7 @@
/**
* Returns an instance that is just like this one, except that all
* register references have been offset by the given delta.
- *
+ *
* @param delta the amount to offset register references by
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -241,7 +241,7 @@
* source (if it is a constant) is represented directly rather than
* as a register reference. {@code this} is returned in cases where
* the translation is not possible.
- *
+ *
* @return {@code non-null;} an appropriately-constructed instance
*/
public Insn withLastSourceLiteral() {
@@ -274,7 +274,7 @@
* to be an identity compare. Insn's are {@code contentEquals()}
* if they have the same opcode, registers, source position, and other
* metadata.
- *
+ *
* @return true in the case described above
*/
public boolean contentEquals(Insn b) {
@@ -300,7 +300,7 @@
/**
* Returns the string form of this instance, with the given bit added in
* the standard location for an inline argument.
- *
+ *
* @param extra {@code null-ok;} the inline argument string
* @return {@code non-null;} the string form
*/
@@ -333,7 +333,7 @@
/**
* Returns the human string form of this instance, with the given
* bit added in the standard location for an inline argument.
- *
+ *
* @param extra {@code null-ok;} the inline argument string
* @return {@code non-null;} the human string form
*/
@@ -379,35 +379,35 @@
public static interface Visitor {
/**
* Visits a {@link PlainInsn}.
- *
+ *
* @param insn {@code non-null;} the instruction to visit
*/
public void visitPlainInsn(PlainInsn insn);
/**
* Visits a {@link PlainCstInsn}.
- *
+ *
* @param insn {@code non-null;} the instruction to visit
*/
public void visitPlainCstInsn(PlainCstInsn insn);
/**
* Visits a {@link SwitchInsn}.
- *
+ *
* @param insn {@code non-null;} the instruction to visit
*/
public void visitSwitchInsn(SwitchInsn insn);
/**
* Visits a {@link ThrowingCstInsn}.
- *
+ *
* @param insn {@code non-null;} the instruction to visit
*/
public void visitThrowingCstInsn(ThrowingCstInsn insn);
/**
* Visits a {@link ThrowingInsn}.
- *
+ *
* @param insn {@code non-null;} the instruction to visit
*/
public void visitThrowingInsn(ThrowingInsn insn);
diff --git a/dx/src/com/android/dx/rop/code/InsnList.java b/dx/src/com/android/dx/rop/code/InsnList.java
index 493f7fc..88abd72 100644
--- a/dx/src/com/android/dx/rop/code/InsnList.java
+++ b/dx/src/com/android/dx/rop/code/InsnList.java
@@ -57,7 +57,7 @@
/**
* Gets the last instruction. This is just a convenient shorthand for
* {@code get(size() - 1)}.
- *
+ *
* @return {@code non-null;} the last instruction
*/
public Insn getLast() {
@@ -91,7 +91,7 @@
int sz = size();
if (sz != b.size()) return false;
-
+
for (int i = 0; i < sz; i++) {
if (!get(i).contentEquals(b.get(i))) {
return false;
@@ -106,7 +106,7 @@
* the registers in each instruction are offset by the given
* amount. Mutability of the result is inherited from the
* original.
- *
+ *
* @param delta the amount to offset register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
diff --git a/dx/src/com/android/dx/rop/code/LocalItem.java b/dx/src/com/android/dx/rop/code/LocalItem.java
index 7d6bebe..82b227c 100644
--- a/dx/src/com/android/dx/rop/code/LocalItem.java
+++ b/dx/src/com/android/dx/rop/code/LocalItem.java
@@ -68,7 +68,7 @@
return 0 == compareTo(local);
}
- /**
+ /**
* Compares two strings like String.compareTo(), excepts treats a null
* as the least-possible string value.
*
diff --git a/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java b/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
index db142c2..c2c4021 100644
--- a/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
+++ b/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
@@ -38,7 +38,7 @@
/**
* Extracts out all the local variable information from the given method.
- *
+ *
* @param method {@code non-null;} the method to extract from
* @return {@code non-null;} the extracted information
*/
@@ -49,7 +49,7 @@
/**
* Constructs an instance. This method is private. Use {@link #extract}.
- *
+ *
* @param method {@code non-null;} the method to extract from
*/
private LocalVariableExtractor(RopMethod method) {
@@ -68,7 +68,7 @@
/**
* Does the extraction.
- *
+ *
* @return {@code non-null;} the extracted information
*/
private LocalVariableInfo doit() {
@@ -78,14 +78,14 @@
Bits.clear(workSet, label);
processBlock(label);
}
-
+
resultInfo.setImmutable();
return resultInfo;
}
/**
* Processes a single block.
- *
+ *
* @param label {@code >= 0;} label of the block to process
*/
private void processBlock(int label) {
@@ -158,7 +158,7 @@
if (previous != null
&& (previous.getReg() != result.getReg())) {
- primaryState.remove(previous);
+ primaryState.remove(previous);
}
resultInfo.addAssignment(insn, result);
diff --git a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
index fa5e7cc..99a10ee 100644
--- a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
+++ b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
@@ -33,14 +33,14 @@
/**
* {@code non-null;} {@link RegisterSpecSet} to use when indicating a block
* that has no locals; it is empty and immutable but has an appropriate
- * max size for the method
+ * max size for the method
*/
private final RegisterSpecSet emptySet;
/**
* {@code non-null;} array consisting of register sets representing the
* sets of variables already assigned upon entry to each block,
- * where array indices correspond to block labels
+ * where array indices correspond to block labels
*/
private final RegisterSpecSet[] blockStarts;
@@ -49,7 +49,7 @@
/**
* Constructs an instance.
- *
+ *
* @param method {@code non-null;} the method being represented by this instance
*/
public LocalVariableInfo(RopMethod method) {
@@ -72,7 +72,7 @@
/**
* Sets the register set associated with the start of the block with
* the given label.
- *
+ *
* @param label {@code >= 0;} the block label
* @param specs {@code non-null;} the register set to associate with the block
*/
@@ -97,7 +97,7 @@
* is the same as calling {@link #setStarts}. Otherwise, this will
* merge the two sets and call {@link #setStarts} on the result of the
* merge.
- *
+ *
* @param label {@code >= 0;} the block label
* @param specs {@code non-null;} the register set to merge into the start set
* for the block
@@ -131,7 +131,7 @@
* Gets the register set associated with the start of the block
* with the given label. This returns an empty set with the appropriate
* max size if no set was associated with the block in question.
- *
+ *
* @param label {@code >= 0;} the block label
* @return {@code non-null;} the associated register set
*/
@@ -145,7 +145,7 @@
* Gets the register set associated with the start of the given
* block. This is just convenient shorthand for
* {@code getStarts(block.getLabel())}.
- *
+ *
* @param block {@code non-null;} the block in question
* @return {@code non-null;} the associated register set
*/
@@ -158,7 +158,7 @@
* start of the block with the given label. This returns a
* newly-allocated empty {@link RegisterSpecSet} of appropriate
* max size if there is not yet any set associated with the block.
- *
+ *
* @param label {@code >= 0;} the block label
* @return {@code non-null;} the associated register set
*/
@@ -173,13 +173,13 @@
* Adds an assignment association for the given instruction and
* register spec. This throws an exception if the instruction
* doesn't actually perform a named variable assignment.
- *
+ *
* <b>Note:</b> Although the instruction contains its own spec for
* the result, it still needs to be passed in explicitly to this
* method, since the spec that is stored here should always have a
* simple type and the one in the instruction can be an arbitrary
* {@link TypeBearer} (such as a constant value).
- *
+ *
* @param insn {@code non-null;} the instruction in question
* @param spec {@code non-null;} the associated register spec
*/
@@ -200,7 +200,7 @@
/**
* Gets the named register being assigned by the given instruction, if
* previously stored in this instance.
- *
+ *
* @param insn {@code non-null;} instruction in question
* @return {@code null-ok;} the named register being assigned, if any
*/
@@ -210,7 +210,7 @@
/**
* Gets the number of assignments recorded by this instance.
- *
+ *
* @return {@code >= 0;} the number of assignments
*/
public int getAssignmentCount() {
@@ -234,7 +234,7 @@
/**
* Helper method, to get the starts for a label, throwing the
* right exception for range problems.
- *
+ *
* @param label {@code >= 0;} the block label
* @return {@code null-ok;} associated register set or {@code null} if there
* is none
diff --git a/dx/src/com/android/dx/rop/code/PlainCstInsn.java b/dx/src/com/android/dx/rop/code/PlainCstInsn.java
index 7a3ac38..fffa76b 100644
--- a/dx/src/com/android/dx/rop/code/PlainCstInsn.java
+++ b/dx/src/com/android/dx/rop/code/PlainCstInsn.java
@@ -29,7 +29,7 @@
extends CstInsn {
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param result {@code null-ok;} spec for the result, if any
diff --git a/dx/src/com/android/dx/rop/code/PlainInsn.java b/dx/src/com/android/dx/rop/code/PlainInsn.java
index d1db646..3fd2ba5 100644
--- a/dx/src/com/android/dx/rop/code/PlainInsn.java
+++ b/dx/src/com/android/dx/rop/code/PlainInsn.java
@@ -30,7 +30,7 @@
extends Insn {
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param result {@code null-ok;} spec for the result, if any
@@ -50,13 +50,13 @@
if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
// move-result-pseudo is required here
throw new IllegalArgumentException
- ("can't mix branchingness with result");
+ ("can't mix branchingness with result");
}
}
/**
* Constructs a single-source instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param result {@code null-ok;} spec for the result, if any
diff --git a/dx/src/com/android/dx/rop/code/RegOps.java b/dx/src/com/android/dx/rop/code/RegOps.java
index 2084a69..bdf9342 100644
--- a/dx/src/com/android/dx/rop/code/RegOps.java
+++ b/dx/src/com/android/dx/rop/code/RegOps.java
@@ -20,7 +20,7 @@
/**
* All the register-based opcodes, and related utilities.
- *
+ *
* <p><b>Note:</b> Opcode descriptions use a rough pseudocode. {@code r}
* is the result register, {@code x} is the first argument,
* {@code y} is the second argument, and {@code z} is the
@@ -93,7 +93,7 @@
/**
* {@code T: any numeric type; r,x,y: T :: r = x % y}
- * (Java-style remainder)
+ * (Java-style remainder)
*/
public static final int REM = 18;
@@ -116,13 +116,13 @@
/**
* {@code T: any integral type; r,x: T; y: int :: r = x >> y}
- * (signed right-shift)
+ * (signed right-shift)
*/
public static final int SHR = 24;
/**
* {@code T: any integral type; r,x: T; y: int :: r = x >>> y}
- * (unsigned right-shift)
+ * (unsigned right-shift)
*/
public static final int USHR = 25;
@@ -133,38 +133,38 @@
* {@code T: any numeric type; r: int; x,y: T :: r = (x == y) ? 0
* : (x > y) ? 1 : -1} (Java-style "cmpl" where a NaN is
* considered "less than" all other values; also used for integral
- * comparisons)
+ * comparisons)
*/
public static final int CMPL = 27;
/**
* {@code T: any floating point type; r: int; x,y: T :: r = (x == y) ? 0
* : (x < y) ? -1 : 1} (Java-style "cmpg" where a NaN is
- * considered "greater than" all other values)
+ * considered "greater than" all other values)
*/
public static final int CMPG = 28;
/**
* {@code T: any numeric type; U: any numeric type; r: T; x: U ::
* r = (T) x} (numeric type conversion between the four
- * "real" numeric types)
+ * "real" numeric types)
*/
public static final int CONV = 29;
/**
* {@code r,x: int :: r = (x << 24) >> 24} (Java-style
- * convert int to byte)
+ * convert int to byte)
*/
public static final int TO_BYTE = 30;
/**
- * {@code r,x: int :: r = x & 0xffff} (Java-style convert int to char)
+ * {@code r,x: int :: r = x & 0xffff} (Java-style convert int to char)
*/
public static final int TO_CHAR = 31;
/**
* {@code r,x: int :: r = (x << 16) >> 16} (Java-style
- * convert int to short)
+ * convert int to short)
*/
public static final int TO_SHORT = 32;
@@ -191,7 +191,7 @@
/**
* {@code T: any non-array object type :: r =
- * alloc(T)} (allocate heap space for an object)
+ * alloc(T)} (allocate heap space for an object)
*/
public static final int NEW_INSTANCE = 40;
@@ -206,7 +206,7 @@
/**
* {@code T: any object type; x: Object :: (T) x} (can
- * throw {@code ClassCastException})
+ * throw {@code ClassCastException})
*/
public static final int CHECK_CAST = 43;
@@ -223,13 +223,13 @@
/**
* {@code T: any type; r: T; f: static field spec of type T :: r =
- * f}
+ * f}
*/
public static final int GET_STATIC = 46;
/**
* {@code T: any type; x: T; y: Object; f: instance field spec of type
- * T :: y.f = x}
+ * T :: y.f = x}
*/
public static final int PUT_FIELD = 47;
@@ -241,35 +241,35 @@
/**
* {@code Tr, T0, T1...: any types; r: Tr; m: static method spec;
* y0: T0; y1: T1 ... :: r = m(y0, y1, ...)} (call static
- * method)
+ * method)
*/
public static final int INVOKE_STATIC = 49;
/**
* {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
* spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call normal
- * virtual method)
+ * virtual method)
*/
public static final int INVOKE_VIRTUAL = 50;
/**
* {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
* spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
- * superclass virtual method)
+ * superclass virtual method)
*/
public static final int INVOKE_SUPER = 51;
/**
* {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
* spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
- * direct/special method)
+ * direct/special method)
*/
public static final int INVOKE_DIRECT = 52;
/**
* {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
* (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
- * ...)} (call interface method)
+ * ...)} (call interface method)
*/
public static final int INVOKE_INTERFACE = 53;
@@ -305,7 +305,7 @@
/**
* Gets the name of the given opcode.
- *
+ *
* @param opcode {@code >= 0, <= 255;} the opcode
* @return {@code non-null;} its name
*/
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpec.java b/dx/src/com/android/dx/rop/code/RegisterSpec.java
index 1f14767..f1ac563 100644
--- a/dx/src/com/android/dx/rop/code/RegisterSpec.java
+++ b/dx/src/com/android/dx/rop/code/RegisterSpec.java
@@ -76,7 +76,7 @@
* Returns an instance for the given register number and type, with
* no variable info. This method is allowed to return shared
* instances (but doesn't necessarily do so).
- *
+ *
* @param reg {@code >= 0;} the register number
* @param type {@code non-null;} the type (or possibly actual value) which
* is loaded from or stored to the indicated register
@@ -126,7 +126,7 @@
/**
* Gets the string form for the given register number.
- *
+ *
* @param reg {@code >= 0;} the register number
* @return {@code non-null;} the string form
*/
@@ -137,7 +137,7 @@
/**
* Constructs an instance. This constructor is private. Use
* {@link #make}.
- *
+ *
* @param reg {@code >= 0;} the register number
* @param type {@code non-null;} the type (or possibly actual value) which
* is loaded from or stored to the indicated register
@@ -177,7 +177,7 @@
* registers. That is, this compares {@code getType()} on the types
* to ignore whatever arbitrary extra stuff might be carried around
* by an outer {@link TypeBearer}.
- *
+ *
* @param other {@code null-ok;} spec to compare to
* @return {@code true} iff {@code this} and {@code other} are equal
* in the stated way
@@ -194,7 +194,7 @@
* Like {@link #equalsUsingSimpleType} but ignoring the register number.
* This is useful to determine if two instances refer to the "same"
* local variable.
- *
+ *
* @param other {@code null-ok;} spec to compare to
* @return {@code true} iff {@code this} and {@code other} are equal
* in the stated way
@@ -212,7 +212,7 @@
/**
* Helper for {@link #equals} and {@link #ForComparison.equals},
* which actually does the test.
- *
+ *
* @param reg value of the instance variable, for another instance
* @param type value of the instance variable, for another instance
* @param local value of the instance variable, for another instance
@@ -229,7 +229,7 @@
/**
* Compares by (in priority order) register number, unwrapped type
* (that is types not {@link TypeBearer}s, and local info.
- *
+ *
* @param other {@code non-null;} spec to compare to
* @return {@code -1..1;} standard result of comparison
*/
@@ -253,7 +253,7 @@
}
return this.local.compareTo(other.local);
- }
+ }
/** {@inheritDoc} */
@Override
@@ -264,7 +264,7 @@
/**
* Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
* which actually does the calculation.
- *
+ *
* @param reg value of the instance variable
* @param type value of the instance variable
* @param local value of the instance variable
@@ -315,7 +315,7 @@
/**
* Gets the register number.
- *
+ *
* @return {@code >= 0;} the register number
*/
public int getReg() {
@@ -325,7 +325,7 @@
/**
* Gets the type (or actual value) which is loaded from or stored
* to the register associated with this instance.
- *
+ *
* @return {@code non-null;} the type
*/
public TypeBearer getTypeBearer() {
@@ -348,7 +348,7 @@
* (category) of the type used. Among other things, this may also
* be used to determine the minimum required register count
* implied by this instance.
- *
+ *
* @return {@code >= 0;} the required registers size
*/
public int getNextReg() {
@@ -358,7 +358,7 @@
/**
* Gets the category of this instance's type. This is just a convenient
* shorthand for {@code getType().getCategory()}.
- *
+ *
* @see #isCategory1
* @see #isCategory2
* @return {@code 1..2;} the category of this instance's type
@@ -370,7 +370,7 @@
/**
* Gets whether this instance's type is category 1. This is just a
* convenient shorthand for {@code getType().isCategory1()}.
- *
+ *
* @see #getCategory
* @see #isCategory2
* @return whether or not this instance's type is of category 1
@@ -382,7 +382,7 @@
/**
* Gets whether this instance's type is category 2. This is just a
* convenient shorthand for {@code getType().isCategory2()}.
- *
+ *
* @see #getCategory
* @see #isCategory1
* @return whether or not this instance's type is of category 2
@@ -393,7 +393,7 @@
/**
* Gets the string form for just the register number of this instance.
- *
+ *
* @return {@code non-null;} the register string form
*/
public String regString() {
@@ -403,7 +403,7 @@
/**
* Returns an instance that is the intersection between this instance
* and the given one, if any. The intersection is defined as follows:
- *
+ *
* <ul>
* <li>If {@code other} is {@code null}, then the result
* is {@code null}.
@@ -420,7 +420,7 @@
* of the intersection is the local info of this instance. Otherwise,
* the local info of the intersection is {@code null}.</li>
* </ul>
- *
+ *
* @param other {@code null-ok;} instance to intersect with (or {@code null})
* @param localPrimary whether local variables are primary to the
* intersection; if {@code true}, then the only non-null
@@ -470,7 +470,7 @@
/**
* Returns an instance that is identical to this one, except that the
* register number is replaced by the given one.
- *
+ *
* @param newReg {@code >= 0;} the new register number
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -496,7 +496,7 @@
/**
* Returns an instance that is identical to this one, except that the
* register number is offset by the given amount.
- *
+ *
* @param delta the amount to offset the register number by
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -507,13 +507,13 @@
return withReg(reg + delta);
}
-
+
/**
* Returns an instance that is identical to this one, except that
* the type bearer is replaced by the actual underlying type
* (thereby stripping off non-type information) with any
* initialization information stripped away as well.
- *
+ *
* @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec withSimpleType() {
@@ -557,7 +557,7 @@
/**
* Helper for {@link #toString} and {@link #toHuman}.
- *
+ *
* @param human whether to be human-oriented
* @return {@code non-null;} the string form
*/
@@ -594,7 +594,7 @@
private static class ForComparison {
/** {@code >= 0;} register number */
private int reg;
-
+
/** {@code non-null;} type loaded or stored */
private TypeBearer type;
@@ -606,7 +606,7 @@
/**
* Set all the instance variables.
- *
+ *
* @param reg {@code >= 0;} the register number
* @param type {@code non-null;} the type (or possibly actual
* value) which is loaded from or stored to the indicated
@@ -623,7 +623,7 @@
/**
* Construct a {@code RegisterSpec} of this instance's
* contents.
- *
+ *
* @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec toRegisterSpec() {
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecList.java b/dx/src/com/android/dx/rop/code/RegisterSpecList.java
index 5a02a8d..e900787 100644
--- a/dx/src/com/android/dx/rop/code/RegisterSpecList.java
+++ b/dx/src/com/android/dx/rop/code/RegisterSpecList.java
@@ -30,7 +30,7 @@
/**
* Makes a single-element instance.
- *
+ *
* @param spec {@code non-null;} the element
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -42,7 +42,7 @@
/**
* Makes a two-element instance.
- *
+ *
* @param spec0 {@code non-null;} the first element
* @param spec1 {@code non-null;} the second element
* @return {@code non-null;} an appropriately-constructed instance
@@ -57,7 +57,7 @@
/**
* Makes a three-element instance.
- *
+ *
* @param spec0 {@code non-null;} the first element
* @param spec1 {@code non-null;} the second element
* @param spec2 {@code non-null;} the third element
@@ -74,7 +74,7 @@
/**
* Makes a four-element instance.
- *
+ *
* @param spec0 {@code non-null;} the first element
* @param spec1 {@code non-null;} the second element
* @param spec2 {@code non-null;} the third element
@@ -94,7 +94,7 @@
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public RegisterSpecList(int size) {
@@ -122,12 +122,12 @@
public TypeList withAddedType(Type type) {
throw new UnsupportedOperationException("unsupported");
}
-
+
/**
* Gets the indicated element. It is an error to call this with the
* index for an element which was never set; if you do that, this
* will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @return {@code non-null;} the indicated element
*/
@@ -174,12 +174,12 @@
}
}
- return -1;
+ return -1;
}
-
+
/**
* Sets the element at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param spec {@code non-null;} the value to store
*/
@@ -192,7 +192,7 @@
* instance. This is equal to the highest register number referred
* to plus the widest width (largest category) of the type used in
* that register.
- *
+ *
* @return {@code >= 0;} the required registers size
*/
public int getRegistersSize() {
@@ -216,7 +216,7 @@
* Returns a new instance, which is the same as this instance,
* except that it has an additional element prepended to the original.
* Mutability of the result is inherited from the original.
- *
+ *
* @param spec {@code non-null;} the new first spec (to prepend)
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -240,7 +240,7 @@
* Returns a new instance, which is the same as this instance,
* except that its first element is removed. Mutability of the
* result is inherited from the original.
- *
+ *
* @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withoutFirst() {
@@ -267,7 +267,7 @@
* Returns a new instance, which is the same as this instance,
* except that its last element is removed. Mutability of the
* result is inherited from the original.
- *
+ *
* @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withoutLast() {
@@ -294,7 +294,7 @@
* Returns an instance that is identical to this one, except that
* all register numbers are offset by the given amount. Mutability
* of the result is inherited from the original.
- *
+ *
* @param delta the amount to offset the register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -325,8 +325,8 @@
/**
* Returns an instance that is identical to this one, except that
* all register numbers are renumbered sequentially from the given
- * base, with the first number duplicated if indicated.
- *
+ * base, with the first number duplicated if indicated.
+ *
* @param base the base register number
* @param duplicateFirst whether to duplicate the first number
* @return {@code non-null;} an appropriately-constructed instance
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
index 68009d9..d16a82a 100644
--- a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
+++ b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
@@ -31,7 +31,7 @@
/**
* {@code non-null;} array of register specs, where each element is
* {@code null} or is an instance whose {@code reg}
- * matches the array index
+ * matches the array index
*/
private final RegisterSpec[] specs;
@@ -40,7 +40,7 @@
/**
* Constructs an instance. The instance is initially empty.
- *
+ *
* @param maxSize {@code >= 0;} the maximum register number (exclusive) that
* may be represented in this instance
*/
@@ -120,13 +120,13 @@
sb.append('}');
return sb.toString();
- }
+ }
/**
* Gets the maximum number of registers that may be in this instance, which
* is also the maximum-plus-one of register numbers that may be
* represented.
- *
+ *
* @return {@code >= 0;} the maximum size
*/
public int getMaxSize() {
@@ -135,7 +135,7 @@
/**
* Gets the current size of this instance.
- *
+ *
* @return {@code >= 0;} the size
*/
public int size() {
@@ -159,7 +159,7 @@
/**
* Gets the element with the given register number, if any.
- *
+ *
* @param reg {@code >= 0;} the desired register number
* @return {@code null-ok;} the element with the given register number or
* {@code null} if there is none
@@ -177,7 +177,7 @@
* Gets the element with the same register number as the given
* spec, if any. This is just a convenient shorthand for
* {@code get(spec.getReg())}.
- *
+ *
* @param spec {@code non-null;} spec with the desired register number
* @return {@code null-ok;} the element with the matching register number or
* {@code null} if there is none
@@ -191,13 +191,13 @@
* given local (type, name, and signature), or {@code null} if there is
* none. This ignores the register number of the given spec but
* matches on everything else.
- *
+ *
* @param spec {@code non-null;} local to look for
* @return {@code null-ok;} first register found that matches, if any
*/
public RegisterSpec findMatchingLocal(RegisterSpec spec) {
int length = specs.length;
-
+
for (int reg = 0; reg < length; reg++) {
RegisterSpec s = specs[reg];
@@ -222,10 +222,10 @@
*/
public RegisterSpec localItemToSpec(LocalItem local) {
int length = specs.length;
-
+
for (int reg = 0; reg < length; reg++) {
RegisterSpec spec = specs[reg];
-
+
if ((spec != null) && local.equals(spec.getLocalItem())) {
return spec;
}
@@ -257,7 +257,7 @@
* previous element is nullified. Finally, if the given spec is for
* a category-2 register, then the immediately subsequent element
* is nullified.
- *
+ *
* @param spec {@code non-null;} the register spec to put in the instance
*/
public void put(RegisterSpec spec) {
@@ -292,7 +292,7 @@
/**
* Put the entire contents of the given set into this one.
- *
+ *
* @param set {@code non-null;} the set to put into this instance
*/
public void putAll(RegisterSpecSet set) {
@@ -311,7 +311,7 @@
* instance. The intersection consists of the pairwise
* {@link RegisterSpec#intersect} of corresponding elements from
* this instance and the given one where both are non-null.
- *
+ *
* @param other {@code non-null;} set to intersect with
* @param localPrimary whether local variables are primary to
* the intersection; if {@code true}, then the only non-null
@@ -350,7 +350,7 @@
* Returns an instance that is identical to this one, except that
* all register numbers are offset by the given amount. Mutability
* of the result is inherited from the original.
- *
+ *
* @param delta the amount to offset the register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -376,7 +376,7 @@
/**
* Makes and return a mutable copy of this instance.
- *
+ *
* @return {@code non-null;} the mutable copy
*/
public RegisterSpecSet mutableCopy() {
diff --git a/dx/src/com/android/dx/rop/code/Rop.java b/dx/src/com/android/dx/rop/code/Rop.java
index fbd9a16..8224584 100644
--- a/dx/src/com/android/dx/rop/code/Rop.java
+++ b/dx/src/com/android/dx/rop/code/Rop.java
@@ -54,7 +54,7 @@
/**
* {@code non-null;} result type of this operation; {@link Type#VOID} for
- * no-result operations
+ * no-result operations
*/
private final Type result;
@@ -66,7 +66,7 @@
/**
* the branchingness of this op; one of the {@code BRANCH_*}
- * constants in this class
+ * constants in this class
*/
private final int branchingness;
@@ -79,7 +79,7 @@
/**
* Constructs an instance. This method is private. Use one of the
* public constructors.
- *
+ *
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
@@ -125,9 +125,9 @@
}
/**
- * Constructs an instance. The constructed instance is never a
+ * Constructs an instance. The constructed instance is never a
* call-like op (see {@link #isCallLike}).
- *
+ *
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
@@ -145,9 +145,9 @@
}
/**
- * Constructs a no-exception instance. The constructed instance is never a
+ * Constructs a no-exception instance. The constructed instance is never a
* call-like op (see {@link #isCallLike}).
- *
+ *
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
@@ -166,7 +166,7 @@
* Constructs a non-branching no-exception instance. The
* {@code branchingness} is always {@code BRANCH_NONE},
* and it is never a call-like op (see {@link #isCallLike}).
- *
+ *
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
@@ -182,7 +182,7 @@
* Constructs a non-empty exceptions instance. Its
* {@code branchingness} is always {@code BRANCH_THROW},
* but it is never a call-like op (see {@link #isCallLike}).
- *
+ *
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
@@ -201,7 +201,7 @@
* Constructs a non-nicknamed instance with non-empty exceptions, which
* is always a call-like op (see {@link #isCallLike}). Its
* {@code branchingness} is always {@code BRANCH_THROW}.
- *
+ *
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param sources {@code non-null;} types of all the sources of this operation
* @param exceptions {@code non-null;} list of possible types thrown by this
@@ -306,7 +306,7 @@
/**
* Gets the opcode.
- *
+ *
* @return the opcode
*/
public int getOpcode() {
@@ -316,7 +316,7 @@
/**
* Gets the result type. A return value of {@link Type#VOID}
* means this operation returns nothing.
- *
+ *
* @return {@code null-ok;} the result spec
*/
public Type getResult() {
@@ -325,7 +325,7 @@
/**
* Gets the source types.
- *
+ *
* @return {@code non-null;} the source types
*/
public TypeList getSources() {
@@ -334,7 +334,7 @@
/**
* Gets the list of exception types that might be thrown.
- *
+ *
* @return {@code non-null;} the list of exception types
*/
public TypeList getExceptions() {
@@ -343,7 +343,7 @@
/**
* Gets the branchingness of this instance.
- *
+ *
* @return the branchingness
*/
public int getBranchingness() {
@@ -352,7 +352,7 @@
/**
* Gets whether this opcode is a function/method call or similar.
- *
+ *
* @return {@code true} iff this opcode is call-like
*/
public boolean isCallLike() {
@@ -383,7 +383,7 @@
/**
* Gets the nickname. If this instance has no nickname, this returns
* the result of calling {@link #toString}.
- *
+ *
* @return {@code non-null;} the nickname
*/
public String getNickname() {
@@ -398,7 +398,7 @@
* Gets whether this operation can possibly throw an exception. This
* is just a convenient wrapper for
* {@code getExceptions().size() != 0}.
- *
+ *
* @return {@code true} iff this operation can possibly throw
*/
public final boolean canThrow() {
diff --git a/dx/src/com/android/dx/rop/code/RopMethod.java b/dx/src/com/android/dx/rop/code/RopMethod.java
index 3957532..591d325 100644
--- a/dx/src/com/android/dx/rop/code/RopMethod.java
+++ b/dx/src/com/android/dx/rop/code/RopMethod.java
@@ -32,19 +32,19 @@
/**
* {@code null-ok;} array of predecessors for each block, indexed by block
- * label
+ * label
*/
private IntList[] predecessors;
/**
* {@code null-ok;} the predecessors for the implicit "exit" block, that is
- * the labels for the blocks that return, if calculated
+ * the labels for the blocks that return, if calculated
*/
private IntList exitPredecessors;
/**
* Constructs an instance.
- *
+ *
* @param blocks {@code non-null;} basic block list of the method
* @param firstLabel {@code >= 0;} the label of the first block to execute
*/
@@ -66,7 +66,7 @@
/**
* Gets the basic block list for this method.
- *
+ *
* @return {@code non-null;} the list
*/
public BasicBlockList getBlocks() {
@@ -76,7 +76,7 @@
/**
* Gets the label for the first block in the method that this list
* represents.
- *
+ *
* @return {@code >= 0;} the first-block label
*/
public int getFirstLabel() {
@@ -86,7 +86,7 @@
/**
* Gets the predecessors associated with the given block. This throws
* an exception if there is no block with the given label.
- *
+ *
* @param label {@code >= 0;} the label of the block in question
* @return {@code non-null;} the predecessors of that block
*/
@@ -106,7 +106,7 @@
/**
* Gets the exit predecessors for this instance.
- *
+ *
* @return {@code non-null;} the exit predecessors
*/
public IntList getExitPredecessors() {
@@ -122,7 +122,7 @@
* Returns an instance that is identical to this one, except that
* the registers in each instruction are offset by the given
* amount.
- *
+ *
* @param delta the amount to offset register numbers by
* @return {@code non-null;} an appropriately-constructed instance
*/
diff --git a/dx/src/com/android/dx/rop/code/Rops.java b/dx/src/com/android/dx/rop/code/Rops.java
index 15c2e17..9085ff4 100644
--- a/dx/src/com/android/dx/rop/code/Rops.java
+++ b/dx/src/com/android/dx/rop/code/Rops.java
@@ -201,7 +201,7 @@
Rop.BRANCH_IF, "if-ne-object");
/** {@code x: int :: goto switchtable[x]} */
- public static final Rop SWITCH =
+ public static final Rop SWITCH =
new Rop(RegOps.SWITCH, Type.VOID, StdTypeList.INT, Rop.BRANCH_SWITCH,
"switch");
@@ -575,21 +575,21 @@
/**
* {@code r,x: int :: r = (x << 24) >> 24} (Java-style
- * convert int to byte)
+ * convert int to byte)
*/
- public static final Rop TO_BYTE =
+ public static final Rop TO_BYTE =
new Rop(RegOps.TO_BYTE, Type.INT, StdTypeList.INT, "to-byte");
/**
* {@code r,x: int :: r = x & 0xffff} (Java-style
- * convert int to char)
+ * convert int to char)
*/
public static final Rop TO_CHAR =
new Rop(RegOps.TO_CHAR, Type.INT, StdTypeList.INT, "to-char");
/**
* {@code r,x: int :: r = (x << 16) >> 16} (Java-style
- * convert int to short)
+ * convert int to short)
*/
public static final Rop TO_SHORT =
new Rop(RegOps.TO_SHORT, Type.INT, StdTypeList.INT, "to-short");
@@ -646,110 +646,110 @@
"monitor-exit");
/** {@code r,y: int; x: int[] :: r = x[y]} */
- public static final Rop AGET_INT =
+ public static final Rop AGET_INT =
new Rop(RegOps.AGET, Type.INT, StdTypeList.INTARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-int");
/** {@code r: long; x: long[]; y: int :: r = x[y]} */
- public static final Rop AGET_LONG =
+ public static final Rop AGET_LONG =
new Rop(RegOps.AGET, Type.LONG, StdTypeList.LONGARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-long");
/** {@code r: float; x: float[]; y: int :: r = x[y]} */
- public static final Rop AGET_FLOAT =
+ public static final Rop AGET_FLOAT =
new Rop(RegOps.AGET, Type.FLOAT, StdTypeList.FLOATARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-float");
/** {@code r: double; x: double[]; y: int :: r = x[y]} */
- public static final Rop AGET_DOUBLE =
+ public static final Rop AGET_DOUBLE =
new Rop(RegOps.AGET, Type.DOUBLE, StdTypeList.DOUBLEARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-double");
/** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
- public static final Rop AGET_OBJECT =
+ public static final Rop AGET_OBJECT =
new Rop(RegOps.AGET, Type.OBJECT, StdTypeList.OBJECTARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-object");
/** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
- public static final Rop AGET_BOOLEAN =
+ public static final Rop AGET_BOOLEAN =
new Rop(RegOps.AGET, Type.INT, StdTypeList.BOOLEANARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-boolean");
/** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
- public static final Rop AGET_BYTE =
+ public static final Rop AGET_BYTE =
new Rop(RegOps.AGET, Type.INT, StdTypeList.BYTEARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte");
/** {@code r: char; x: char[]; y: int :: r = x[y]} */
- public static final Rop AGET_CHAR =
+ public static final Rop AGET_CHAR =
new Rop(RegOps.AGET, Type.INT, StdTypeList.CHARARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char");
/** {@code r: short; x: short[]; y: int :: r = x[y]} */
- public static final Rop AGET_SHORT =
+ public static final Rop AGET_SHORT =
new Rop(RegOps.AGET, Type.INT, StdTypeList.SHORTARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aget-short");
/** {@code x,z: int; y: int[] :: y[z] = x} */
- public static final Rop APUT_INT =
+ public static final Rop APUT_INT =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_INTARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int");
/** {@code x: long; y: long[]; z: int :: y[z] = x} */
- public static final Rop APUT_LONG =
+ public static final Rop APUT_LONG =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.LONG_LONGARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long");
/** {@code x: float; y: float[]; z: int :: y[z] = x} */
- public static final Rop APUT_FLOAT =
+ public static final Rop APUT_FLOAT =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.FLOAT_FLOATARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aput-float");
/** {@code x: double; y: double[]; z: int :: y[z] = x} */
- public static final Rop APUT_DOUBLE =
+ public static final Rop APUT_DOUBLE =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.DOUBLE_DOUBLEARR_INT,
Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
"aput-double");
/** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
- public static final Rop APUT_OBJECT =
+ public static final Rop APUT_OBJECT =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.OBJECT_OBJECTARR_INT,
Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
"aput-object");
/** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
- public static final Rop APUT_BOOLEAN =
+ public static final Rop APUT_BOOLEAN =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BOOLEANARR_INT,
Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
"aput-boolean");
/** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
- public static final Rop APUT_BYTE =
+ public static final Rop APUT_BYTE =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BYTEARR_INT,
Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte");
/** {@code x: char; y: char[]; z: int :: y[z] = x} */
- public static final Rop APUT_CHAR =
+ public static final Rop APUT_CHAR =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_CHARARR_INT,
Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char");
/** {@code x: short; y: short[]; z: int :: y[z] = x} */
- public static final Rop APUT_SHORT =
+ public static final Rop APUT_SHORT =
new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_SHORTARR_INT,
Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
"aput-short");
/**
* {@code T: any non-array object type :: r =
- * alloc(T)} (allocate heap space for an object)
+ * alloc(T)} (allocate heap space for an object)
*/
public static final Rop NEW_INSTANCE =
new Rop(RegOps.NEW_INSTANCE, Type.OBJECT, StdTypeList.EMPTY,
@@ -805,9 +805,9 @@
/**
* {@code T: any non-array object type; x: Object :: (T) x} (can
- * throw {@code ClassCastException})
+ * throw {@code ClassCastException})
*/
- public static final Rop CHECK_CAST =
+ public static final Rop CHECK_CAST =
new Rop(RegOps.CHECK_CAST, Type.VOID, StdTypeList.OBJECT,
Exceptions.LIST_Error_ClassCastException, "check-cast");
@@ -815,7 +815,7 @@
* {@code T: any non-array object type; x: Object :: x instanceof
* T}. Note: This is listed as throwing {@code Error}
* explicitly because the op <i>can</i> throw, but there are no
- * other predefined exceptions for it.
+ * other predefined exceptions for it.
*/
public static final Rop INSTANCE_OF =
new Rop(RegOps.INSTANCE_OF, Type.INT, StdTypeList.OBJECT,
@@ -823,7 +823,7 @@
/**
* {@code r: int; x: Object; f: instance field spec of
- * type int :: r = x.f}
+ * type int :: r = x.f}
*/
public static final Rop GET_FIELD_INT =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -831,7 +831,7 @@
/**
* {@code r: long; x: Object; f: instance field spec of
- * type long :: r = x.f}
+ * type long :: r = x.f}
*/
public static final Rop GET_FIELD_LONG =
new Rop(RegOps.GET_FIELD, Type.LONG, StdTypeList.OBJECT,
@@ -839,7 +839,7 @@
/**
* {@code r: float; x: Object; f: instance field spec of
- * type float :: r = x.f}
+ * type float :: r = x.f}
*/
public static final Rop GET_FIELD_FLOAT =
new Rop(RegOps.GET_FIELD, Type.FLOAT, StdTypeList.OBJECT,
@@ -848,7 +848,7 @@
/**
* {@code r: double; x: Object; f: instance field spec of
- * type double :: r = x.f}
+ * type double :: r = x.f}
*/
public static final Rop GET_FIELD_DOUBLE =
new Rop(RegOps.GET_FIELD, Type.DOUBLE, StdTypeList.OBJECT,
@@ -857,7 +857,7 @@
/**
* {@code r: Object; x: Object; f: instance field spec of
- * type Object :: r = x.f}
+ * type Object :: r = x.f}
*/
public static final Rop GET_FIELD_OBJECT =
new Rop(RegOps.GET_FIELD, Type.OBJECT, StdTypeList.OBJECT,
@@ -866,7 +866,7 @@
/**
* {@code r: boolean; x: Object; f: instance field spec of
- * type boolean :: r = x.f}
+ * type boolean :: r = x.f}
*/
public static final Rop GET_FIELD_BOOLEAN =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -875,7 +875,7 @@
/**
* {@code r: byte; x: Object; f: instance field spec of
- * type byte :: r = x.f}
+ * type byte :: r = x.f}
*/
public static final Rop GET_FIELD_BYTE =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -884,7 +884,7 @@
/**
* {@code r: char; x: Object; f: instance field spec of
- * type char :: r = x.f}
+ * type char :: r = x.f}
*/
public static final Rop GET_FIELD_CHAR =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -893,7 +893,7 @@
/**
* {@code r: short; x: Object; f: instance field spec of
- * type short :: r = x.f}
+ * type short :: r = x.f}
*/
public static final Rop GET_FIELD_SHORT =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -947,7 +947,7 @@
/**
* {@code x: int; y: Object; f: instance field spec of type
- * int :: y.f = x}
+ * int :: y.f = x}
*/
public static final Rop PUT_FIELD_INT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -955,7 +955,7 @@
/**
* {@code x: long; y: Object; f: instance field spec of type
- * long :: y.f = x}
+ * long :: y.f = x}
*/
public static final Rop PUT_FIELD_LONG =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.LONG_OBJECT,
@@ -963,7 +963,7 @@
/**
* {@code x: float; y: Object; f: instance field spec of type
- * float :: y.f = x}
+ * float :: y.f = x}
*/
public static final Rop PUT_FIELD_FLOAT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.FLOAT_OBJECT,
@@ -972,7 +972,7 @@
/**
* {@code x: double; y: Object; f: instance field spec of type
- * double :: y.f = x}
+ * double :: y.f = x}
*/
public static final Rop PUT_FIELD_DOUBLE =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.DOUBLE_OBJECT,
@@ -981,7 +981,7 @@
/**
* {@code x: Object; y: Object; f: instance field spec of type
- * Object :: y.f = x}
+ * Object :: y.f = x}
*/
public static final Rop PUT_FIELD_OBJECT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.OBJECT_OBJECT,
@@ -990,7 +990,7 @@
/**
* {@code x: int; y: Object; f: instance field spec of type
- * boolean :: y.f = x}
+ * boolean :: y.f = x}
*/
public static final Rop PUT_FIELD_BOOLEAN =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -999,7 +999,7 @@
/**
* {@code x: int; y: Object; f: instance field spec of type
- * byte :: y.f = x}
+ * byte :: y.f = x}
*/
public static final Rop PUT_FIELD_BYTE =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -1008,7 +1008,7 @@
/**
* {@code x: int; y: Object; f: instance field spec of type
- * char :: y.f = x}
+ * char :: y.f = x}
*/
public static final Rop PUT_FIELD_CHAR =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -1017,7 +1017,7 @@
/**
* {@code x: int; y: Object; f: instance field spec of type
- * short :: y.f = x}
+ * short :: y.f = x}
*/
public static final Rop PUT_FIELD_SHORT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -1106,12 +1106,12 @@
* Returns the appropriate rop for the given opcode, destination,
* and sources. The result is typically, but not necessarily, a
* shared instance.
- *
+ *
* <p><b>Note:</b> This method does not do complete error checking on
* its arguments, and so it may return an instance which seemed "right
* enough" even though in actuality the passed arguments don't quite
* match what is returned. TODO: Revisit this issue.</p>
- *
+ *
* @param opcode the opcode
* @param dest {@code non-null;} destination (result) type, or
* {@link Type#VOID} if none
@@ -1239,7 +1239,7 @@
/**
* Returns the appropriate {@code move} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being moved
* @return {@code non-null;} an appropriate instance
*/
@@ -1259,7 +1259,7 @@
/**
* Returns the appropriate {@code move-param} rop for the
* given type. The result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being moved
* @return {@code non-null;} an appropriate instance
*/
@@ -1278,7 +1278,7 @@
/**
* Returns the appropriate {@code move-exception} rop for the
* given type. The result may be a shared instance.
- *
+ *
* @param type {@code non-null;} type of the exception
* @return {@code non-null;} an appropriate instance
*/
@@ -1314,7 +1314,7 @@
/**
* Returns the appropriate {@code const} rop for the given
* type. The result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of the constant
* @return {@code non-null;} an appropriate instance
*/
@@ -1337,7 +1337,7 @@
/**
* Returns the appropriate {@code if-eq} rop for the given
* sources. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} source types
* @return {@code non-null;} an appropriate instance
*/
@@ -1349,7 +1349,7 @@
/**
* Returns the appropriate {@code if-ne} rop for the given
* sources. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} source types
* @return {@code non-null;} an appropriate instance
*/
@@ -1361,7 +1361,7 @@
/**
* Returns the appropriate {@code if-lt} rop for the given
* sources. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} source types
* @return {@code non-null;} an appropriate instance
*/
@@ -1372,7 +1372,7 @@
/**
* Returns the appropriate {@code if-ge} rop for the given
* sources. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} source types
* @return {@code non-null;} an appropriate instance
*/
@@ -1383,7 +1383,7 @@
/**
* Returns the appropriate {@code if-gt} rop for the given
* sources. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} source types
* @return {@code non-null;} an appropriate instance
*/
@@ -1394,7 +1394,7 @@
/**
* Returns the appropriate {@code if-le} rop for the given
* sources. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} source types
* @return {@code non-null;} an appropriate instance
*/
@@ -1406,7 +1406,7 @@
* Helper for all the {@code if*}-related methods, which
* checks types and picks one of the four variants, throwing if
* there's a problem.
- *
+ *
* @param types {@code non-null;} the types
* @param intZ {@code non-null;} the int-to-0 comparison
* @param objZ {@code null-ok;} the object-to-null comparison
@@ -1454,7 +1454,7 @@
/**
* Returns the appropriate {@code add} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1467,7 +1467,7 @@
/**
* Returns the appropriate {@code sub} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1480,7 +1480,7 @@
/**
* Returns the appropriate {@code mul} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1493,7 +1493,7 @@
/**
* Returns the appropriate {@code div} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1506,7 +1506,7 @@
/**
* Returns the appropriate {@code rem} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1519,7 +1519,7 @@
/**
* Returns the appropriate {@code and} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1531,7 +1531,7 @@
/**
* Returns the appropriate {@code or} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1543,7 +1543,7 @@
/**
* Returns the appropriate {@code xor} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1555,7 +1555,7 @@
/**
* Returns the appropriate {@code shl} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1567,7 +1567,7 @@
/**
* Returns the appropriate {@code shr} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1579,7 +1579,7 @@
/**
* Returns the appropriate {@code ushr} rop for the given
* types. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} types of the sources
* @return {@code non-null;} an appropriate instance
*/
@@ -1591,7 +1591,7 @@
/**
* Returns the appropriate binary arithmetic rop for the given type
* and arguments. The result is a shared instance.
- *
+ *
* @param types {@code non-null;} sources of the operation
* @param int1 {@code non-null;} the int-to-constant rop
* @param long1 {@code non-null;} the long-to-constant rop
@@ -1640,7 +1640,7 @@
/**
* Returns the appropriate {@code neg} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being operated on
* @return {@code non-null;} an appropriate instance
*/
@@ -1658,7 +1658,7 @@
/**
* Returns the appropriate {@code not} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being operated on
* @return {@code non-null;} an appropriate instance
*/
@@ -1674,7 +1674,7 @@
/**
* Returns the appropriate {@code cmpl} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being compared
* @return {@code non-null;} an appropriate instance
*/
@@ -1691,7 +1691,7 @@
/**
* Returns the appropriate {@code cmpg} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being compared
* @return {@code non-null;} an appropriate instance
*/
@@ -1707,7 +1707,7 @@
/**
* Returns the appropriate {@code conv} rop for the given types. The
* result is a shared instance.
- *
+ *
* @param dest {@code non-null;} target value type
* @param source {@code non-null;} source value type
* @return {@code non-null;} an appropriate instance
@@ -1752,7 +1752,7 @@
/**
* Returns the appropriate {@code return} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of value being returned
* @return {@code non-null;} an appropriate instance
*/
@@ -1772,7 +1772,7 @@
/**
* Returns the appropriate {@code aget} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} element type of array being accessed
* @return {@code non-null;} an appropriate instance
*/
@@ -1795,7 +1795,7 @@
/**
* Returns the appropriate {@code aput} rop for the given type. The
* result is a shared instance.
- *
+ *
* @param type {@code non-null;} element type of array being accessed
* @return {@code non-null;} an appropriate instance
*/
@@ -1818,7 +1818,7 @@
/**
* Returns the appropriate {@code new-array} rop for the given
* type. The result is a shared instance.
- *
+ *
* @param arrayType {@code non-null;} array type of array being created
* @return {@code non-null;} an appropriate instance
*/
@@ -1848,7 +1848,7 @@
/**
* Returns the appropriate {@code filled-new-array} rop for the given
* type. The result may be a shared instance.
- *
+ *
* @param arrayType {@code non-null;} type of array being created
* @param count {@code >= 0;} number of elements that the array should have
* @return {@code non-null;} an appropriate instance
@@ -1880,7 +1880,7 @@
/**
* Returns the appropriate {@code get-field} rop for the given
* type. The result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of the field in question
* @return {@code non-null;} an appropriate instance
*/
@@ -1903,7 +1903,7 @@
/**
* Returns the appropriate {@code put-field} rop for the given
* type. The result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of the field in question
* @return {@code non-null;} an appropriate instance
*/
@@ -1926,7 +1926,7 @@
/**
* Returns the appropriate {@code get-static} rop for the given
* type. The result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of the field in question
* @return {@code non-null;} an appropriate instance
*/
@@ -1949,7 +1949,7 @@
/**
* Returns the appropriate {@code put-static} rop for the given
* type. The result is a shared instance.
- *
+ *
* @param type {@code non-null;} type of the field in question
* @return {@code non-null;} an appropriate instance
*/
@@ -1972,7 +1972,7 @@
/**
* Returns the appropriate {@code invoke-static} rop for the
* given type. The result is typically a newly-allocated instance.
- *
+ *
* @param meth {@code non-null;} descriptor of the method
* @return {@code non-null;} an appropriate instance
*/
@@ -1985,7 +1985,7 @@
/**
* Returns the appropriate {@code invoke-virtual} rop for the
* given type. The result is typically a newly-allocated instance.
- *
+ *
* @param meth {@code non-null;} descriptor of the method, including the
* {@code this} parameter
* @return {@code non-null;} an appropriate instance
@@ -1999,7 +1999,7 @@
/**
* Returns the appropriate {@code invoke-super} rop for the
* given type. The result is typically a newly-allocated instance.
- *
+ *
* @param meth {@code non-null;} descriptor of the method, including the
* {@code this} parameter
* @return {@code non-null;} an appropriate instance
@@ -2013,7 +2013,7 @@
/**
* Returns the appropriate {@code invoke-direct} rop for the
* given type. The result is typically a newly-allocated instance.
- *
+ *
* @param meth {@code non-null;} descriptor of the method, including the
* {@code this} parameter
* @return {@code non-null;} an appropriate instance
@@ -2027,7 +2027,7 @@
/**
* Returns the appropriate {@code invoke-interface} rop for the
* given type. The result is typically a newly-allocated instance.
- *
+ *
* @param meth {@code non-null;} descriptor of the method, including the
* {@code this} parameter
* @return {@code non-null;} an appropriate instance
@@ -2037,7 +2037,7 @@
meth.getParameterFrameTypes(),
StdTypeList.THROWABLE);
}
-
+
/**
* Returns the appropriate {@code mark-local} rop for the given type.
* The result is a shared instance.
@@ -2066,7 +2066,7 @@
/**
* Throws the right exception to complain about a bogus type.
- *
+ *
* @param type {@code non-null;} the bad type
* @return never
*/
@@ -2076,7 +2076,7 @@
/**
* Throws the right exception to complain about a bogus list of types.
- *
+ *
* @param types {@code non-null;} the bad types
* @return never
*/
diff --git a/dx/src/com/android/dx/rop/code/SourcePosition.java b/dx/src/com/android/dx/rop/code/SourcePosition.java
index f32caa1..f7a7961 100644
--- a/dx/src/com/android/dx/rop/code/SourcePosition.java
+++ b/dx/src/com/android/dx/rop/code/SourcePosition.java
@@ -33,19 +33,19 @@
/**
* {@code >= -1;} the bytecode address, or {@code -1} if that
- * information is unknown
+ * information is unknown
*/
private final int address;
/**
* {@code >= -1;} the line number, or {@code -1} if that
- * information is unknown
+ * information is unknown
*/
private final int line;
/**
* Constructs an instance.
- *
+ *
* @param sourceFile {@code null-ok;} name of the file of origin or
* {@code null} if unknown
* @param address {@code >= -1;} original bytecode address or {@code -1}
@@ -117,7 +117,7 @@
/**
* Returns whether the lines match between this instance and
* the one given.
- *
+ *
* @param other {@code non-null;} the instance to compare to
* @return {@code true} iff the lines match
*/
@@ -128,7 +128,7 @@
/**
* Returns whether the lines and files match between this instance and
* the one given.
- *
+ *
* @param other {@code non-null;} the instance to compare to
* @return {@code true} iff the lines and files match
*/
@@ -140,7 +140,7 @@
/**
* Gets the source file, if known.
- *
+ *
* @return {@code null-ok;} the source file or {@code null} if unknown
*/
public CstUtf8 getSourceFile() {
@@ -149,7 +149,7 @@
/**
* Gets the original bytecode address.
- *
+ *
* @return {@code >= -1;} the address or {@code -1} if unknown
*/
public int getAddress() {
@@ -158,7 +158,7 @@
/**
* Gets the original line number.
- *
+ *
* @return {@code >= -1;} the original line number or {@code -1} if
* unknown
*/
diff --git a/dx/src/com/android/dx/rop/code/SwitchInsn.java b/dx/src/com/android/dx/rop/code/SwitchInsn.java
index 586205b..31bb94d 100644
--- a/dx/src/com/android/dx/rop/code/SwitchInsn.java
+++ b/dx/src/com/android/dx/rop/code/SwitchInsn.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param result {@code null-ok;} spec for the result, if any
@@ -110,7 +110,7 @@
/**
* Gets the list of switch cases.
- *
+ *
* @return {@code non-null;} the case list
*/
public IntList getCases() {
diff --git a/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java b/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
index b14e758..cdd21d1 100644
--- a/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
+++ b/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param sources {@code non-null;} specs for all the sources
diff --git a/dx/src/com/android/dx/rop/code/ThrowingInsn.java b/dx/src/com/android/dx/rop/code/ThrowingInsn.java
index 78dc874..6561d41 100644
--- a/dx/src/com/android/dx/rop/code/ThrowingInsn.java
+++ b/dx/src/com/android/dx/rop/code/ThrowingInsn.java
@@ -33,7 +33,7 @@
/**
* Gets the string form of a register spec list to be used as a catches
* list.
- *
+ *
* @param catches {@code non-null;} the catches list
* @return {@code non-null;} the string form
*/
@@ -53,7 +53,7 @@
/**
* Constructs an instance.
- *
+ *
* @param opcode {@code non-null;} the opcode
* @param position {@code non-null;} source position
* @param sources {@code non-null;} specs for all the sources
diff --git a/dx/src/com/android/dx/rop/cst/Constant.java b/dx/src/com/android/dx/rop/cst/Constant.java
index 64231d3..3ef035e 100644
--- a/dx/src/com/android/dx/rop/cst/Constant.java
+++ b/dx/src/com/android/dx/rop/cst/Constant.java
@@ -42,7 +42,7 @@
/**
* {@inheritDoc}
- *
+ *
* This compares in class-major and value-minor order.
*/
public final int compareTo(Constant other) {
@@ -59,7 +59,7 @@
/**
* Compare the values of this and another instance, which are guaranteed
* to be of the same class. Subclasses must implement this.
- *
+ *
* @param other {@code non-null;} the instance to compare to
* @return {@code -1}, {@code 0}, or {@code 1}, as usual
* for a comparison
diff --git a/dx/src/com/android/dx/rop/cst/CstAnnotation.java b/dx/src/com/android/dx/rop/cst/CstAnnotation.java
index 1385798..8cdf1df 100644
--- a/dx/src/com/android/dx/rop/cst/CstAnnotation.java
+++ b/dx/src/com/android/dx/rop/cst/CstAnnotation.java
@@ -24,7 +24,7 @@
public final class CstAnnotation extends Constant {
/** {@code non-null;} the actual annotation */
private final Annotation annotation;
-
+
/**
* Constructs an instance.
*
@@ -87,7 +87,7 @@
/**
* Get the underlying annotation.
- *
+ *
* @return {@code non-null;} the annotation
*/
public Annotation getAnnotation() {
diff --git a/dx/src/com/android/dx/rop/cst/CstArray.java b/dx/src/com/android/dx/rop/cst/CstArray.java
index 8b521bd..cb7d54d 100644
--- a/dx/src/com/android/dx/rop/cst/CstArray.java
+++ b/dx/src/com/android/dx/rop/cst/CstArray.java
@@ -26,7 +26,7 @@
public final class CstArray extends Constant {
/** {@code non-null;} the actual list of contents */
private final List list;
-
+
/**
* Constructs an instance.
*
@@ -89,7 +89,7 @@
/**
* Get the underlying list.
- *
+ *
* @return {@code non-null;} the list
*/
public List getList() {
@@ -104,7 +104,7 @@
/**
* Constructs an instance. All indices initially contain
* {@code null}.
- *
+ *
* @param size the size of the list
*/
public List(int size) {
@@ -139,7 +139,7 @@
* Gets the element at the given index. It is an error to call
* this with the index for an element which was never set; if you
* do that, this will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @return {@code non-null;} element at that index
*/
@@ -149,7 +149,7 @@
/**
* Sets the element at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which index
* @param a {@code null-ok;} the element to set at {@code n}
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
index 039d7ed..5b0aeb6 100644
--- a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
@@ -99,7 +99,7 @@
/**
* {@inheritDoc}
- *
+ *
* In this case, this method returns the <i>return type</i> of this method.
*
* @return {@code non-null;} the method's return type
@@ -117,7 +117,7 @@
* {@code getPrototype().getParameterTypes().getWordCount()},
* plus {@code 1} if the method is to be treated as an
* instance method.
- *
+ *
* @param isStatic whether the method should be considered static
* @return {@code >= 0;} the argument word count
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstBoolean.java b/dx/src/com/android/dx/rop/cst/CstBoolean.java
index 8c290ef..5ff858a 100644
--- a/dx/src/com/android/dx/rop/cst/CstBoolean.java
+++ b/dx/src/com/android/dx/rop/cst/CstBoolean.java
@@ -32,7 +32,7 @@
/**
* Makes an instance for the given value. This will return an
* already-allocated instance.
- *
+ *
* @param value the {@code boolean} value
* @return {@code non-null;} the appropriate instance
*/
@@ -43,7 +43,7 @@
/**
* Makes an instance for the given {@code int} value. This
* will return an already-allocated instance.
- *
+ *
* @param value must be either {@code 0} or {@code 1}
* @return {@code non-null;} the appropriate instance
*/
@@ -59,7 +59,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param value the {@code boolean} value
*/
private CstBoolean(boolean value) {
@@ -90,7 +90,7 @@
/**
* Gets the {@code boolean} value.
- *
+ *
* @return the value
*/
public boolean getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstByte.java b/dx/src/com/android/dx/rop/cst/CstByte.java
index a8af9f7..fc8f58f 100644
--- a/dx/src/com/android/dx/rop/cst/CstByte.java
+++ b/dx/src/com/android/dx/rop/cst/CstByte.java
@@ -26,11 +26,11 @@
extends CstLiteral32 {
/** {@code non-null;} the value {@code 0} as an instance of this class */
public static final CstByte VALUE_0 = make((byte) 0);
-
+
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param value the {@code byte} value
*/
public static CstByte make(byte value) {
@@ -41,7 +41,7 @@
* Makes an instance for the given {@code int} value. This
* may (but does not necessarily) return an already-allocated
* instance.
- *
+ *
* @param value the value, which must be in range for a {@code byte}
* @return {@code non-null;} the appropriate instance
*/
@@ -49,7 +49,7 @@
byte cast = (byte) value;
if (cast != value) {
- throw new IllegalArgumentException("bogus byte value: " +
+ throw new IllegalArgumentException("bogus byte value: " +
value);
}
@@ -58,7 +58,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param value the {@code byte} value
*/
private CstByte(byte value) {
@@ -90,7 +90,7 @@
/**
* Gets the {@code byte} value.
- *
+ *
* @return the value
*/
public byte getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstChar.java b/dx/src/com/android/dx/rop/cst/CstChar.java
index 0a87cbc..21d8b67 100644
--- a/dx/src/com/android/dx/rop/cst/CstChar.java
+++ b/dx/src/com/android/dx/rop/cst/CstChar.java
@@ -30,7 +30,7 @@
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param value the {@code char} value
*/
public static CstChar make(char value) {
@@ -41,7 +41,7 @@
* Makes an instance for the given {@code int} value. This
* may (but does not necessarily) return an already-allocated
* instance.
- *
+ *
* @param value the value, which must be in range for a {@code char}
* @return {@code non-null;} the appropriate instance
*/
@@ -49,7 +49,7 @@
char cast = (char) value;
if (cast != value) {
- throw new IllegalArgumentException("bogus char value: " +
+ throw new IllegalArgumentException("bogus char value: " +
value);
}
@@ -58,7 +58,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param value the {@code char} value
*/
private CstChar(char value) {
@@ -90,7 +90,7 @@
/**
* Gets the {@code char} value.
- *
+ *
* @return the value
*/
public char getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstDouble.java b/dx/src/com/android/dx/rop/cst/CstDouble.java
index df4a2cf..8f1766f 100644
--- a/dx/src/com/android/dx/rop/cst/CstDouble.java
+++ b/dx/src/com/android/dx/rop/cst/CstDouble.java
@@ -35,7 +35,7 @@
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param bits the {@code double} value as {@code long} bits
*/
public static CstDouble make(long bits) {
@@ -48,7 +48,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param bits the {@code double} value as {@code long} bits
*/
private CstDouble(long bits) {
@@ -81,7 +81,7 @@
/**
* Gets the {@code double} value.
- *
+ *
* @return the value
*/
public double getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstEnumRef.java b/dx/src/com/android/dx/rop/cst/CstEnumRef.java
index 78cab9d..641ab3f 100644
--- a/dx/src/com/android/dx/rop/cst/CstEnumRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstEnumRef.java
@@ -25,7 +25,7 @@
public final class CstEnumRef extends CstMemberRef {
/** {@code null-ok;} the corresponding field ref, lazily initialized */
private CstFieldRef fieldRef;
-
+
/**
* Constructs an instance.
*
@@ -45,8 +45,8 @@
}
/**
- * {@inheritDoc}
- *
+ * {@inheritDoc}
+ *
* <b>Note:</b> This returns the enumerated type.
*/
public Type getType() {
@@ -55,7 +55,7 @@
/**
* Get a {@link CstFieldRef} that corresponds with this instance.
- *
+ *
* @return {@code non-null;} the corresponding field reference
*/
public CstFieldRef getFieldRef() {
diff --git a/dx/src/com/android/dx/rop/cst/CstFieldRef.java b/dx/src/com/android/dx/rop/cst/CstFieldRef.java
index 497531f..06f0b15 100644
--- a/dx/src/com/android/dx/rop/cst/CstFieldRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstFieldRef.java
@@ -28,7 +28,7 @@
* primitive type. For example, if given {@link Type#INT}, this
* method returns an instance corresponding to the field
* {@code java.lang.Integer.TYPE}.
- *
+ *
* @param primitiveType {@code non-null;} the primitive type
* @return {@code non-null;} the corresponding static field
*/
@@ -39,7 +39,7 @@
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the type of the defining class
* @param nat {@code non-null;} the name-and-type
*/
@@ -55,7 +55,7 @@
/**
* Returns the type of this field.
- *
+ *
* @return {@code non-null;} the field's type
*/
public Type getType() {
diff --git a/dx/src/com/android/dx/rop/cst/CstFloat.java b/dx/src/com/android/dx/rop/cst/CstFloat.java
index 531a20d..0a2354a 100644
--- a/dx/src/com/android/dx/rop/cst/CstFloat.java
+++ b/dx/src/com/android/dx/rop/cst/CstFloat.java
@@ -36,7 +36,7 @@
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param bits the {@code float} value as {@code int} bits
*/
public static CstFloat make(int bits) {
@@ -49,7 +49,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param bits the {@code float} value as {@code int} bits
*/
private CstFloat(int bits) {
@@ -82,7 +82,7 @@
/**
* Gets the {@code float} value.
- *
+ *
* @return the value
*/
public float getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstInteger.java b/dx/src/com/android/dx/rop/cst/CstInteger.java
index 8fae4fa..3691fc0 100644
--- a/dx/src/com/android/dx/rop/cst/CstInteger.java
+++ b/dx/src/com/android/dx/rop/cst/CstInteger.java
@@ -51,7 +51,7 @@
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param value the {@code int} value
* @return {@code non-null;} the appropriate instance
*/
@@ -75,7 +75,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param value the {@code int} value
*/
private CstInteger(int value) {
@@ -107,7 +107,7 @@
/**
* Gets the {@code int} value.
- *
+ *
* @return the value
*/
public int getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
index 55a7599..8b8cb30 100644
--- a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
@@ -23,13 +23,13 @@
extends CstBaseMethodRef {
/**
* {@code null-ok;} normal {@link CstMethodRef} that corresponds to this
- * instance, if calculated
+ * instance, if calculated
*/
private CstMethodRef methodRef;
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the type of the defining class
* @param nat {@code non-null;} the name-and-type
*/
@@ -47,7 +47,7 @@
/**
* Gets a normal (non-interface) {@link CstMethodRef} that corresponds to
* this instance.
- *
+ *
* @return {@code non-null;} an appropriate instance
*/
public CstMethodRef toMethodRef() {
diff --git a/dx/src/com/android/dx/rop/cst/CstKnownNull.java b/dx/src/com/android/dx/rop/cst/CstKnownNull.java
index 09dde1b..a80322c 100644
--- a/dx/src/com/android/dx/rop/cst/CstKnownNull.java
+++ b/dx/src/com/android/dx/rop/cst/CstKnownNull.java
@@ -88,7 +88,7 @@
/**
* {@inheritDoc}
- *
+ *
* As "literal bits," a known-null is always represented as the
* number zero.
*/
@@ -99,7 +99,7 @@
/**
* {@inheritDoc}
- *
+ *
* As "literal bits," a known-null is always represented as the
* number zero.
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral32.java b/dx/src/com/android/dx/rop/cst/CstLiteral32.java
index c6e3021..042cbd9 100644
--- a/dx/src/com/android/dx/rop/cst/CstLiteral32.java
+++ b/dx/src/com/android/dx/rop/cst/CstLiteral32.java
@@ -26,7 +26,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bits the value as {@code int} bits
*/
/*package*/ CstLiteral32(int bits) {
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral64.java b/dx/src/com/android/dx/rop/cst/CstLiteral64.java
index d0b27d2..94cfa8c 100644
--- a/dx/src/com/android/dx/rop/cst/CstLiteral64.java
+++ b/dx/src/com/android/dx/rop/cst/CstLiteral64.java
@@ -26,7 +26,7 @@
/**
* Constructs an instance.
- *
+ *
* @param bits the value as {@code long} bits
*/
/*package*/ CstLiteral64(long bits) {
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
index 6415487..8bf13a2 100644
--- a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
+++ b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
@@ -45,7 +45,7 @@
* Gets the value as {@code long} bits. If this instance contains
* fewer bits than fit in a {@code long}, then the result of this
* method is the sign extension of the value.
- *
+ *
* @return the bits
*/
public abstract long getLongBits();
@@ -60,7 +60,7 @@
if (! fitsInInt()) {
return false;
}
-
+
int bits = getIntBits();
return (short) bits == bits;
}
diff --git a/dx/src/com/android/dx/rop/cst/CstLong.java b/dx/src/com/android/dx/rop/cst/CstLong.java
index c89a339..d159529 100644
--- a/dx/src/com/android/dx/rop/cst/CstLong.java
+++ b/dx/src/com/android/dx/rop/cst/CstLong.java
@@ -33,7 +33,7 @@
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param value the {@code long} value
*/
public static CstLong make(long value) {
@@ -46,7 +46,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param value the {@code long} value
*/
private CstLong(long value) {
@@ -78,7 +78,7 @@
/**
* Gets the {@code long} value.
- *
+ *
* @return the value
*/
public long getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstMemberRef.java b/dx/src/com/android/dx/rop/cst/CstMemberRef.java
index bae47c2..0791087 100644
--- a/dx/src/com/android/dx/rop/cst/CstMemberRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstMemberRef.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the type of the defining class
* @param nat {@code non-null;} the name-and-type
*/
@@ -53,7 +53,7 @@
}
CstMemberRef otherRef = (CstMemberRef) other;
- return definingClass.equals(otherRef.definingClass) &&
+ return definingClass.equals(otherRef.definingClass) &&
nat.equals(otherRef.nat);
}
@@ -104,7 +104,7 @@
/**
* Gets the type of the defining class.
- *
+ *
* @return {@code non-null;} the type of defining class
*/
public final CstType getDefiningClass() {
@@ -113,7 +113,7 @@
/**
* Gets the defining name-and-type.
- *
+ *
* @return {@code non-null;} the name-and-type
*/
public final CstNat getNat() {
diff --git a/dx/src/com/android/dx/rop/cst/CstMethodRef.java b/dx/src/com/android/dx/rop/cst/CstMethodRef.java
index 77c97e9..075bc7c 100644
--- a/dx/src/com/android/dx/rop/cst/CstMethodRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstMethodRef.java
@@ -23,7 +23,7 @@
extends CstBaseMethodRef {
/**
* Constructs an instance.
- *
+ *
* @param definingClass {@code non-null;} the type of the defining class
* @param nat {@code non-null;} the name-and-type
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstNat.java b/dx/src/com/android/dx/rop/cst/CstNat.java
index 5270fd2..8a2c591 100644
--- a/dx/src/com/android/dx/rop/cst/CstNat.java
+++ b/dx/src/com/android/dx/rop/cst/CstNat.java
@@ -25,7 +25,7 @@
/**
* {@code non-null;} the instance for name {@code TYPE} and descriptor
* {@code java.lang.Class}, which is useful when dealing with
- * wrapped primitives
+ * wrapped primitives
*/
public static final CstNat PRIMITIVE_TYPE_NAT =
new CstNat(new CstUtf8("TYPE"),
@@ -39,7 +39,7 @@
/**
* Constructs an instance.
- *
+ *
* @param name {@code non-null;} the name
* @param descriptor {@code non-null;} the descriptor
*/
@@ -64,7 +64,7 @@
}
CstNat otherNat = (CstNat) other;
- return name.equals(otherNat.name) &&
+ return name.equals(otherNat.name) &&
descriptor.equals(otherNat.descriptor);
}
@@ -107,7 +107,7 @@
/**
* Gets the name.
- *
+ *
* @return {@code non-null;} the name
*/
public CstUtf8 getName() {
@@ -116,7 +116,7 @@
/**
* Gets the descriptor.
- *
+ *
* @return {@code non-null;} the descriptor
*/
public CstUtf8 getDescriptor() {
@@ -126,7 +126,7 @@
/**
* Returns an unadorned but human-readable version of the name-and-type
* value.
- *
+ *
* @return {@code non-null;} the human form
*/
public String toHuman() {
@@ -137,7 +137,7 @@
* Gets the field type corresponding to this instance's descriptor.
* This method is only valid to call if the descriptor in fact describes
* a field (and not a method).
- *
+ *
* @return {@code non-null;} the field type
*/
public Type getFieldType() {
@@ -148,7 +148,7 @@
* Gets whether this instance has the name of a standard instance
* initialization method. This is just a convenient shorthand for
* {@code getName().getString().equals("<init>")}.
- *
+ *
* @return {@code true} iff this is a reference to an
* instance initialization method
*/
@@ -160,7 +160,7 @@
* Gets whether this instance has the name of a standard class
* initialization method. This is just a convenient shorthand for
* {@code getName().getString().equals("<clinit>")}.
- *
+ *
* @return {@code true} iff this is a reference to an
* instance initialization method
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstShort.java b/dx/src/com/android/dx/rop/cst/CstShort.java
index 4ac2f68..5be1022 100644
--- a/dx/src/com/android/dx/rop/cst/CstShort.java
+++ b/dx/src/com/android/dx/rop/cst/CstShort.java
@@ -30,7 +30,7 @@
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
- *
+ *
* @param value the {@code short} value
* @return {@code non-null;} the appropriate instance
*/
@@ -42,7 +42,7 @@
* Makes an instance for the given {@code int} value. This
* may (but does not necessarily) return an already-allocated
* instance.
- *
+ *
* @param value the value, which must be in range for a {@code short}
* @return {@code non-null;} the appropriate instance
*/
@@ -50,7 +50,7 @@
short cast = (short) value;
if (cast != value) {
- throw new IllegalArgumentException("bogus short value: " +
+ throw new IllegalArgumentException("bogus short value: " +
value);
}
@@ -59,7 +59,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
- *
+ *
* @param value the {@code short} value
*/
private CstShort(short value) {
@@ -91,7 +91,7 @@
/**
* Gets the {@code short} value.
- *
+ *
* @return the value
*/
public short getValue() {
diff --git a/dx/src/com/android/dx/rop/cst/CstString.java b/dx/src/com/android/dx/rop/cst/CstString.java
index ce00f52..7dbfa02 100644
--- a/dx/src/com/android/dx/rop/cst/CstString.java
+++ b/dx/src/com/android/dx/rop/cst/CstString.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
- *
+ *
* @param string {@code non-null;} the string value
*/
public CstString(CstUtf8 string) {
@@ -41,7 +41,7 @@
/**
* Constructs an instance.
- *
+ *
* @param string {@code non-null;} the string value
*/
public CstString(String string) {
@@ -100,7 +100,7 @@
/**
* Gets the string value.
- *
+ *
* @return {@code non-null;} the string value
*/
public CstUtf8 getString() {
diff --git a/dx/src/com/android/dx/rop/cst/CstType.java b/dx/src/com/android/dx/rop/cst/CstType.java
index 6dc9867..593adf8 100644
--- a/dx/src/com/android/dx/rop/cst/CstType.java
+++ b/dx/src/com/android/dx/rop/cst/CstType.java
@@ -96,7 +96,7 @@
* class corresponding to a given primitive type. For example, if
* given {@link Type#INT}, this method returns the class reference
* {@code java.lang.Integer}.
- *
+ *
* @param primitiveType {@code non-null;} the primitive type
* @return {@code non-null;} the corresponding wrapper class
*/
@@ -118,7 +118,7 @@
/**
* Returns an interned instance of this class for the given type.
- *
+ *
* @param type {@code non-null;} the underlying type
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -135,7 +135,7 @@
/**
* Constructs an instance.
- *
+ *
* @param type {@code non-null;} the underlying type
*/
public CstType(Type type) {
@@ -208,7 +208,7 @@
* Gets the underlying type (as opposed to the type corresponding
* to this instance as a constant, which is always
* {@code Class}).
- *
+ *
* @return {@code non-null;} the type corresponding to the name
*/
public Type getClassType() {
@@ -217,14 +217,14 @@
/**
* Gets the type descriptor for this instance.
- *
+ *
* @return {@code non-null;} the descriptor
*/
public CstUtf8 getDescriptor() {
if (descriptor == null) {
descriptor = new CstUtf8(type.getDescriptor());
}
-
+
return descriptor;
}
}
diff --git a/dx/src/com/android/dx/rop/cst/CstUtf8.java b/dx/src/com/android/dx/rop/cst/CstUtf8.java
index 2c7a1df..5cfc1f3 100644
--- a/dx/src/com/android/dx/rop/cst/CstUtf8.java
+++ b/dx/src/com/android/dx/rop/cst/CstUtf8.java
@@ -23,12 +23,12 @@
* Constants of type {@code CONSTANT_Utf8_info}.
*/
public final class CstUtf8 extends Constant {
- /**
+ /**
* {@code non-null;} instance representing {@code ""}, that is, the
- * empty string
+ * empty string
*/
public static final CstUtf8 EMPTY_STRING = new CstUtf8("");
-
+
/** {@code non-null;} the UTF-8 value as a string */
private final String string;
@@ -39,7 +39,7 @@
* Converts a string into its Java-style UTF-8 form. Java-style UTF-8
* differs from normal UTF-8 in the handling of character '\0' and
* surrogate pairs.
- *
+ *
* @param string {@code non-null;} the string to convert
* @return {@code non-null;} the UTF-8 bytes for it
*/
@@ -72,7 +72,7 @@
/**
* Converts an array of UTF-8 bytes into a string.
- *
+ *
* @param bytes {@code non-null;} the bytes to convert
* @return {@code non-null;} the converted string
*/
@@ -161,7 +161,7 @@
/**
* Helper for {@link #utf8BytesToString}, which throws the right
* exception for a bogus utf-8 byte.
- *
+ *
* @param value the byte value
* @param offset the file offset
* @return never
@@ -174,7 +174,7 @@
/**
* Constructs an instance from a {@code String}.
- *
+ *
* @param string {@code non-null;} the UTF-8 value as a string
*/
public CstUtf8(String string) {
@@ -188,7 +188,7 @@
/**
* Constructs an instance from some UTF-8 bytes.
- *
+ *
* @param bytes {@code non-null;} array of the UTF-8 bytes
*/
public CstUtf8(ByteArray bytes) {
@@ -266,7 +266,7 @@
*/
char nextChar =
(i < (len - 1)) ? string.charAt(i + 1) : 0;
- boolean displayZero =
+ boolean displayZero =
(nextChar >= '0') && (nextChar <= '7');
sb.append('\\');
for (int shift = 6; shift >= 0; shift -= 3) {
@@ -298,7 +298,7 @@
/**
* Gets the value as a human-oriented string, surrounded by double
* quotes.
- *
+ *
* @return {@code non-null;} the quoted string
*/
public String toQuoted() {
@@ -309,7 +309,7 @@
* Gets the value as a human-oriented string, surrounded by double
* quotes, but ellipsizes the result if it is longer than the given
* maximum length
- *
+ *
* @param maxLength {@code >= 5;} the maximum length of the string to return
* @return {@code non-null;} the quoted string
*/
@@ -331,7 +331,7 @@
/**
* Gets the UTF-8 value as a string.
* The returned string is always already interned.
- *
+ *
* @return {@code non-null;} the UTF-8 value as a string
*/
public String getString() {
@@ -340,7 +340,7 @@
/**
* Gets the UTF-8 value as UTF-8 encoded bytes.
- *
+ *
* @return {@code non-null;} an array of the UTF-8 bytes
*/
public ByteArray getBytes() {
@@ -350,7 +350,7 @@
/**
* Gets the size of this instance as UTF-8 code points. That is,
* get the number of bytes in the UTF-8 encoding of this instance.
- *
+ *
* @return {@code >= 0;} the UTF-8 size
*/
public int getUtf8Size() {
@@ -362,10 +362,10 @@
* get the number of 16-bit chars in the UTF-16 encoding of this
* instance. This is the same as the {@code length} of the
* Java {@code String} representation of this instance.
- *
+ *
* @return {@code >= 0;} the UTF-16 size
*/
public int getUtf16Size() {
return string.length();
- }
+ }
}
diff --git a/dx/src/com/android/dx/rop/cst/StdConstantPool.java b/dx/src/com/android/dx/rop/cst/StdConstantPool.java
index 82c3ab7..244395d 100644
--- a/dx/src/com/android/dx/rop/cst/StdConstantPool.java
+++ b/dx/src/com/android/dx/rop/cst/StdConstantPool.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the pool; this corresponds to the
* class file field {@code constant_pool_count}, and is in fact
* always at least one more than the actual size of the constant pool,
@@ -89,7 +89,7 @@
/**
* Sets the entry at the given index.
- *
+ *
* @param n {@code >= 1, < size();} which entry
* @param cst {@code null-ok;} the constant to store
*/
@@ -127,7 +127,7 @@
/**
* Throws the right exception for an invalid cpi.
- *
+ *
* @param idx the bad cpi
* @return never
* @throws ExceptionWithContext always thrown
diff --git a/dx/src/com/android/dx/rop/cst/TypedConstant.java b/dx/src/com/android/dx/rop/cst/TypedConstant.java
index 823d9c4..c250c46 100644
--- a/dx/src/com/android/dx/rop/cst/TypedConstant.java
+++ b/dx/src/com/android/dx/rop/cst/TypedConstant.java
@@ -25,7 +25,7 @@
extends Constant implements TypeBearer {
/**
* {@inheritDoc}
- *
+ *
* This implentation always returns {@code this}.
*/
public final TypeBearer getFrameType() {
diff --git a/dx/src/com/android/dx/rop/cst/Zeroes.java b/dx/src/com/android/dx/rop/cst/Zeroes.java
index 8bed657..7250b5a 100644
--- a/dx/src/com/android/dx/rop/cst/Zeroes.java
+++ b/dx/src/com/android/dx/rop/cst/Zeroes.java
@@ -28,10 +28,10 @@
private Zeroes() {
// This space intentionally left blank.
}
-
+
/**
* Gets the "zero" (or {@code null}) value for the given type.
- *
+ *
* @param type {@code non-null;} the type in question
* @return {@code non-null;} its "zero" value
*/
diff --git a/dx/src/com/android/dx/rop/type/Prototype.java b/dx/src/com/android/dx/rop/type/Prototype.java
index 7e6ab59..cbd5328 100644
--- a/dx/src/com/android/dx/rop/type/Prototype.java
+++ b/dx/src/com/android/dx/rop/type/Prototype.java
@@ -41,10 +41,10 @@
private StdTypeList parameterFrameTypes;
/**
- * Returns the unique instance corresponding to the
+ * Returns the unique instance corresponding to the
* given method descriptor. See vmspec-2 sec4.3.3 for details on the
* field descriptor syntax.
- *
+ *
* @param descriptor {@code non-null;} the descriptor
* @return {@code non-null;} the corresponding instance
* @throws IllegalArgumentException thrown if the descriptor has
@@ -110,7 +110,7 @@
* populate with parsed parameter types, and which also ensures
* that there is a '(' at the start of the descriptor and a
* single ')' somewhere before the end.
- *
+ *
* @param descriptor {@code non-null;} the descriptor string
* @return {@code non-null;} array large enough to hold all parsed parameter
* types, but which is likely actually larger than needed
@@ -155,7 +155,7 @@
* on the given definer, name, and flags. For example, an init
* method has an uninitialized object of type {@code definer}
* as its first argument.
- *
+ *
* @param descriptor {@code non-null;} the descriptor string
* @param definer {@code non-null;} class the method is defined on
* @param isStatic whether this is a static method
@@ -180,7 +180,7 @@
/**
* Interns an instance which consists of the given number of
* {@code int}s along with the given return type
- *
+ *
* @param returnType {@code non-null;} the return type
* @param count {@code > 0;} the number of elements in the prototype
* @return {@code non-null;} the interned instance
@@ -206,7 +206,7 @@
/**
* Constructs an instance. This is a private constructor; use one
* of the public static methods to get instances.
- *
+ *
* @param descriptor {@code non-null;} the descriptor string
*/
private Prototype(String descriptor, Type returnType,
@@ -258,7 +258,7 @@
if (this == other) {
return 0;
}
-
+
/*
* The return type is the major order, and then args in order,
* and then the shorter list comes first (similar to string
@@ -303,7 +303,7 @@
/**
* Gets the descriptor string.
- *
+ *
* @return {@code non-null;} the descriptor
*/
public String getDescriptor() {
@@ -312,7 +312,7 @@
/**
* Gets the return type.
- *
+ *
* @return {@code non-null;} the return type
*/
public Type getReturnType() {
@@ -321,7 +321,7 @@
/**
* Gets the list of parameter types.
- *
+ *
* @return {@code non-null;} the list of parameter types
*/
public StdTypeList getParameterTypes() {
@@ -333,7 +333,7 @@
* types. The difference between the two lists (if any) is that all
* "intlike" types (see {@link Type#isIntlike}) are replaced by
* {@link Type#INT}.
- *
+ *
* @return {@code non-null;} the list of parameter frame types
*/
public StdTypeList getParameterFrameTypes() {
@@ -359,7 +359,7 @@
* Returns a new interned instance, which is the same as this instance,
* except that it has an additional parameter prepended to the original's
* argument list.
- *
+ *
* @param param {@code non-null;} the new first parameter
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -379,7 +379,7 @@
* Puts the given instance in the intern table if it's not already
* there. If a conflicting value is already in the table, then leave it.
* Return the interned value.
- *
+ *
* @param desc {@code non-null;} instance to make interned
* @return {@code non-null;} the actual interned object
*/
diff --git a/dx/src/com/android/dx/rop/type/StdTypeList.java b/dx/src/com/android/dx/rop/type/StdTypeList.java
index a023812..fe6647c0 100644
--- a/dx/src/com/android/dx/rop/type/StdTypeList.java
+++ b/dx/src/com/android/dx/rop/type/StdTypeList.java
@@ -163,7 +163,7 @@
/**
* Makes a single-element instance.
- *
+ *
* @param type {@code non-null;} the element
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -175,7 +175,7 @@
/**
* Makes a two-element instance.
- *
+ *
* @param type0 {@code non-null;} the first element
* @param type1 {@code non-null;} the second element
* @return {@code non-null;} an appropriately-constructed instance
@@ -189,7 +189,7 @@
/**
* Makes a three-element instance.
- *
+ *
* @param type0 {@code non-null;} the first element
* @param type1 {@code non-null;} the second element
* @param type2 {@code non-null;} the third element
@@ -205,7 +205,7 @@
/**
* Makes a four-element instance.
- *
+ *
* @param type0 {@code non-null;} the first element
* @param type1 {@code non-null;} the second element
* @param type2 {@code non-null;} the third element
@@ -226,7 +226,7 @@
* Returns the given list as a comma-separated list of human forms. This
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
- *
+ *
* @param list {@code non-null;} the list to convert
* @return {@code non-null;} the human form
*/
@@ -236,7 +236,7 @@
if (size == 0) {
return "<empty>";
}
-
+
StringBuffer sb = new StringBuffer(100);
for (int i = 0; i < size; i++) {
@@ -253,7 +253,7 @@
* Returns a hashcode of the contents of the given list. This
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
- *
+ *
* @param list {@code non-null;} the list to inspect
* @return {@code non-null;} the hash code
*/
@@ -267,12 +267,12 @@
return hash;
}
-
+
/**
* Compares the contents of the given two instances for equality. This
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
- *
+ *
* @param list1 {@code non-null;} one list to compare
* @param list2 {@code non-null;} another list to compare
* @return whether the two lists contain corresponding equal elements
@@ -297,7 +297,7 @@
* Compares the contents of the given two instances for ordering. This
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
- *
+ *
* @param list1 {@code non-null;} one list to compare
* @param list2 {@code non-null;} another list to compare
* @return the order of the two lists
@@ -322,10 +322,10 @@
return 1;
}
}
-
+
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public StdTypeList(int size) {
@@ -367,7 +367,7 @@
* Gets the indicated element. It is an error to call this with the
* index for an element which was never set; if you do that, this
* will throw {@code NullPointerException}.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @return {@code non-null;} the indicated element
*/
@@ -377,7 +377,7 @@
/**
* Sets the type at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param type {@code non-null;} the type to store
*/
@@ -389,7 +389,7 @@
* Returns a new instance, which is the same as this instance,
* except that it has an additional type prepended to the
* original.
- *
+ *
* @param type {@code non-null;} the new first element
* @return {@code non-null;} an appropriately-constructed instance
*/
diff --git a/dx/src/com/android/dx/rop/type/Type.java b/dx/src/com/android/dx/rop/type/Type.java
index 64c3c30..16b16f5 100644
--- a/dx/src/com/android/dx/rop/type/Type.java
+++ b/dx/src/com/android/dx/rop/type/Type.java
@@ -28,7 +28,7 @@
*/
public final class Type implements TypeBearer, Comparable<Type> {
/** {@code non-null;} intern table mapping string descriptors to instances */
- private static final HashMap<String, Type> internTable =
+ private static final HashMap<String, Type> internTable =
new HashMap<String, Type>(500);
/** basic type constant for {@code void} */
@@ -147,63 +147,63 @@
/**
* {@code non-null;} instance representing {@code java.lang.Boolean}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;");
/**
* {@code non-null;} instance representing {@code java.lang.Byte}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;");
/**
* {@code non-null;} instance representing {@code java.lang.Character}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;");
/**
* {@code non-null;} instance representing {@code java.lang.Double}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;");
/**
* {@code non-null;} instance representing {@code java.lang.Float}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;");
/**
* {@code non-null;} instance representing {@code java.lang.Integer}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;");
/**
* {@code non-null;} instance representing {@code java.lang.Long}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type LONG_CLASS = intern("Ljava/lang/Long;");
/**
* {@code non-null;} instance representing {@code java.lang.Short}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type SHORT_CLASS = intern("Ljava/lang/Short;");
/**
* {@code non-null;} instance representing {@code java.lang.Void}; the
* suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ * representing a primitive type
*/
public static final Type VOID_CLASS = intern("Ljava/lang/Void;");
@@ -239,7 +239,7 @@
/**
* basic type corresponding to this type; one of the
- * {@code BT_*} constants
+ * {@code BT_*} constants
*/
private final int basicType;
@@ -247,32 +247,32 @@
* {@code >= -1;} for an uninitialized type, bytecode index that this
* instance was allocated at; {@code Integer.MAX_VALUE} if it
* was an incoming uninitialized instance; {@code -1} if this
- * is an <i>inititialized</i> instance
+ * is an <i>inititialized</i> instance
*/
private final int newAt;
/**
* {@code null-ok;} the internal-form class name corresponding to this type, if
* calculated; only valid if {@code this} is a reference type and
- * additionally not a return address
+ * additionally not a return address
*/
private String className;
/**
* {@code null-ok;} the type corresponding to an array of this type, if
- * calculated
+ * calculated
*/
private Type arrayType;
/**
* {@code null-ok;} the type corresponding to elements of this type, if
- * calculated; only valid if {@code this} is an array type
+ * calculated; only valid if {@code this} is an array type
*/
private Type componentType;
/**
* {@code null-ok;} the type corresponding to the initialized version of
- * this type, if this instance is in fact an uninitialized type
+ * this type, if this instance is in fact an uninitialized type
*/
private Type initializedType;
@@ -282,7 +282,7 @@
* field descriptor syntax. This method does <i>not</i> allow
* {@code "V"} (that is, type {@code void}) as a valid
* descriptor.
- *
+ *
* @param descriptor {@code non-null;} the descriptor
* @return {@code non-null;} the corresponding instance
* @throws IllegalArgumentException thrown if the descriptor has
@@ -339,8 +339,8 @@
char c = descriptor.charAt(i);
switch (c) {
case '[':
- case ';':
- case '.':
+ case ';':
+ case '.':
case '(':
case ')': {
throw new IllegalArgumentException("bad descriptor");
@@ -365,7 +365,7 @@
* given descriptor, allowing {@code "V"} to return the type
* for {@code void}. Other than that one caveat, this method
* is identical to {@link #intern}.
- *
+ *
* @param descriptor {@code non-null;} the descriptor
* @return {@code non-null;} the corresponding instance
* @throws IllegalArgumentException thrown if the descriptor has
@@ -391,7 +391,7 @@
* calling {@code intern(name)} if {@code name} begins
* with {@code "["} and calling {@code intern("L" + name + ";")}
* in all other cases.
- *
+ *
* @param name {@code non-null;} the name of the class whose type is desired
* @return {@code non-null;} the corresponding type
* @throws IllegalArgumentException thrown if the name has
@@ -413,7 +413,7 @@
* Constructs an instance corresponding to an "uninitialized type."
* This is a private constructor; use one of the public static
* methods to get instances.
- *
+ *
* @param descriptor {@code non-null;} the field descriptor for the type
* @param basicType basic type corresponding to this type; one of the
* {@code BT_*} constants
@@ -444,7 +444,7 @@
* Constructs an instance corresponding to an "initialized type."
* This is a private constructor; use one of the public static
* methods to get instances.
- *
+ *
* @param descriptor {@code non-null;} the field descriptor for the type
* @param basicType basic type corresponding to this type; one of the
* {@code BT_*} constants
@@ -559,7 +559,7 @@
/**
* Gets the descriptor.
- *
+ *
* @return {@code non-null;} the descriptor
*/
public String getDescriptor() {
@@ -571,7 +571,7 @@
* form. This method is only valid if this instance is for a
* normal reference type (that is, a reference type and
* additionally not a return address).
- *
+ *
* @return {@code non-null;} the internal-form class name
*/
public String getClassName() {
@@ -594,7 +594,7 @@
/**
* Gets the category. Most instances are category 1. {@code long}
* and {@code double} are the only category 2 types.
- *
+ *
* @see #isCategory1
* @see #isCategory2
* @return the category
@@ -612,7 +612,7 @@
/**
* Returns whether or not this is a category 1 type.
- *
+ *
* @see #getCategory
* @see #isCategory2
* @return whether or not this is a category 1 type
@@ -630,7 +630,7 @@
/**
* Returns whether or not this is a category 2 type.
- *
+ *
* @see #getCategory
* @see #isCategory1
* @return whether or not this is a category 2 type
@@ -650,7 +650,7 @@
* Gets whether this type is "intlike." An intlike type is one which, when
* placed on a stack or in a local, is automatically converted to an
* {@code int}.
- *
+ *
* @return whether this type is "intlike"
*/
public boolean isIntlike() {
@@ -670,7 +670,7 @@
/**
* Gets whether this type is a primitive type. All types are either
* primitive or reference types.
- *
+ *
* @return whether this type is primitive
*/
public boolean isPrimitive() {
@@ -696,7 +696,7 @@
* reference type is a reference type that is not a return
* address. This method is just convenient shorthand for
* {@code getBasicType() == Type.BT_OBJECT}.
- *
+ *
* @return whether this type is a normal reference type
*/
public boolean isReference() {
@@ -707,7 +707,7 @@
* Gets whether this type is an array type. If this method returns
* {@code true}, then it is safe to use {@link #getComponentType}
* to determine the component type.
- *
+ *
* @return whether this type is an array type
*/
public boolean isArray() {
@@ -717,7 +717,7 @@
/**
* Gets whether this type is an array type or is a known-null, and
* hence is compatible with array types.
- *
+ *
* @return whether this type is an array type
*/
public boolean isArrayOrKnownNull() {
@@ -729,7 +729,7 @@
* uninitialized instance is what one gets back from the {@code new}
* opcode, and remains uninitialized until a valid constructor is
* invoked on it.
- *
+ *
* @return whether this type is "uninitialized"
*/
public boolean isUninitialized() {
@@ -742,7 +742,7 @@
* type is an uninitialized incoming parameter (i.e., the
* {@code this} of an {@code <init>} method) or
* {@code -1} if this type is in fact <i>initialized</i>.
- *
+ *
* @return {@code >= -1;} the allocation bytecode index
*/
public int getNewAt() {
@@ -752,7 +752,7 @@
/**
* Gets the initialized type corresponding to this instance, but only
* if this instance is in fact an uninitialized object type.
- *
+ *
* @return {@code non-null;} the initialized type
*/
public Type getInitializedType() {
@@ -766,7 +766,7 @@
/**
* Gets the type corresponding to an array of this type.
- *
+ *
* @return {@code non-null;} the array type
*/
public Type getArrayType() {
@@ -780,7 +780,7 @@
/**
* Gets the component type of this type. This method is only valid on
* array types.
- *
+ *
* @return {@code non-null;} the component type
*/
public Type getComponentType() {
@@ -799,7 +799,7 @@
* Returns a new interned instance which is identical to this one, except
* it is indicated as uninitialized and allocated at the given bytecode
* index. This instance must be an initialized object type.
- *
+ *
* @param newAt {@code >= 0;} the allocation bytecode index
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -837,7 +837,7 @@
* Puts the given instance in the intern table if it's not already
* there. If a conflicting value is already in the table, then leave it.
* Return the interned value.
- *
+ *
* @param type {@code non-null;} instance to make interned
* @return {@code non-null;} the actual interned object
*/
diff --git a/dx/src/com/android/dx/rop/type/TypeBearer.java b/dx/src/com/android/dx/rop/type/TypeBearer.java
index 2f2f274..b03dbaf 100644
--- a/dx/src/com/android/dx/rop/type/TypeBearer.java
+++ b/dx/src/com/android/dx/rop/type/TypeBearer.java
@@ -55,10 +55,10 @@
* is the same as calling {@code getFrameType()} unless this
* instance is an int-like type, in which case this method returns
* {@code BT_INT}.
- *
+ *
* @see #getBasicType
* @see #getFrameType
- *
+ *
* @return the basic frame type; one of the {@code BT_*} constants
* defined by {@link Type}
*/
@@ -66,7 +66,7 @@
/**
* Returns whether this instance represents a constant value.
- *
+ *
* @return {@code true} if this instance represents a constant value
* and {@code false} if not
*/
diff --git a/dx/src/com/android/dx/rop/type/TypeList.java b/dx/src/com/android/dx/rop/type/TypeList.java
index e82cca7..de2d62e 100644
--- a/dx/src/com/android/dx/rop/type/TypeList.java
+++ b/dx/src/com/android/dx/rop/type/TypeList.java
@@ -25,12 +25,12 @@
* {@code TypeList} interface itself doesn't provide any
* means of mutation, but that doesn't mean that there isn't an
* extra-interface way of mutating an instance.
- *
+ *
* @return {@code true} if this instance is mutable or
* {@code false} if it is immutable
*/
public boolean isMutable();
-
+
/**
* Gets the size of this list.
*
@@ -52,7 +52,7 @@
* Gets the number of 32-bit words required to hold instances of
* all the elements of this list. This is a sum of the widths (categories)
* of all the elements.
- *
+ *
* @return {@code >= 0;} the required number of words
*/
public int getWordCount();
@@ -61,7 +61,7 @@
* Returns a new instance which is identical to this one, except that
* the given item is appended to the end and it is guaranteed to be
* immutable.
- *
+ *
* @param type {@code non-null;} item to append
* @return {@code non-null;} an appropriately-constructed instance
*/
diff --git a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
index fdabaab..83045b2 100644
--- a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
+++ b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
@@ -33,7 +33,7 @@
/**
* Creates a new OneToOneRegisterMapper.
- *
+ *
* @param countOldRegisters the number of registers in the old name space
*/
public BasicRegisterMapper(int countOldRegisters) {
diff --git a/dx/src/com/android/dx/ssa/ConstCollector.java b/dx/src/com/android/dx/ssa/ConstCollector.java
index 03252d1..7aa512d 100644
--- a/dx/src/com/android/dx/ssa/ConstCollector.java
+++ b/dx/src/com/android/dx/ssa/ConstCollector.java
@@ -71,7 +71,7 @@
/**
* Constructs an instance.
- *
+ *
* @param ssaMethod {@code non-null;} method to process
*/
private ConstCollector(SsaMethod ssaMethod) {
@@ -86,7 +86,7 @@
ArrayList<TypedConstant> constantList
= getConstsSortedByCountUse();
-
+
int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);
SsaBasicBlock start = ssaMeth.getEntryBlock();
@@ -126,7 +126,7 @@
SsaBasicBlock resultBlock
= constBlock.insertNewSuccessor(successorBlock);
- PlainInsn insn
+ PlainInsn insn
= new PlainInsn(
Rops.opMoveResultPseudo(result.getTypeBearer()),
SourcePosition.NO_INFO,
@@ -184,7 +184,7 @@
}
/*
* We can't move any throwable const whose throw will be
- * caught, so don't count them.
+ * caught, so don't count them.
*/
if (insn.getBlock().getSuccessors().cardinality() > 1) {
continue;
@@ -255,7 +255,7 @@
* variable, then insert a mark-local for {@code newReg} just below
* it. We expect the definition of {@code origReg} to ultimately
* be removed by the dead code eliminator
- *
+ *
* @param origReg {@code non-null;} original register
* @param newReg {@code non-null;} new register that will replace
* {@code origReg}
@@ -338,7 +338,7 @@
if (ssaMeth.isRegALocal(origReg)) {
if (!COLLECT_ONE_LOCAL) {
- continue;
+ continue;
} else {
/*
* TODO: If the same local gets the same cst
diff --git a/dx/src/com/android/dx/ssa/DeadCodeRemover.java b/dx/src/com/android/dx/ssa/DeadCodeRemover.java
index ec960b8..2a29050 100644
--- a/dx/src/com/android/dx/ssa/DeadCodeRemover.java
+++ b/dx/src/com/android/dx/ssa/DeadCodeRemover.java
@@ -53,7 +53,7 @@
/**
* Process a method with the dead-code remver
- *
+ *
* @param ssaMethod method to process
*/
public static void process(SsaMethod ssaMethod) {
@@ -63,7 +63,7 @@
/**
* Constructs an instance.
- *
+ *
* @param ssaMethod method to process
*/
private DeadCodeRemover(SsaMethod ssaMethod) {
@@ -127,7 +127,7 @@
/**
* Returns true if the only uses of this register form a circle of
* operations with no side effects.
- *
+ *
* @param regV register to examine
* @param set a set of registers that we've already determined
* are only used as sources in operations with no side effect or null
@@ -179,7 +179,7 @@
return true;
}
- return insn.hasSideEffect();
+ return insn.hasSideEffect();
}
/**
diff --git a/dx/src/com/android/dx/ssa/DomFront.java b/dx/src/com/android/dx/ssa/DomFront.java
index 3005015..941a317 100644
--- a/dx/src/com/android/dx/ssa/DomFront.java
+++ b/dx/src/com/android/dx/ssa/DomFront.java
@@ -37,7 +37,7 @@
private final SsaMethod meth;
private final ArrayList<SsaBasicBlock> nodes;
-
+
private final DomInfo[] domInfos;
/**
@@ -55,8 +55,8 @@
}
/**
- * Constructs instance. Call {@link DomFront#run} to process.
- *
+ * Constructs instance. Call {@link DomFront#run} to process.
+ *
* @param meth {@code non-null;} method to process
*/
public DomFront(SsaMethod meth) {
@@ -98,7 +98,7 @@
}
buildDomTree();
-
+
if (DEBUG) {
debugPrintDomChildren();
}
@@ -153,6 +153,9 @@
for (int i = 0; i < szNodes; i++) {
DomInfo info = domInfos[i];
+
+ if (info.idom == -1) continue;
+
SsaBasicBlock domParent = nodes.get(info.idom);
domParent.addDomChild(nodes.get(i));
}
@@ -182,6 +185,8 @@
* added label to, since we must be at a part
* of the dom tree we have seen before.
*/
+ if (runnerIndex == -1) break;
+
DomInfo runnerInfo = domInfos[runnerIndex];
if (runnerInfo.dominanceFrontiers.has(b)) {
diff --git a/dx/src/com/android/dx/ssa/Dominators.java b/dx/src/com/android/dx/ssa/Dominators.java
index f7d7da6..503e857 100644
--- a/dx/src/com/android/dx/ssa/Dominators.java
+++ b/dx/src/com/android/dx/ssa/Dominators.java
@@ -60,7 +60,7 @@
/**
* Constructs an instance.
- *
+ *
* @param meth {@code non-null;} method to process
* @param domInfos {@code non-null;} the raw dominator info
* @param postdom true for postdom information, false for normal dom info
@@ -78,7 +78,7 @@
/**
* Constructs a fully-initialized instance. (This method exists so as
* to avoid calling a large amount of code in the constructor.)
- *
+ *
* @param meth {@code non-null;} method to process
* @param domInfos {@code non-null;} the raw dominator info
* @param postdom true for postdom information, false for normal dom info
@@ -109,7 +109,7 @@
/**
* Performs path compress on the DFS info.
- *
+ *
* @param in Basic block whose DFS info we are path compressing.
*/
private void compress(SsaBasicBlock in) {
@@ -120,7 +120,7 @@
ArrayList<SsaBasicBlock> worklist = new ArrayList<SsaBasicBlock>();
HashSet<SsaBasicBlock> visited = new HashSet<SsaBasicBlock>();
worklist.add(in);
-
+
while (!worklist.isEmpty()) {
int wsize = worklist.size();
SsaBasicBlock v = worklist.get(wsize - 1);
@@ -164,7 +164,7 @@
/**
* Performs dominator/post-dominator calculation for the control
* flow graph.
- *
+ *
* @param meth {@code non-null;} method to analyze
*/
private void run() {
@@ -175,7 +175,7 @@
vertex.add(root);
domInfos[root.getIndex()].idom = root.getIndex();
}
-
+
/*
* First we perform a DFS numbering of the blocks, by
* numbering the dfs tree roots.
diff --git a/dx/src/com/android/dx/ssa/EscapeAnalysis.java b/dx/src/com/android/dx/ssa/EscapeAnalysis.java
new file mode 100644
index 0000000..d270857
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/EscapeAnalysis.java
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.Exceptions;
+import com.android.dx.rop.code.FillArrayDataInsn;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.ThrowingCstInsn;
+import com.android.dx.rop.code.ThrowingInsn;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstUtf8;
+import com.android.dx.rop.cst.TypedConstant;
+import com.android.dx.rop.cst.Zeroes;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Simple intraprocedural escape analysis. Finds new arrays that don't escape
+ * the method they are created in and replaces the array values with registers.
+ */
+public class EscapeAnalysis {
+ /**
+ * Struct used to generate and maintain escape analysis results.
+ */
+ static class EscapeSet {
+ /** set containing all registers related to an object */
+ BitSet regSet;
+ /** escape state of the object */
+ EscapeState escape;
+ /** list of objects that are put into this object */
+ ArrayList<EscapeSet> childSets;
+ /** list of objects that this object is put into */
+ ArrayList<EscapeSet> parentSets;
+ /** flag to indicate this object is a scalar replaceable array */
+ boolean replaceableArray;
+
+ /**
+ * Constructs an instance of an EscapeSet
+ *
+ * @param reg the SSA register that defines the object
+ * @param size the number of registers in the method
+ * @param escState the lattice value to initially set this to
+ */
+ EscapeSet(int reg, int size, EscapeState escState) {
+ regSet = new BitSet(size);
+ regSet.set(reg);
+ escape = escState;
+ childSets = new ArrayList<EscapeSet>();
+ parentSets = new ArrayList<EscapeSet>();
+ replaceableArray = false;
+ }
+ }
+
+ /**
+ * Lattice values used to indicate escape state for an object. Analysis can
+ * only raise escape state values, not lower them.
+ *
+ * TOP - Used for objects that haven't been analyzed yet
+ * NONE - Object does not escape, and is eligible for scalar replacement.
+ * METHOD - Object remains local to method, but can't be scalar replaced.
+ * INTER - Object is passed between methods. (treated as globally escaping
+ * since this is an intraprocedural analysis)
+ * GLOBAL - Object escapes globally.
+ */
+ public enum EscapeState {
+ TOP, NONE, METHOD, INTER, GLOBAL
+ }
+
+ /** method we're processing */
+ private SsaMethod ssaMeth;
+ /** ssaMeth.getRegCount() */
+ private int regCount;
+ /** Lattice values for each object register group */
+ private ArrayList<EscapeSet> latticeValues;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMeth method to process
+ */
+ private EscapeAnalysis(SsaMethod ssaMeth) {
+ this.ssaMeth = ssaMeth;
+ this.regCount = ssaMeth.getRegCount();
+ this.latticeValues = new ArrayList<EscapeSet>();
+ }
+
+ /**
+ * Finds the index in the lattice for a particular register.
+ * Returns the size of the lattice if the register wasn't found.
+ *
+ * @param reg {@code non-null;} register being looked up
+ * @return index of the register or size of the lattice if it wasn't found.
+ */
+ private int findSetIndex(RegisterSpec reg) {
+ int i;
+ for (i = 0; i < latticeValues.size(); i++) {
+ EscapeSet e = latticeValues.get(i);
+ if (e.regSet.get(reg.getReg())) {
+ return i;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Finds the corresponding instruction for a given move result
+ *
+ * @param moveInsn {@code non-null;} a move result instruction
+ * @return {@code non-null;} the instruction that produces the result for
+ * the move
+ */
+ private SsaInsn getInsnForMove(SsaInsn moveInsn) {
+ int pred = moveInsn.getBlock().getPredecessors().nextSetBit(0);
+ ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+ return predInsns.get(predInsns.size()-1);
+ }
+
+ /**
+ * Finds the corresponding move result for a given instruction
+ *
+ * @param insn {@code non-null;} an instruction that must always be
+ * followed by a move result
+ * @return {@code non-null;} the move result for the given instruction
+ */
+ private SsaInsn getMoveForInsn(SsaInsn insn) {
+ int succ = insn.getBlock().getSuccessors().nextSetBit(0);
+ ArrayList<SsaInsn> succInsns = ssaMeth.getBlocks().get(succ).getInsns();
+ return succInsns.get(0);
+ }
+
+ /**
+ * Creates a link in the lattice between two EscapeSets due to a put
+ * instruction. The object being put is the child and the object being put
+ * into is the parent. A child set must always have an escape state at
+ * least as high as its parent.
+ *
+ * @param parentSet {@code non-null;} the EscapeSet for the object being put
+ * into
+ * @param childSet {@code non-null;} the EscapeSet for the object being put
+ */
+ private void addEdge(EscapeSet parentSet, EscapeSet childSet) {
+ if (!childSet.parentSets.contains(parentSet)) {
+ childSet.parentSets.add(parentSet);
+ }
+ if (!parentSet.childSets.contains(childSet)) {
+ parentSet.childSets.add(childSet);
+ }
+ }
+
+ /**
+ * Merges all links in the lattice among two EscapeSets. On return, the
+ * newNode will have its old links as well as all links from the oldNode.
+ * The oldNode has all its links removed.
+ *
+ * @param newNode {@code non-null;} the EscapeSet to merge all links into
+ * @param oldNode {@code non-null;} the EscapeSet to remove all links from
+ */
+ private void replaceNode(EscapeSet newNode, EscapeSet oldNode) {
+ for (EscapeSet e : oldNode.parentSets) {
+ e.childSets.remove(oldNode);
+ e.childSets.add(newNode);
+ newNode.parentSets.add(e);
+ }
+ for (EscapeSet e : oldNode.childSets) {
+ e.parentSets.remove(oldNode);
+ e.parentSets.add(newNode);
+ newNode.childSets.add(e);
+ }
+ }
+
+ /**
+ * Performs escape analysis on a method. Finds scalar replaceable arrays and
+ * replaces them with equivalent registers.
+ *
+ * @param ssaMethod {@code non-null;} method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ new EscapeAnalysis(ssaMethod).run();
+ }
+
+ /**
+ * Process a single instruction, looking for new objects resulting from
+ * move result or move param.
+ *
+ * @param insn {@code non-null;} instruction to process
+ */
+ private void processInsn(SsaInsn insn) {
+ int op = insn.getOpcode().getOpcode();
+ RegisterSpec result = insn.getResult();
+ EscapeSet escSet;
+
+ // Identify new objects
+ if (op == RegOps.MOVE_RESULT_PSEUDO &&
+ result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+ // Handle objects generated through move_result_pseudo
+ escSet = processMoveResultPseudoInsn(insn);
+ processRegister(result, escSet);
+ } else if (op == RegOps.MOVE_PARAM &&
+ result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+ // Track method arguments that are objects
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+ latticeValues.add(escSet);
+ processRegister(result, escSet);
+ } else if (op == RegOps.MOVE_RESULT &&
+ result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+ // Track method return values that are objects
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+ latticeValues.add(escSet);
+ processRegister(result, escSet);
+ }
+ }
+
+ /**
+ * Determine the origin of a move result pseudo instruction that generates
+ * an object. Creates a new EscapeSet for the new object accordingly.
+ *
+ * @param insn {@code non-null;} move result pseudo instruction to process
+ * @return {@code non-null;} an EscapeSet for the object referred to by the
+ * move result pseudo instruction
+ */
+ private EscapeSet processMoveResultPseudoInsn(SsaInsn insn) {
+ RegisterSpec result = insn.getResult();
+ SsaInsn prevSsaInsn = getInsnForMove(insn);
+ int prevOpcode = prevSsaInsn.getOpcode().getOpcode();
+ EscapeSet escSet;
+ RegisterSpec prevSource;
+
+ switch(prevOpcode) {
+ // New instance / Constant
+ case RegOps.NEW_INSTANCE:
+ case RegOps.CONST:
+ escSet = new EscapeSet(result.getReg(), regCount,
+ EscapeState.NONE);
+ break;
+ // New array
+ case RegOps.NEW_ARRAY:
+ case RegOps.FILLED_NEW_ARRAY:
+ prevSource = prevSsaInsn.getSources().get(0);
+ if (prevSource.getTypeBearer().isConstant()) {
+ // New fixed array
+ escSet = new EscapeSet(result.getReg(), regCount,
+ EscapeState.NONE);
+ escSet.replaceableArray = true;
+ } else {
+ // New variable array
+ escSet = new EscapeSet(result.getReg(), regCount,
+ EscapeState.GLOBAL);
+ }
+ break;
+ // Loading a static object
+ case RegOps.GET_STATIC:
+ escSet = new EscapeSet(result.getReg(), regCount,
+ EscapeState.GLOBAL);
+ break;
+ // Type cast / load an object from a field or array
+ case RegOps.CHECK_CAST:
+ case RegOps.GET_FIELD:
+ case RegOps.AGET:
+ prevSource = prevSsaInsn.getSources().get(0);
+ int setIndex = findSetIndex(prevSource);
+
+ // Set should already exist, try to find it
+ if (setIndex != latticeValues.size()) {
+ escSet = latticeValues.get(setIndex);
+ escSet.regSet.set(result.getReg());
+ return escSet;
+ }
+
+ // Set not found, must be either null or unknown
+ if (prevSource.getType() == Type.KNOWN_NULL) {
+ escSet = new EscapeSet(result.getReg(), regCount,
+ EscapeState.NONE);
+ } else {
+ escSet = new EscapeSet(result.getReg(), regCount,
+ EscapeState.GLOBAL);
+ }
+ break;
+ default:
+ return null;
+ }
+
+ // Add the newly created escSet to the lattice and return it
+ latticeValues.add(escSet);
+ return escSet;
+ }
+
+ /**
+ * Iterate through all the uses of a new object.
+ *
+ * @param result {@code non-null;} register where new object is stored
+ * @param escSet {@code non-null;} EscapeSet for the new object
+ */
+ private void processRegister(RegisterSpec result, EscapeSet escSet) {
+ ArrayList<RegisterSpec> regWorklist = new ArrayList<RegisterSpec>();
+ regWorklist.add(result);
+
+ // Go through the worklist
+ while (!regWorklist.isEmpty()) {
+ int listSize = regWorklist.size() - 1;
+ RegisterSpec def = regWorklist.remove(listSize);
+ List<SsaInsn> useList = ssaMeth.getUseListForRegister(def.getReg());
+
+ // Handle all the uses of this register
+ for (SsaInsn use : useList) {
+ Rop useOpcode = use.getOpcode();
+
+ if (useOpcode == null) {
+ // Handle phis
+ processPhiUse(use, escSet, regWorklist);
+ } else {
+ // Handle other opcodes
+ processUse(def, use, escSet, regWorklist);
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles phi uses of new objects. Will merge together the sources of a phi
+ * into a single EscapeSet. Adds the result of the phi to the worklist so
+ * its uses can be followed.
+ *
+ * @param use {@code non-null;} phi use being processed
+ * @param escSet {@code non-null;} EscapeSet for the object
+ * @param regWorklist {@code non-null;} worklist of instructions left to
+ * process for this object
+ */
+ private void processPhiUse(SsaInsn use, EscapeSet escSet,
+ ArrayList<RegisterSpec> regWorklist) {
+ int setIndex = findSetIndex(use.getResult());
+ if (setIndex != latticeValues.size()) {
+ // Check if result is in a set already
+ EscapeSet mergeSet = latticeValues.get(setIndex);
+ if (mergeSet != escSet) {
+ // If it is, merge the sets and states, then delete the copy
+ escSet.replaceableArray = false;
+ escSet.regSet.or(mergeSet.regSet);
+ if (escSet.escape.compareTo(mergeSet.escape) < 0) {
+ escSet.escape = mergeSet.escape;
+ }
+ replaceNode(escSet, mergeSet);
+ latticeValues.remove(setIndex);
+ }
+ } else {
+ // If no set is found, add it to this escSet and the worklist
+ escSet.regSet.set(use.getResult().getReg());
+ regWorklist.add(use.getResult());
+ }
+ }
+
+ /**
+ * Handles non-phi uses of new objects. Checks to see how instruction is
+ * used and updates the escape state accordingly.
+ *
+ * @param def {@code non-null;} register holding definition of new object
+ * @param use {@code non-null;} use of object being processed
+ * @param escSet {@code non-null;} EscapeSet for the object
+ * @param regWorklist {@code non-null;} worklist of instructions left to
+ * process for this object
+ */
+ private void processUse(RegisterSpec def, SsaInsn use, EscapeSet escSet,
+ ArrayList<RegisterSpec> regWorklist) {
+ int useOpcode = use.getOpcode().getOpcode();
+ switch (useOpcode) {
+ case RegOps.MOVE:
+ // Follow uses of the move by adding it to the worklist
+ escSet.regSet.set(use.getResult().getReg());
+ regWorklist.add(use.getResult());
+ break;
+ case RegOps.IF_EQ:
+ case RegOps.IF_NE:
+ case RegOps.CHECK_CAST:
+ // Compared objects can't be replaced, so promote if necessary
+ if (escSet.escape.compareTo(EscapeState.METHOD) < 0) {
+ escSet.escape = EscapeState.METHOD;
+ }
+ break;
+ case RegOps.APUT:
+ // For array puts, check for a constant array index
+ RegisterSpec putIndex = use.getSources().get(2);
+ if (!putIndex.getTypeBearer().isConstant()) {
+ // If not constant, array can't be replaced
+ escSet.replaceableArray = false;
+ }
+ // Intentional fallthrough
+ case RegOps.PUT_FIELD:
+ // Skip non-object puts
+ RegisterSpec putValue = use.getSources().get(0);
+ if (putValue.getTypeBearer().getBasicType() != Type.BT_OBJECT) {
+ break;
+ }
+ escSet.replaceableArray = false;
+
+ // Raise 1st object's escape state to 2nd if 2nd is higher
+ RegisterSpecList sources = use.getSources();
+ if (sources.get(0).getReg() == def.getReg()) {
+ int setIndex = findSetIndex(sources.get(1));
+ if (setIndex != latticeValues.size()) {
+ EscapeSet parentSet = latticeValues.get(setIndex);
+ addEdge(parentSet, escSet);
+ if (escSet.escape.compareTo(parentSet.escape) < 0) {
+ escSet.escape = parentSet.escape;
+ }
+ }
+ } else {
+ int setIndex = findSetIndex(sources.get(0));
+ if (setIndex != latticeValues.size()) {
+ EscapeSet childSet = latticeValues.get(setIndex);
+ addEdge(escSet, childSet);
+ if (childSet.escape.compareTo(escSet.escape) < 0) {
+ childSet.escape = escSet.escape;
+ }
+ }
+ }
+ break;
+ case RegOps.AGET:
+ // For array gets, check for a constant array index
+ RegisterSpec getIndex = use.getSources().get(1);
+ if (!getIndex.getTypeBearer().isConstant()) {
+ // If not constant, array can't be replaced
+ escSet.replaceableArray = false;
+ }
+ break;
+ case RegOps.PUT_STATIC:
+ // Static puts cause an object to escape globally
+ escSet.escape = EscapeState.GLOBAL;
+ break;
+ case RegOps.INVOKE_STATIC:
+ case RegOps.INVOKE_VIRTUAL:
+ case RegOps.INVOKE_SUPER:
+ case RegOps.INVOKE_DIRECT:
+ case RegOps.INVOKE_INTERFACE:
+ case RegOps.RETURN:
+ case RegOps.THROW:
+ // These operations cause an object to escape interprocedurally
+ escSet.escape = EscapeState.INTER;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Performs scalar replacement on all eligible arrays.
+ */
+ private void scalarReplacement() {
+ // Iterate through lattice, looking for non-escaping replaceable arrays
+ for (EscapeSet escSet : latticeValues) {
+ if (!escSet.replaceableArray || escSet.escape != EscapeState.NONE) {
+ continue;
+ }
+
+ // Get the instructions for the definition and move of the array
+ int e = escSet.regSet.nextSetBit(0);
+ SsaInsn def = ssaMeth.getDefinitionForRegister(e);
+ SsaInsn prev = getInsnForMove(def);
+
+ // Create a map for the new registers that will be created
+ TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
+ int length = ((CstLiteralBits) lengthReg).getIntBits();
+ ArrayList<RegisterSpec> newRegs =
+ new ArrayList<RegisterSpec>(length);
+ HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+ // Replace the definition of the array with registers
+ replaceDef(def, prev, length, newRegs);
+
+ // Mark definition instructions for deletion
+ deletedInsns.add(prev);
+ deletedInsns.add(def);
+
+ // Go through all uses of the array
+ List<SsaInsn> useList = ssaMeth.getUseListForRegister(e);
+ for (SsaInsn use : useList) {
+ // Replace the use with scalars and then mark it for deletion
+ replaceUse(use, prev, newRegs, deletedInsns);
+ deletedInsns.add(use);
+ }
+
+ // Delete all marked instructions
+ ssaMeth.deleteInsns(deletedInsns);
+ ssaMeth.onInsnsChanged();
+
+ // Convert the method back to SSA form
+ SsaConverter.updateSsaMethod(ssaMeth, regCount);
+
+ // Propagate and remove extra moves added by scalar replacement
+ movePropagate();
+ }
+ }
+
+ /**
+ * Replaces the instructions that define an array with equivalent registers.
+ * For each entry in the array, a register is created, initialized to zero.
+ * A mapping between this register and the corresponding array index is
+ * added.
+ *
+ * @param def {@code non-null;} move result instruction for array
+ * @param prev {@code non-null;} instruction for instantiating new array
+ * @param length size of the new array
+ * @param newRegs {@code non-null;} mapping of array indices to new
+ * registers to be populated
+ */
+ private void replaceDef(SsaInsn def, SsaInsn prev, int length,
+ ArrayList<RegisterSpec> newRegs) {
+ Type resultType = def.getResult().getType();
+
+ // Create new zeroed out registers for each element in the array
+ for (int i = 0; i < length; i++) {
+ Constant newZero = Zeroes.zeroFor(resultType.getComponentType());
+ TypedConstant typedZero = (TypedConstant) newZero;
+ RegisterSpec newReg =
+ RegisterSpec.make(ssaMeth.makeNewSsaReg(), typedZero);
+ newRegs.add(newReg);
+ insertPlainInsnBefore(def, RegisterSpecList.EMPTY, newReg,
+ RegOps.CONST, newZero);
+ }
+ }
+
+ /**
+ * Replaces the use for a scalar replaceable array. Gets and puts become
+ * move instructions, and array lengths and fills are handled. Can also
+ * identify ArrayIndexOutOfBounds exceptions and throw them if detected.
+ *
+ * @param use {@code non-null;} move result instruction for array
+ * @param prev {@code non-null;} instruction for instantiating new array
+ * @param newRegs {@code non-null;} mapping of array indices to new
+ * registers
+ * @param deletedInsns {@code non-null;} set of instructions marked for
+ * deletion
+ */
+ private void replaceUse(SsaInsn use, SsaInsn prev,
+ ArrayList<RegisterSpec> newRegs,
+ HashSet<SsaInsn> deletedInsns) {
+ int index;
+ int length = newRegs.size();
+ SsaInsn next;
+ RegisterSpecList sources;
+ RegisterSpec source, result;
+ CstLiteralBits indexReg;
+
+ switch (use.getOpcode().getOpcode()) {
+ case RegOps.AGET:
+ // Replace array gets with moves
+ next = getMoveForInsn(use);
+ sources = use.getSources();
+ indexReg = ((CstLiteralBits) sources.get(1).getTypeBearer());
+ index = indexReg.getIntBits();
+ if (index < length) {
+ source = newRegs.get(index);
+ result = source.withReg(next.getResult().getReg());
+ insertPlainInsnBefore(next, RegisterSpecList.make(source),
+ result, RegOps.MOVE, null);
+ } else {
+ // Throw an exception if the index is out of bounds
+ insertExceptionThrow(next, sources.get(1), deletedInsns);
+ deletedInsns.add(next.getBlock().getInsns().get(2));
+ }
+ deletedInsns.add(next);
+ break;
+ case RegOps.APUT:
+ // Replace array puts with moves
+ sources = use.getSources();
+ indexReg = ((CstLiteralBits) sources.get(2).getTypeBearer());
+ index = indexReg.getIntBits();
+ if (index < length) {
+ source = sources.get(0);
+ result = source.withReg(newRegs.get(index).getReg());
+ insertPlainInsnBefore(use, RegisterSpecList.make(source),
+ result, RegOps.MOVE, null);
+ // Update the newReg entry to mark value as unknown now
+ newRegs.set(index, result.withSimpleType());
+ } else {
+ // Throw an exception if the index is out of bounds
+ insertExceptionThrow(use, sources.get(2), deletedInsns);
+ }
+ break;
+ case RegOps.ARRAY_LENGTH:
+ // Replace array lengths with const instructions
+ TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
+ //CstInteger lengthReg = CstInteger.make(length);
+ next = getMoveForInsn(use);
+ insertPlainInsnBefore(next, RegisterSpecList.EMPTY,
+ next.getResult(), RegOps.CONST,
+ (Constant) lengthReg);
+ deletedInsns.add(next);
+ break;
+ case RegOps.MARK_LOCAL:
+ // Remove mark local instructions
+ break;
+ case RegOps.FILL_ARRAY_DATA:
+ // Create const instructions for each fill value
+ Insn ropUse = use.getOriginalRopInsn();
+ FillArrayDataInsn fill = (FillArrayDataInsn) ropUse;
+ ArrayList<Constant> constList = fill.getInitValues();
+ for (int i = 0; i < length; i++) {
+ RegisterSpec newFill =
+ RegisterSpec.make(newRegs.get(i).getReg(),
+ (TypeBearer) constList.get(i));
+ insertPlainInsnBefore(use, RegisterSpecList.EMPTY, newFill,
+ RegOps.CONST, constList.get(i));
+ // Update the newRegs to hold the new const value
+ newRegs.set(i, newFill);
+ }
+ break;
+ default:
+ }
+ }
+
+ /**
+ * Identifies extra moves added by scalar replacement and propagates the
+ * source of the move to any users of the result.
+ */
+ private void movePropagate() {
+ for (int i = 0; i < ssaMeth.getRegCount(); i++) {
+ SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
+
+ // Look for move instructions only
+ if (insn == null || insn.getOpcode() == null ||
+ insn.getOpcode().getOpcode() != RegOps.MOVE) {
+ continue;
+ }
+
+ final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
+ final RegisterSpec source = insn.getSources().get(0);
+ final RegisterSpec result = insn.getResult();
+
+ // Ignore moves that weren't added due to scalar replacement
+ if (source.getReg() < regCount && result.getReg() < regCount) {
+ continue;
+ }
+
+ // Create a mapping from source to result
+ RegisterMapper mapper = new RegisterMapper() {
+ @Override
+ public int getNewRegisterCount() {
+ return ssaMeth.getRegCount();
+ }
+
+ @Override
+ public RegisterSpec map(RegisterSpec registerSpec) {
+ if (registerSpec.getReg() == result.getReg()) {
+ return source;
+ }
+
+ return registerSpec;
+ }
+ };
+
+ // Modify all uses of the move to use the source of the move instead
+ for (SsaInsn use : useList[result.getReg()]) {
+ use.mapSourceRegisters(mapper);
+ }
+ }
+ }
+
+ /**
+ * Runs escape analysis and scalar replacement of arrays.
+ */
+ private void run() {
+ ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
+ public void visitBlock (SsaBasicBlock block,
+ SsaBasicBlock unused) {
+ block.forEachInsn(new SsaInsn.Visitor() {
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ // do nothing
+ }
+
+ public void visitPhiInsn(PhiInsn insn) {
+ // do nothing
+ }
+
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ processInsn(insn);
+ }
+ });
+ }
+ });
+
+ // Go through lattice and promote fieldSets as necessary
+ for (EscapeSet e : latticeValues) {
+ if (e.escape != EscapeState.NONE) {
+ for (EscapeSet field : e.childSets) {
+ if (e.escape.compareTo(field.escape) > 0) {
+ field.escape = e.escape;
+ }
+ }
+ }
+ }
+
+ // Perform scalar replacement for arrays
+ scalarReplacement();
+ }
+
+ /**
+ * Replaces instructions that trigger an ArrayIndexOutofBounds exception
+ * with an actual throw of the exception.
+ *
+ * @param insn {@code non-null;} instruction causing the exception
+ * @param index {@code non-null;} index value that is out of bounds
+ * @param deletedInsns {@code non-null;} set of instructions marked for
+ * deletion
+ */
+ private void insertExceptionThrow(SsaInsn insn, RegisterSpec index,
+ HashSet<SsaInsn> deletedInsns) {
+ // Create a new ArrayIndexOutOfBoundsException
+ CstType exception =
+ new CstType(Exceptions.TYPE_ArrayIndexOutOfBoundsException);
+ insertThrowingInsnBefore(insn, RegisterSpecList.EMPTY, null,
+ RegOps.NEW_INSTANCE, exception);
+
+ // Add a successor block with a move result pseudo for the exception
+ SsaBasicBlock currBlock = insn.getBlock();
+ SsaBasicBlock newBlock =
+ currBlock.insertNewSuccessor(currBlock.getPrimarySuccessor());
+ SsaInsn newInsn = newBlock.getInsns().get(0);
+ RegisterSpec newReg =
+ RegisterSpec.make(ssaMeth.makeNewSsaReg(), exception);
+ insertPlainInsnBefore(newInsn, RegisterSpecList.EMPTY, newReg,
+ RegOps.MOVE_RESULT_PSEUDO, null);
+
+ // Add another successor block to initialize the exception
+ SsaBasicBlock newBlock2 =
+ newBlock.insertNewSuccessor(newBlock.getPrimarySuccessor());
+ SsaInsn newInsn2 = newBlock2.getInsns().get(0);
+ CstNat newNat = new CstNat(new CstUtf8("<init>"), new CstUtf8("(I)V"));
+ CstMethodRef newRef = new CstMethodRef(exception, newNat);
+ insertThrowingInsnBefore(newInsn2, RegisterSpecList.make(newReg, index),
+ null, RegOps.INVOKE_DIRECT, newRef);
+ deletedInsns.add(newInsn2);
+
+ // Add another successor block to throw the new exception
+ SsaBasicBlock newBlock3 =
+ newBlock2.insertNewSuccessor(newBlock2.getPrimarySuccessor());
+ SsaInsn newInsn3 = newBlock3.getInsns().get(0);
+ insertThrowingInsnBefore(newInsn3, RegisterSpecList.make(newReg), null,
+ RegOps.THROW, null);
+ newBlock3.replaceSuccessor(newBlock3.getPrimarySuccessorIndex(),
+ ssaMeth.getExitBlock().getIndex());
+ deletedInsns.add(newInsn3);
+ }
+
+ /**
+ * Inserts a new PlainInsn before the given instruction.
+ * TODO: move this somewhere more appropriate
+ *
+ * @param insn {@code non-null;} instruction to insert before
+ * @param newSources {@code non-null;} sources of new instruction
+ * @param newResult {@code non-null;} result of new instruction
+ * @param newOpcode opcode of new instruction
+ * @param cst {@code null-ok;} constant for new instruction, if any
+ */
+ private void insertPlainInsnBefore(SsaInsn insn,
+ RegisterSpecList newSources, RegisterSpec newResult, int newOpcode,
+ Constant cst) {
+
+ Insn originalRopInsn = insn.getOriginalRopInsn();
+ Rop newRop;
+ if (newOpcode == RegOps.MOVE_RESULT_PSEUDO) {
+ newRop = Rops.opMoveResultPseudo(newResult.getType());
+ } else {
+ newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
+ }
+
+ Insn newRopInsn;
+ if (cst == null) {
+ newRopInsn = new PlainInsn(newRop,
+ originalRopInsn.getPosition(), newResult, newSources);
+ } else {
+ newRopInsn = new PlainCstInsn(newRop,
+ originalRopInsn.getPosition(), newResult, newSources, cst);
+ }
+
+ NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+ List<SsaInsn> insns = insn.getBlock().getInsns();
+
+ insns.add(insns.lastIndexOf(insn), newInsn);
+ ssaMeth.onInsnAdded(newInsn);
+ }
+
+ /**
+ * Inserts a new ThrowingInsn before the given instruction.
+ * TODO: move this somewhere more appropriate
+ *
+ * @param insn {@code non-null;} instruction to insert before
+ * @param newSources {@code non-null;} sources of new instruction
+ * @param newResult {@code non-null;} result of new instruction
+ * @param newOpcode opcode of new instruction
+ * @param cst {@code null-ok;} constant for new instruction, if any
+ */
+ private void insertThrowingInsnBefore(SsaInsn insn,
+ RegisterSpecList newSources, RegisterSpec newResult, int newOpcode,
+ Constant cst) {
+
+ Insn origRopInsn = insn.getOriginalRopInsn();
+ Rop newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
+ Insn newRopInsn;
+ if (cst == null) {
+ newRopInsn = new ThrowingInsn(newRop,
+ origRopInsn.getPosition(), newSources, StdTypeList.EMPTY);
+ } else {
+ newRopInsn = new ThrowingCstInsn(newRop,
+ origRopInsn.getPosition(), newSources, StdTypeList.EMPTY, cst);
+ }
+
+ NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+ List<SsaInsn> insns = insn.getBlock().getInsns();
+
+ insns.add(insns.lastIndexOf(insn), newInsn);
+ ssaMeth.onInsnAdded(newInsn);
+ }
+}
diff --git a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
index 392579d..851249b 100644
--- a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
+++ b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
@@ -49,7 +49,7 @@
/**
* Constructs an instance
- *
+ *
* @param countOldRegisters number of registers in old namespace
*/
public InterferenceRegisterMapper(InterferenceGraph oldRegInterference,
@@ -113,7 +113,7 @@
/**
* Adds a register's interference set to the interference list,
* growing it if necessary.
- *
+ *
* @param newReg register in new namespace
* @param oldReg register in old namespace
*/
@@ -158,7 +158,7 @@
return true;
}
}
-
+
return false;
}
}
diff --git a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
index a70b5bb..01d818d 100644
--- a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
+++ b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
@@ -48,7 +48,7 @@
LiteralOpUpgrader dc;
dc = new LiteralOpUpgrader(ssaMethod);
-
+
dc.run();
}
diff --git a/dx/src/com/android/dx/ssa/MoveParamCombiner.java b/dx/src/com/android/dx/ssa/MoveParamCombiner.java
index 352e3e6..41660d2 100644
--- a/dx/src/com/android/dx/ssa/MoveParamCombiner.java
+++ b/dx/src/com/android/dx/ssa/MoveParamCombiner.java
@@ -37,7 +37,7 @@
/**
* Processes a method with this optimization step.
- *
+ *
* @param ssaMethod method to process
*/
public static void process(SsaMethod ssaMethod) {
@@ -45,7 +45,7 @@
}
private MoveParamCombiner(SsaMethod ssaMeth) {
- this.ssaMeth = ssaMeth;
+ this.ssaMeth = ssaMeth;
}
/**
@@ -126,7 +126,7 @@
// Use list is modified by mapSourceRegisters
for (int i = uses.size() - 1; i >= 0; i--) {
- SsaInsn use = uses.get(i);
+ SsaInsn use = uses.get(i);
use.mapSourceRegisters(mapper);
}
diff --git a/dx/src/com/android/dx/ssa/NormalSsaInsn.java b/dx/src/com/android/dx/ssa/NormalSsaInsn.java
index d3392ca..93d3647 100644
--- a/dx/src/com/android/dx/ssa/NormalSsaInsn.java
+++ b/dx/src/com/android/dx/ssa/NormalSsaInsn.java
@@ -63,13 +63,13 @@
for (int i = 0; i < sz; i++) {
newSources.set(i, i == index ? newSpec : origSources.get(i));
}
-
+
newSources.setImmutable();
RegisterSpec origSpec = origSources.get(index);
if (origSpec.getReg() != newSpec.getReg()) {
/*
- * If the register remains unchanged, we're only changing
+ * If the register remains unchanged, we're only changing
* the type or local var name so don't update use list
*/
getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
@@ -102,7 +102,7 @@
/**
* Like rop.Insn.getSources().
- *
+ *
* @return {@code null-ok;} sources list
*/
public RegisterSpecList getSources() {
@@ -137,7 +137,7 @@
/** {@inheritDoc} */
public RegisterSpec getLocalAssignment() {
RegisterSpec assignment;
-
+
if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
assignment = insn.getSources().get(0);
} else {
diff --git a/dx/src/com/android/dx/ssa/Optimizer.java b/dx/src/com/android/dx/ssa/Optimizer.java
index c5f6dc9..06ed138 100644
--- a/dx/src/com/android/dx/ssa/Optimizer.java
+++ b/dx/src/com/android/dx/ssa/Optimizer.java
@@ -18,12 +18,10 @@
import com.android.dx.rop.code.RopMethod;
import com.android.dx.rop.code.TranslationAdvice;
-import com.android.dx.ssa.back.SsaToRop;
import com.android.dx.ssa.back.LivenessAnalyzer;
+import com.android.dx.ssa.back.SsaToRop;
import java.util.EnumSet;
-import java.util.BitSet;
-import java.util.ArrayList;
/**
* Runs a method through the SSA form conversion, any optimization algorithms,
@@ -36,7 +34,8 @@
/** optional optimizer steps */
public enum OptionalStep {
- MOVE_PARAM_COMBINER,SCCP,LITERAL_UPGRADE,CONST_COLLECTOR
+ MOVE_PARAM_COMBINER, SCCP, LITERAL_UPGRADE, CONST_COLLECTOR,
+ ESCAPE_ANALYSIS
}
/**
@@ -71,14 +70,14 @@
boolean isStatic, boolean inPreserveLocals,
TranslationAdvice inAdvice) {
- return optimize(rmeth, paramWidth, isStatic, inPreserveLocals, inAdvice,
+ return optimize(rmeth, paramWidth, isStatic, inPreserveLocals, inAdvice,
EnumSet.allOf(OptionalStep.class));
}
/**
* Runs optimization algorthims over this method, and returns a new
* instance of RopMethod with the changes.
- *
+ *
* @param rmeth method to process
* @param paramWidth the total width, in register-units, of this method's
* parameters
@@ -167,6 +166,16 @@
needsDeadCodeRemover = false;
}
+ /*
+ * ESCAPE_ANALYSIS impacts debuggability, so left off by default
+ */
+ steps.remove(OptionalStep.ESCAPE_ANALYSIS);
+ if (steps.contains(OptionalStep.ESCAPE_ANALYSIS)) {
+ EscapeAnalysis.process(ssaMeth);
+ DeadCodeRemover.process(ssaMeth);
+ needsDeadCodeRemover = false;
+ }
+
if (steps.contains(OptionalStep.CONST_COLLECTOR)) {
ConstCollector.process(ssaMeth);
DeadCodeRemover.process(ssaMeth);
@@ -241,6 +250,6 @@
LivenessAnalyzer.constructInterferenceGraph(ssaMeth);
- return ssaMeth;
+ return ssaMeth;
}
}
diff --git a/dx/src/com/android/dx/ssa/PhiInsn.java b/dx/src/com/android/dx/ssa/PhiInsn.java
index 64e85ac..3ea876f 100644
--- a/dx/src/com/android/dx/ssa/PhiInsn.java
+++ b/dx/src/com/android/dx/ssa/PhiInsn.java
@@ -48,7 +48,7 @@
/**
* Constructs a new phi insn with no operands.
- *
+ *
* @param resultReg the result reg for this phi insn
* @param block block containing this insn.
*/
@@ -59,7 +59,7 @@
/**
* Makes a phi insn with a void result type.
- *
+ *
* @param resultReg the result register for this phi insn.
* @param block block containing this insn.
*/
@@ -88,7 +88,7 @@
*/
public void updateSourcesToDefinitions(SsaMethod ssaMeth) {
for (Operand o : operands) {
- RegisterSpec def
+ RegisterSpec def
= ssaMeth.getDefinitionForRegister(
o.regSpec.getReg()).getResult();
@@ -111,7 +111,7 @@
/**
* Gets the original rop-form result reg. This is useful during renaming.
- *
+ *
* @return the original rop-form result reg
*/
public int getRopResultReg() {
@@ -120,7 +120,7 @@
/**
* Adds an operand to this phi instruction.
- *
+ *
* @param registerSpec register spec, including type and reg of operand
* @param predBlock predecessor block to be associated with this operand
*/
@@ -128,7 +128,7 @@
SsaBasicBlock predBlock) {
operands.add(new Operand(registerSpec, predBlock.getIndex(),
predBlock.getRopLabel()));
-
+
// Un-cache sources, in case someone has already called getSources().
sources = null;
}
@@ -136,7 +136,7 @@
/**
* Gets the index of the pred block associated with the RegisterSpec
* at the particular getSources() index.
- *
+ *
* @param sourcesIndex index of source in getSources()
* @return block index
*/
@@ -177,7 +177,7 @@
/**
* Gets sources. Constructed lazily from phi operand data structures and
* then cached.
- *
+ *
* @return {@code non-null;} sources list
*/
public RegisterSpecList getSources() {
@@ -255,7 +255,7 @@
/**
* Always throws an exeption, since a phi insn may not be
* converted back to rop form.
- *
+ *
* @return always throws exception
*/
@Override
@@ -287,7 +287,7 @@
/** {@inheritDoc} */
@Override
public boolean isPhiOrMove() {
- return true;
+ return true;
}
/** {@inheritDoc} */
@@ -310,7 +310,7 @@
/**
* Returns human-readable string for listing dumps. This method
* allows sub-classes to specify extra text.
- *
+ *
* @param extra {@code null-ok;} the argument to print after the opcode
* @return human-readable string for listing dumps
*/
@@ -318,7 +318,7 @@
StringBuffer sb = new StringBuffer(80);
sb.append(SourcePosition.NO_INFO);
- sb.append(": phi");
+ sb.append(": phi");
if (extra != null) {
sb.append("(");
@@ -327,7 +327,7 @@
}
RegisterSpec result = getResult();
-
+
if (result == null) {
sb.append(" .");
} else {
diff --git a/dx/src/com/android/dx/ssa/PhiTypeResolver.java b/dx/src/com/android/dx/ssa/PhiTypeResolver.java
index f4c26d7..4b8b4e3 100644
--- a/dx/src/com/android/dx/ssa/PhiTypeResolver.java
+++ b/dx/src/com/android/dx/ssa/PhiTypeResolver.java
@@ -121,7 +121,7 @@
* Resolves the result of a phi insn based on its operands. The "void"
* type, which is a nonsensical type for a register, is used for
* registers defined by as-of-yet-unresolved phi operations.
- *
+ *
* @return true if the result type changed, false if no change
*/
boolean resolveResultType(PhiInsn insn) {
@@ -185,7 +185,7 @@
}
LocalItem newLocal = sameLocals ? firstLocal : null;
-
+
RegisterSpec result = insn.getResult();
if ((result.getTypeBearer() == newResultType)
diff --git a/dx/src/com/android/dx/ssa/RegisterMapper.java b/dx/src/com/android/dx/ssa/RegisterMapper.java
index 1f45b42..bef941f 100644
--- a/dx/src/com/android/dx/ssa/RegisterMapper.java
+++ b/dx/src/com/android/dx/ssa/RegisterMapper.java
@@ -21,7 +21,7 @@
import com.android.dx.util.ToHuman;
/**
- * Represents a mapping between two register numbering schemes.
+ * Represents a mapping between two register numbering schemes.
* Subclasses of this may be mutable, and as such the mapping provided
* is only valid for the lifetime of the method call in which
* instances of this class are passed.
diff --git a/dx/src/com/android/dx/ssa/SCCP.java b/dx/src/com/android/dx/ssa/SCCP.java
index 73e9b49..42abbb2 100644
--- a/dx/src/com/android/dx/ssa/SCCP.java
+++ b/dx/src/com/android/dx/ssa/SCCP.java
@@ -136,7 +136,7 @@
return false;
}
}
-
+
/**
* Simulates a PHI node and set the lattice for the result
* to the approriate value.
@@ -438,7 +438,7 @@
* steps.
*/
private void replaceConstants() {
- for (int reg = 0; reg < regCount; reg++) {
+ for (int reg = 0; reg < regCount; reg++) {
if (latticeValues[reg] != CONSTANT) {
continue;
}
diff --git a/dx/src/com/android/dx/ssa/SsaBasicBlock.java b/dx/src/com/android/dx/ssa/SsaBasicBlock.java
index ab0e122..499f59f 100644
--- a/dx/src/com/android/dx/ssa/SsaBasicBlock.java
+++ b/dx/src/com/android/dx/ssa/SsaBasicBlock.java
@@ -18,20 +18,18 @@
import com.android.dx.rop.code.BasicBlock;
import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
import com.android.dx.rop.code.InsnList;
import com.android.dx.rop.code.PlainInsn;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
import com.android.dx.rop.code.RopMethod;
import com.android.dx.rop.code.Rops;
import com.android.dx.rop.code.SourcePosition;
-import com.android.dx.rop.code.Insn;
-import com.android.dx.rop.code.Rop;
-import com.android.dx.util.IntList;
import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
import com.android.dx.util.IntSet;
-import com.android.dx.util.BitIntSet;
-import com.android.dx.util.ListIntSet;
import java.util.ArrayList;
import java.util.BitSet;
@@ -96,6 +94,12 @@
private int movesFromPhisAtBeginning = 0;
/**
+ * contains last computed value of reachability of this block, or -1
+ * if reachability hasn't been calculated yet
+ */
+ private int reachable = -1;
+
+ /**
* {@code null-ok;} indexed by reg: the regs that are live-in at
* this block
*/
@@ -514,6 +518,26 @@
parent.getBlocks().get(oldIndex).predecessors.clear(index);
}
+ /**
+ * Removes a successor from this block's successor list.
+ *
+ * @param oldIndex index of successor block to remove
+ */
+ public void removeSuccessor(int oldIndex) {
+ int removeIndex = 0;
+
+ for (int i = successorList.size() - 1; i >= 0; i--) {
+ if (successorList.get(i) == oldIndex) {
+ removeIndex = i;
+ } else {
+ primarySuccessor = successorList.get(i);
+ }
+ }
+
+ successorList.removeIndex(removeIndex);
+ successors.clear(oldIndex);
+ parent.getBlocks().get(oldIndex).predecessors.clear(index);
+ }
/**
* Attaches block to an exit block if necessary. If this block
@@ -820,16 +844,25 @@
}
/**
- * Returns true if this block is reachable (that is, it hasn't been
- * unlinked from the control flow of this method). This currently tests
- * that it's either the start block or it has predecessors, which suffices
- * for all current control flow transformations.
+ * Returns true if this block was last calculated to be reachable.
+ * Recalculates reachability if value has never been computed.
*
* @return {@code true} if reachable
*/
public boolean isReachable() {
- return index == parent.getEntryBlockIndex()
- || predecessors.cardinality() > 0;
+ if (reachable == -1) {
+ parent.computeReachability();
+ }
+ return (reachable == 1);
+ }
+
+ /**
+ * Sets reachability of block to specified value
+ *
+ * @param reach new value of reachability for block
+ */
+ public void setReachable(int reach) {
+ reachable = reach;
}
/**
@@ -959,6 +992,7 @@
}
/** {@inheritDoc} */
+ @Override
public String toString() {
return "{" + index + ":" + Hex.u2(ropLabel) + '}';
}
diff --git a/dx/src/com/android/dx/ssa/SsaConverter.java b/dx/src/com/android/dx/ssa/SsaConverter.java
index d5be287..5cd8b6f 100644
--- a/dx/src/com/android/dx/ssa/SsaConverter.java
+++ b/dx/src/com/android/dx/ssa/SsaConverter.java
@@ -49,7 +49,7 @@
LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
- placePhiFunctions(result, localInfo);
+ placePhiFunctions(result, localInfo, 0);
new SsaRenamer(result).run();
/*
@@ -62,6 +62,19 @@
}
/**
+ * Updates an SSA representation, placing phi functions and renaming all
+ * registers above a certain threshold number.
+ *
+ * @param ssaMeth input
+ * @param threshold registers below this number are unchanged
+ */
+ public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
+ placePhiFunctions(ssaMeth, localInfo, threshold);
+ new SsaRenamer(ssaMeth, threshold).run();
+ }
+
+ /**
* Returns an SSA represention with only the edge-splitter run.
*
* @param rmeth method to process
@@ -100,7 +113,7 @@
LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
- placePhiFunctions(result, localInfo);
+ placePhiFunctions(result, localInfo, 0);
return result;
}
@@ -269,16 +282,17 @@
* Modifications are made in-place.
* @param localInfo {@code non-null;} local variable info, used
* when placing phis
+ * @param threshold registers below this number are ignored
*/
private static void placePhiFunctions (SsaMethod ssaMeth,
- LocalVariableInfo localInfo) {
+ LocalVariableInfo localInfo, int threshold) {
ArrayList<SsaBasicBlock> ssaBlocks;
int regCount;
int blockCount;
ssaBlocks = ssaMeth.getBlocks();
blockCount = ssaBlocks.size();
- regCount = ssaMeth.getRegCount();
+ regCount = ssaMeth.getRegCount() - threshold;
DomFront df = new DomFront(ssaMeth);
DomFront.DomInfo[] domInfos = df.run();
@@ -304,8 +318,8 @@
for (SsaInsn insn : b.getInsns()) {
RegisterSpec rs = insn.getResult();
- if (rs != null) {
- defsites[rs.getReg()].set(bi);
+ if (rs != null && rs.getReg() - threshold >= 0) {
+ defsites[rs.getReg() - threshold].set(bi);
}
}
}
@@ -327,7 +341,7 @@
* For each register, compute all locations for phi placement
* based on dominance-frontier algorithm.
*/
- for (int reg = 0, s = ssaMeth.getRegCount() ; reg < s ; reg++ ) {
+ for (int reg = 0, s = regCount; reg < s; reg++) {
int workBlockIndex;
/* Worklist set starts out with each node where reg is assigned. */
@@ -345,11 +359,12 @@
if (!phisites[reg].get(dfBlockIndex)) {
phisites[reg].set(dfBlockIndex);
+ int tReg = reg + threshold;
RegisterSpec rs
- = localInfo.getStarts(dfBlockIndex).get(reg);
+ = localInfo.getStarts(dfBlockIndex).get(tReg);
if (rs == null) {
- ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(reg);
+ ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
} else {
ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
}
diff --git a/dx/src/com/android/dx/ssa/SsaInsn.java b/dx/src/com/android/dx/ssa/SsaInsn.java
index 815f82d..ca7a1a2 100644
--- a/dx/src/com/android/dx/ssa/SsaInsn.java
+++ b/dx/src/com/android/dx/ssa/SsaInsn.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
- *
+ *
* @param result {@code null-ok;} initial result register. May be changed.
* @param block {@code non-null;} block containing this insn. Can
* never change.
@@ -68,7 +68,7 @@
/**
* Like {@link com.android.dx.rop.code.Insn getResult()}.
- *
+ *
* @return result register
*/
public RegisterSpec getResult() {
@@ -77,7 +77,7 @@
/**
* Set the result register.
- *
+ *
* @param result {@code non-null;} the new result register
*/
protected void setResult(RegisterSpec result) {
@@ -90,7 +90,7 @@
/**
* Like {@link com.android.dx.rop.code.Insn getSources()}.
- *
+ *
* @return {@code non-null;} sources list
*/
abstract public RegisterSpecList getSources();
@@ -106,7 +106,7 @@
/**
* Returns whether or not the specified reg is the result reg.
- *
+ *
* @param reg register to test
* @return true if there is a result and it is stored in the specified
* register
@@ -119,7 +119,7 @@
/**
* Changes the result register if this insn has a result. This is used
* during renaming.
- *
+ *
* @param reg new result register
*/
public void changeResultReg(int reg) {
@@ -154,7 +154,7 @@
result = mapper.map(result);
block.getParent().updateOneDefinition(this, oldResult);
- mapSourceRegisters(mapper);
+ mapSourceRegisters(mapper);
}
/**
@@ -176,7 +176,7 @@
/**
* Returns the original Rop insn for this insn, or null if this is
* a phi insn.
- *
+ *
* TODO: Move this up into NormalSsaInsn.
*
* @return {@code null-ok;} Rop insn if there is one.
@@ -189,8 +189,8 @@
* may be the result register, or for {@code mark-local} insns
* it may be the source.
*
- * @see com.android.dx.rop.code.Insn#getLocalAssignment()
- *
+ * @see com.android.dx.rop.code.Insn#getLocalAssignment()
+ *
* @return {@code null-ok;} a local-associated register spec or null
*/
public RegisterSpec getLocalAssignment() {
@@ -204,7 +204,7 @@
/**
* Indicates whether the specified register is amongst the registers
* used as sources for this instruction.
- *
+ *
* @param reg the register in question
* @return true if the reg is a source
*/
@@ -230,7 +230,7 @@
/**
* Returns true if this insn is considered to have a side effect beyond
* that of assigning to the result reg.
- *
+ *
* @return true if this insn is considered to have a side effect beyond
* that of assigning to the result reg.
*/
@@ -259,7 +259,7 @@
/**
* Accepts a visitor.
- *
+ *
* @param v {@code non-null} the visitor
*/
public abstract void accept(Visitor v);
diff --git a/dx/src/com/android/dx/ssa/SsaMethod.java b/dx/src/com/android/dx/ssa/SsaMethod.java
index 073e515..4c2bd85 100644
--- a/dx/src/com/android/dx/ssa/SsaMethod.java
+++ b/dx/src/com/android/dx/ssa/SsaMethod.java
@@ -17,23 +17,23 @@
package com.android.dx.ssa;
import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
import com.android.dx.rop.code.RopMethod;
import com.android.dx.rop.code.Rops;
import com.android.dx.rop.code.SourcePosition;
-import com.android.dx.rop.code.Insn;
-import com.android.dx.rop.code.RegOps;
-import com.android.dx.rop.code.Rop;
import com.android.dx.util.IntList;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
-import java.util.Stack;
import java.util.Set;
+import java.util.Stack;
/**
* A method in SSA form.
@@ -359,6 +359,32 @@
}
/**
+ * Computes reachability for all blocks in the method. First clears old
+ * values from all blocks, then starts with the entry block and walks down
+ * the control flow graph, marking all blocks it finds as reachable.
+ */
+ public void computeReachability() {
+ for (SsaBasicBlock block : blocks) {
+ block.setReachable(0);
+ }
+
+ ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>();
+ blockList.add(this.getEntryBlock());
+
+ while (!blockList.isEmpty()) {
+ SsaBasicBlock block = blockList.remove(0);
+ if (block.isReachable()) continue;
+
+ block.setReachable(1);
+ BitSet succs = block.getSuccessors();
+ for (int i = succs.nextSetBit(0); i >= 0;
+ i = succs.nextSetBit(i + 1)) {
+ blockList.add(blocks.get(i));
+ }
+ }
+ }
+
+ /**
* Remaps unversioned registers.
*
* @param mapper maps old registers to new.
@@ -821,6 +847,15 @@
Insn gotoInsn = new PlainInsn(Rops.GOTO,
SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
insns.add(SsaInsn.makeFromRop(gotoInsn, block));
+
+ // Remove secondary successors from this block
+ BitSet succs = block.getSuccessors();
+ for (int i = succs.nextSetBit(0); i >= 0;
+ i = succs.nextSetBit(i + 1)) {
+ if (i != block.getPrimarySuccessorIndex()) {
+ block.removeSuccessor(i);
+ }
+ }
}
}
}
diff --git a/dx/src/com/android/dx/ssa/SsaRenamer.java b/dx/src/com/android/dx/ssa/SsaRenamer.java
index 8452c03..58e4142 100644
--- a/dx/src/com/android/dx/ssa/SsaRenamer.java
+++ b/dx/src/com/android/dx/ssa/SsaRenamer.java
@@ -16,14 +16,19 @@
package com.android.dx.ssa;
-import com.android.dx.rop.code.*;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
import com.android.dx.rop.type.Type;
import com.android.dx.util.IntList;
import java.util.ArrayList;
import java.util.BitSet;
-import java.util.HashSet;
import java.util.HashMap;
+import java.util.HashSet;
/**
* Complete transformation to SSA form by renaming all registers accessed.<p>
@@ -67,6 +72,9 @@
/** the number of original rop registers */
private final int ropRegCount;
+ /** work only on registers above this value */
+ private int threshold;
+
/**
* indexed by block index; register version state for each block start.
* This list is updated by each dom parent for its children. The only
@@ -100,6 +108,7 @@
* "version 0" registers.
*/
nextSsaReg = ropRegCount;
+ threshold = 0;
startsForBlocks = new RegisterSpec[ssaMeth.getBlocks().size()][];
ssaRegToLocalItems = new ArrayList<LocalItem>();
@@ -135,6 +144,18 @@
}
/**
+ * Constructs an instance of the renamer with threshold set
+ *
+ * @param ssaMeth {@code non-null;} un-renamed SSA method that will
+ * be renamed.
+ * @param thresh registers below this number are unchanged
+ */
+ public SsaRenamer(SsaMethod ssaMeth, int thresh) {
+ this(ssaMeth);
+ threshold = thresh;
+ }
+
+ /**
* Performs renaming transformation, modifying the method's instructions
* in-place.
*/
@@ -215,6 +236,18 @@
}
/**
+ * Returns true if this SSA register is below the specified threshold.
+ * Used when most code is already in SSA form, and renaming is needed only
+ * for registers above a certain threshold.
+ *
+ * @param ssaReg the SSA register in question
+ * @return {@code true} if its register number is below the threshold
+ */
+ private boolean isBelowThresholdRegister(int ssaReg) {
+ return ssaReg < threshold;
+ }
+
+ /**
* Returns true if this SSA register is a "version 0"
* register. All version 0 registers are assigned the first N register
* numbers, where N is the count of original rop registers.
@@ -504,7 +537,8 @@
ssaSourceReg, ropResult.getType(), newLocal);
if (!Optimizer.getPreserveLocals() || (onlyOneAssociatedLocal
- && equalsHandlesNulls(newLocal, sourceLocal))) {
+ && equalsHandlesNulls(newLocal, sourceLocal)) &&
+ threshold == 0) {
/*
* We don't have to keep this move to preserve local
* information. Either the name is the same, or the result
@@ -512,7 +546,8 @@
*/
addMapping(ropResultReg, ssaReg);
- } else if (onlyOneAssociatedLocal && sourceLocal == null) {
+ } else if (onlyOneAssociatedLocal && sourceLocal == null &&
+ threshold == 0) {
/*
* The register was previously unnamed. This means that a
* local starts after it's first assignment in SSA form
@@ -572,6 +607,9 @@
}
int ropReg = ropResult.getReg();
+ if (isBelowThresholdRegister(ropReg)) {
+ return;
+ }
insn.changeResultReg(nextSsaReg);
addMapping(ropReg, insn.getResult());
@@ -593,6 +631,9 @@
int ropReg;
ropReg = insn.getRopResultReg();
+ if (isBelowThresholdRegister(ropReg)) {
+ return;
+ }
/*
* Never add a version 0 register as a phi
diff --git a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
index cfc7015..515b04f 100644
--- a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
+++ b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
@@ -41,7 +41,7 @@
/**
* Constructs instance. Call {@code process()} to run.
- *
+ *
* @param rm {@code non-null;} instance to process
*/
public IdenticalBlockCombiner(RopMethod rm) {
@@ -120,7 +120,7 @@
/**
* Helper method to compare the contents of two blocks.
- *
+ *
* @param a {@code non-null;} a block to compare
* @param b {@code non-null;} another block to compare
* @return {@code true} iff the two blocks' instructions are the same
diff --git a/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java b/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
index cd3f7d2..a293e6f 100644
--- a/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
+++ b/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
@@ -98,7 +98,7 @@
return interference;
}
-
+
/**
* Makes liveness analyzer instance for specific register.
*
diff --git a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
index f6dc961..0205c11 100644
--- a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
+++ b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
@@ -54,5 +54,5 @@
}
return mapper;
- }
+ }
}
diff --git a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
index e75eee1..1f9f70f 100644
--- a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
+++ b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
@@ -66,7 +66,7 @@
/**
* Runs the algorithm.
- *
+ *
* @return a register mapper to apply to the {@code SsaMethod}
*/
public abstract RegisterMapper allocateRegisters();
@@ -105,7 +105,7 @@
/**
* Returns true if the definition site of this register is a
* move-param (ie, this is a method parameter).
- *
+ *
* @param reg register in question
* @return {@code true} if this is a method parameter
*/
diff --git a/dx/src/com/android/dx/ssa/back/SsaToRop.java b/dx/src/com/android/dx/ssa/back/SsaToRop.java
index 0ecbead..d9d2c45 100644
--- a/dx/src/com/android/dx/ssa/back/SsaToRop.java
+++ b/dx/src/com/android/dx/ssa/back/SsaToRop.java
@@ -65,7 +65,7 @@
/**
* Converts a method in SSA form to ROP form.
- *
+ *
* @param ssaMeth {@code non-null;} method to process
* @param minimizeRegisters {@code true} if the converter should
* attempt to minimize the rop-form register count
@@ -78,7 +78,7 @@
/**
* Constructs an instance.
- *
+ *
* @param ssaMeth {@code non-null;} method to process
* @param minimizeRegisters {@code true} if the converter should
* attempt to minimize the rop-form register count
@@ -92,7 +92,7 @@
/**
* Performs the conversion.
- *
+ *
* @return {@code non-null;} rop-form output
*/
private RopMethod convert() {
@@ -113,7 +113,7 @@
if (DEBUG) {
System.out.println("Printing reg map");
System.out.println(((BasicRegisterMapper)mapper).toHuman());
- }
+ }
ssaMeth.setBackMode();
@@ -135,7 +135,7 @@
}
/**
- * Removes all blocks containing only GOTOs from the control flow.
+ * Removes all blocks containing only GOTOs from the control flow.
* Although much of this work will be done later when converting
* from rop to dex, not all simplification cases can be handled
* there. Furthermore, any no-op block between the exit block and
@@ -171,7 +171,7 @@
*/
private void removePhiFunctions() {
ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
-
+
for (SsaBasicBlock block : blocks) {
// Add moves in all the pred blocks for each phi insn.
block.forEachPhiInsn(new PhiVisitor(blocks));
@@ -251,6 +251,7 @@
// Exit block may be null.
SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
+ ssaMeth.computeReachability();
int ropBlockCount = ssaMeth.getCountReachableBlocks();
// Don't count the exit block, if it exists.
@@ -335,7 +336,7 @@
/**
* Converts an insn list to rop form.
- *
+ *
* @param ssaInsns {@code non-null;} old instructions
* @return {@code non-null;} immutable instruction list
*/
@@ -354,7 +355,7 @@
/**
* <b>Note:</b> This method is not presently used.
- *
+ *
* @return a list of registers ordered by most-frequently-used to
* least-frequently-used. Each register is listed once and only
* once.
@@ -381,5 +382,5 @@
}
return result;
- }
+ }
}
diff --git a/dx/src/com/android/dx/util/AnnotatedOutput.java b/dx/src/com/android/dx/util/AnnotatedOutput.java
index 9b69a36..7a9ea29 100644
--- a/dx/src/com/android/dx/util/AnnotatedOutput.java
+++ b/dx/src/com/android/dx/util/AnnotatedOutput.java
@@ -24,7 +24,7 @@
extends Output {
/**
* Get whether this instance will actually keep annotations.
- *
+ *
* @return {@code true} iff annotations are being kept
*/
public boolean annotates();
@@ -33,7 +33,7 @@
* Get whether this instance is intended to keep verbose annotations.
* Annotators may use the result of calling this method to inform their
* annotation activity.
- *
+ *
* @return {@code true} iff annotations are to be verbose
*/
public boolean isVerbose();
@@ -43,7 +43,7 @@
* open annotation will be closed by this call, and the new
* annotation marks all subsequent output until another annotation
* call.
- *
+ *
* @param msg {@code non-null;} the annotation message
*/
public void annotate(String msg);
@@ -54,7 +54,7 @@
* call. If there is already pending annotation from one or more
* previous calls to this method, the new call "consumes" output
* after all the output covered by the previous calls.
- *
+ *
* @param amt {@code >= 0;} the amount of output for this annotation to
* cover
* @param msg {@code non-null;} the annotation message
@@ -72,7 +72,7 @@
* Implementations of this interface are encouraged to deal with too-wide
* output, but annotaters are encouraged to attempt to avoid exceeding
* the indicated width.
- *
+ *
* @return {@code >= 1;} the maximum width
*/
public int getAnnotationWidth();
diff --git a/dx/src/com/android/dx/util/BitIntSet.java b/dx/src/com/android/dx/util/BitIntSet.java
index db85571..b364f0c 100644
--- a/dx/src/com/android/dx/util/BitIntSet.java
+++ b/dx/src/com/android/dx/util/BitIntSet.java
@@ -64,7 +64,7 @@
/** @inheritDoc */
public boolean has(int value) {
- return (value < Bits.getMax(bits)) && Bits.get(bits, value);
+ return (value < Bits.getMax(bits)) && Bits.get(bits, value);
}
/** @inheritDoc */
@@ -93,7 +93,7 @@
/** @inheritDoc */
public int elements() {
- return Bits.bitCount(bits);
+ return Bits.bitCount(bits);
}
/** @inheritDoc */
diff --git a/dx/src/com/android/dx/util/Bits.java b/dx/src/com/android/dx/util/Bits.java
index 1f45bd3..cbc0a5b 100644
--- a/dx/src/com/android/dx/util/Bits.java
+++ b/dx/src/com/android/dx/util/Bits.java
@@ -29,7 +29,7 @@
/**
* Constructs a bit set to contain bits up to the given index (exclusive).
- *
+ *
* @param max {@code >= 0;} the maximum bit index (exclusive)
* @return {@code non-null;} an appropriately-constructed instance
*/
@@ -40,7 +40,7 @@
/**
* Gets the maximum index (exclusive) for the given bit set.
- *
+ *
* @param bits {@code non-null;} bit set in question
* @return {@code >= 0;} the maximum index (exclusive) that may be set
*/
@@ -50,7 +50,7 @@
/**
* Gets the value of the bit at the given index.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @param idx {@code >= 0, < getMax(set);} which bit
* @return the value of the indicated bit
@@ -63,7 +63,7 @@
/**
* Sets the given bit to the given value.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @param idx {@code >= 0, < getMax(set);} which bit
* @param value the new value for the bit
@@ -81,7 +81,7 @@
/**
* Sets the given bit to {@code true}.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @param idx {@code >= 0, < getMax(set);} which bit
*/
@@ -93,7 +93,7 @@
/**
* Sets the given bit to {@code false}.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @param idx {@code >= 0, < getMax(set);} which bit
*/
@@ -106,7 +106,7 @@
/**
* Returns whether or not the given bit set is empty, that is, whether
* no bit is set to {@code true}.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @return {@code true} iff all bits are {@code false}
*/
@@ -124,7 +124,7 @@
/**
* Gets the number of bits set to {@code true} in the given bit set.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @return {@code >= 0;} the bit count (aka population count) of the set
*/
@@ -142,7 +142,7 @@
/**
* Returns whether any bits are set to {@code true} in the
* specified range.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @param start {@code >= 0;} index of the first bit in the range (inclusive)
* @param end {@code >= 0;} index of the last bit in the range (exclusive)
@@ -157,7 +157,7 @@
/**
* Finds the lowest-order bit set at or after the given index in the
* given bit set.
- *
+ *
* @param bits {@code non-null;} bit set to operate on
* @param idx {@code >= 0;} minimum index to return
* @return {@code >= -1;} lowest-order bit set at or after {@code idx},
@@ -184,7 +184,7 @@
/**
* Finds the lowest-order bit set at or after the given index in the
* given {@code int}.
- *
+ *
* @param value the value in question
* @param idx 0..31 the minimum bit index to return
* @return {@code >= -1;} lowest-order bit set at or after {@code idx},
diff --git a/dx/src/com/android/dx/util/ByteArray.java b/dx/src/com/android/dx/util/ByteArray.java
index 79fa195..21d0457 100644
--- a/dx/src/com/android/dx/util/ByteArray.java
+++ b/dx/src/com/android/dx/util/ByteArray.java
@@ -198,7 +198,7 @@
* Copies the contents of this instance into the given raw
* {@code byte[]} at the given offset. The given array must be
* large enough.
- *
+ *
* @param out {@code non-null;} array to hold the output
* @param offset {@code non-null;} index into {@code out} for the first
* byte of output
@@ -252,7 +252,7 @@
* with the cursor starting at the beginning of this instance's data.
* <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
* if needed.
- *
+ *
* @return {@code non-null;} an appropriately-constructed
* {@code DataInputStream} instance
*/
@@ -265,7 +265,7 @@
* with the cursor starting at the beginning of this instance's data.
* <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
* if needed.
- *
+ *
* @return {@code non-null;} an appropriately-constructed
* {@code InputStream} instancex
*/
@@ -279,12 +279,12 @@
public interface GetCursor {
/**
* Gets the current cursor.
- *
+ *
* @return {@code 0..size();} the cursor
*/
public int getCursor();
}
-
+
/**
* Helper class for {@link #makeInputStream}, which implements the
* stream functionality.
@@ -295,7 +295,7 @@
/** 0..size; the mark */
private int mark;
-
+
public MyInputStream() {
cursor = 0;
mark = 0;
@@ -315,7 +315,7 @@
if ((offset + length) > arr.length) {
length = arr.length - offset;
}
-
+
int maxLength = size - cursor;
if (length > maxLength) {
length = maxLength;
@@ -351,7 +351,7 @@
public static class MyDataInputStream extends DataInputStream {
/** {@code non-null;} the underlying {@link #MyInputStream} */
private final MyInputStream wrapped;
-
+
public MyDataInputStream(MyInputStream wrapped) {
super(wrapped);
diff --git a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
index 5fcf5d8..6d0615e 100644
--- a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
+++ b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
@@ -23,7 +23,7 @@
/**
* Implementation of {@link AnnotatedOutput} which stores the written data
* into a {@code byte[]}.
- *
+ *
* <p><b>Note:</b> As per the {@link Output} interface, multi-byte
* writes all use little-endian order.</p>
*/
@@ -31,7 +31,7 @@
implements AnnotatedOutput {
/** default size for stretchy instances */
private static final int DEFAULT_SIZE = 1000;
-
+
/**
* whether the instance is stretchy, that is, whether its array
* may be resized to increase capacity
@@ -49,7 +49,7 @@
/**
* {@code null-ok;} list of annotations, or {@code null} if this instance
- * isn't keeping them
+ * isn't keeping them
*/
private ArrayList<Annotation> annotations;
@@ -58,7 +58,7 @@
/**
* {@code >= 8 (if used);} the number of bytes of hex output to use
- * in annotations
+ * in annotations
*/
private int hexCols;
@@ -68,7 +68,7 @@
* particular, no reallocation will occur in order to expand the
* capacity of the resulting instance. Also, the constructed
* instance does not keep annotations by default.
- *
+ *
* @param data {@code non-null;} data array to use for output
*/
public ByteArrayAnnotatedOutput(byte[] data) {
@@ -86,7 +86,7 @@
/**
* Internal constructor.
- *
+ *
* @param data {@code non-null;} data array to use for output
* @param stretchy whether the instance is to be stretchy
*/
@@ -107,9 +107,9 @@
/**
* Gets the underlying {@code byte[]} of this instance, which
* may be larger than the number of bytes written
- *
+ *
* @see #toByteArray
- *
+ *
* @return {@code non-null;} the {@code byte[]}
*/
public byte[] getArray() {
@@ -120,9 +120,9 @@
* Constructs and returns a new {@code byte[]} that contains
* the written contents exactly (that is, with no extra unwritten
* bytes at the end).
- *
+ *
* @see #getArray
- *
+ *
* @return {@code non-null;} an appropriately-constructed array
*/
public byte[] toByteArray() {
@@ -258,7 +258,7 @@
return count;
}
-
+
/** {@inheritDoc} */
public void write(ByteArray bytes) {
int blen = bytes.size();
@@ -285,7 +285,7 @@
// twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
throw new IndexOutOfBoundsException("bytes.length " +
- bytes.length + "; " +
+ bytes.length + "; " +
offset + "..!" + end);
}
@@ -418,7 +418,7 @@
* Indicates that this instance should keep annotations. This method may
* be called only once per instance, and only before any data has been
* written to the it.
- *
+ *
* @param annotationWidth {@code >= 40;} the desired maximum annotation width
* @param verbose whether or not to indicate verbose annotations
*/
@@ -473,7 +473,7 @@
/**
* Writes the annotated content of this instance to the given writer.
- *
+ *
* @param out {@code non-null;} where to write to
*/
public void writeAnnotationsTo(Writer out) throws IOException {
@@ -537,7 +537,7 @@
/**
* Reallocates the underlying array if necessary. Calls to this method
* should be guarded by a test of {@link #stretchy}.
- *
+ *
* @param desiredSize {@code >= 0;} the desired minimum total size of the array
*/
private void ensureCapacity(int desiredSize) {
@@ -557,7 +557,7 @@
/**
* {@code >= 0;} end of annotated range (exclusive);
- * {@code Integer.MAX_VALUE} if unclosed
+ * {@code Integer.MAX_VALUE} if unclosed
*/
private int end;
@@ -566,7 +566,7 @@
/**
* Constructs an instance.
- *
+ *
* @param start {@code >= 0;} start of annotated range
* @param end {@code >= start;} end of annotated range (exclusive) or
* {@code Integer.MAX_VALUE} if unclosed
@@ -580,7 +580,7 @@
/**
* Constructs an instance. It is initally unclosed.
- *
+ *
* @param start {@code >= 0;} start of annotated range
* @param text {@code non-null;} annotation text
*/
@@ -591,7 +591,7 @@
/**
* Sets the end as given, but only if the instance is unclosed;
* otherwise, do nothing.
- *
+ *
* @param end {@code >= start;} the end
*/
public void setEndIfUnset(int end) {
@@ -602,7 +602,7 @@
/**
* Sets the end as given.
- *
+ *
* @param end {@code >= start;} the end
*/
public void setEnd(int end) {
@@ -611,7 +611,7 @@
/**
* Gets the start.
- *
+ *
* @return the start
*/
public int getStart() {
@@ -620,7 +620,7 @@
/**
* Gets the end.
- *
+ *
* @return the end
*/
public int getEnd() {
@@ -629,7 +629,7 @@
/**
* Gets the text.
- *
+ *
* @return {@code non-null;} the text
*/
public String getText() {
diff --git a/dx/src/com/android/dx/util/FileUtils.java b/dx/src/com/android/dx/util/FileUtils.java
index 3f51207..098c5ab 100644
--- a/dx/src/com/android/dx/util/FileUtils.java
+++ b/dx/src/com/android/dx/util/FileUtils.java
@@ -34,7 +34,7 @@
/**
* Reads the named file, translating {@link IOException} to a
* {@link RuntimeException} of some sort.
- *
+ *
* @param fileName {@code non-null;} name of the file to read
* @return {@code non-null;} contents of the file
*/
@@ -46,7 +46,7 @@
/**
* Reads the given file, translating {@link IOException} to a
* {@link RuntimeException} of some sort.
- *
+ *
* @param file {@code non-null;} the file to read
* @return {@code non-null;} contents of the file
*/
diff --git a/dx/src/com/android/dx/util/FixedSizeList.java b/dx/src/com/android/dx/util/FixedSizeList.java
index 17d773c..fb3af04 100644
--- a/dx/src/com/android/dx/util/FixedSizeList.java
+++ b/dx/src/com/android/dx/util/FixedSizeList.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance. All indices initially contain {@code null}.
- *
+ *
* @param size the size of the list
*/
public FixedSizeList(int size) {
@@ -78,7 +78,7 @@
/**
* {@inheritDoc}
- *
+ *
* This method will only work if every element of the list
* implements {@link ToHuman}.
*/
@@ -93,7 +93,7 @@
/**
* Gets a customized string form for this instance.
- *
+ *
* @param prefix {@code null-ok;} prefix for the start of the result
* @param separator {@code null-ok;} separator to insert between each item
* @param suffix {@code null-ok;} suffix for the end of the result
@@ -107,7 +107,7 @@
* Gets a customized human string for this instance. This method will
* only work if every element of the list implements {@link
* ToHuman}.
- *
+ *
* @param prefix {@code null-ok;} prefix for the start of the result
* @param separator {@code null-ok;} separator to insert between each item
* @param suffix {@code null-ok;} suffix for the end of the result
@@ -168,7 +168,7 @@
* will throw {@code NullPointerException}. This method is
* protected so that subclasses may offer a safe type-checked
* public interface to their clients.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @return {@code non-null;} the indicated element
*/
@@ -192,7 +192,7 @@
* returned. This method is protected so that subclasses may
* (optionally) offer a safe type-checked public interface to
* their clients.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @return {@code null-ok;} the indicated element
*/
@@ -205,7 +205,7 @@
* checks on the element. This method is protected so that
* subclasses may offer a safe type-checked public interface to
* their clients.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param obj {@code null-ok;} the value to store
*/
@@ -222,7 +222,7 @@
/**
* Throws the appropriate exception for the given index value.
- *
+ *
* @param n the index value
* @return never
* @throws IndexOutOfBoundsException always thrown
@@ -238,11 +238,11 @@
/**
* Helper for {@link #toString} and {@link #toHuman}, which both of
* those call to pretty much do everything.
- *
+ *
* @param prefix {@code null-ok;} prefix for the start of the result
* @param separator {@code null-ok;} separator to insert between each item
* @param suffix {@code null-ok;} suffix for the end of the result
- * @param human whether the output is to be human
+ * @param human whether the output is to be human
* @return {@code non-null;} the custom string
*/
private String toString0(String prefix, String separator, String suffix,
diff --git a/dx/src/com/android/dx/util/Hex.java b/dx/src/com/android/dx/util/Hex.java
index cb71e5e..e95669c 100644
--- a/dx/src/com/android/dx/util/Hex.java
+++ b/dx/src/com/android/dx/util/Hex.java
@@ -29,7 +29,7 @@
/**
* Formats a {@code long} as an 8-byte unsigned hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -45,7 +45,7 @@
/**
* Formats an {@code int} as a 4-byte unsigned hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -61,7 +61,7 @@
/**
* Formats an {@code int} as a 3-byte unsigned hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -77,7 +77,7 @@
/**
* Formats an {@code int} as a 2-byte unsigned hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -95,7 +95,7 @@
* Formats an {@code int} as either a 2-byte unsigned hex value
* (if the value is small enough) or a 4-byte unsigned hex value (if
* not).
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -109,7 +109,7 @@
/**
* Formats an {@code int} as a 1-byte unsigned hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -125,7 +125,7 @@
/**
* Formats an {@code int} as a 4-bit unsigned hex nibble.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -138,7 +138,7 @@
/**
* Formats a {@code long} as an 8-byte signed hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -162,7 +162,7 @@
/**
* Formats an {@code int} as a 4-byte signed hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -186,7 +186,7 @@
/**
* Formats an {@code int} as a 2-byte signed hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -210,7 +210,7 @@
/**
* Formats an {@code int} as a 1-byte signed hex value.
- *
+ *
* @param v value to format
* @return {@code non-null;} formatted form
*/
@@ -236,7 +236,7 @@
* Formats a hex dump of a portion of a {@code byte[]}. The result
* is always newline-terminated, unless the passed-in length was zero,
* in which case the result is always the empty string ({@code ""}).
- *
+ *
* @param arr {@code non-null;} array to format
* @param offset {@code >= 0;} offset to the part to dump
* @param length {@code >= 0;} number of bytes to dump
@@ -253,7 +253,7 @@
// twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
if (((offset | length | end) < 0) || (end > arr.length)) {
throw new IndexOutOfBoundsException("arr.length " +
- arr.length + "; " +
+ arr.length + "; " +
offset + "..!" + end);
}
@@ -298,6 +298,6 @@
sb.append('\n');
}
- return sb.toString();
+ return sb.toString();
}
}
diff --git a/dx/src/com/android/dx/util/HexParser.java b/dx/src/com/android/dx/util/HexParser.java
index 3d0c992..1b34345 100644
--- a/dx/src/com/android/dx/util/HexParser.java
+++ b/dx/src/com/android/dx/util/HexParser.java
@@ -37,7 +37,7 @@
* comment. If a double quote is encountered, then the ASCII value
* of the subsequent characters is used, until the next double
* quote. Quoted strings may not span multiple lines.
- *
+ *
* @param src {@code non-null;} the source string
* @return {@code non-null;} the parsed form
*/
diff --git a/dx/src/com/android/dx/util/IndentingWriter.java b/dx/src/com/android/dx/util/IndentingWriter.java
index 92f0b55..3424e37 100644
--- a/dx/src/com/android/dx/util/IndentingWriter.java
+++ b/dx/src/com/android/dx/util/IndentingWriter.java
@@ -47,7 +47,7 @@
/**
* Constructs an instance.
- *
+ *
* @param out {@code non-null;} writer to send final output to
* @param width {@code >= 0;} the maximum output width (not including
* {@code prefix}), or {@code 0} for no maximum
@@ -77,7 +77,7 @@
/**
* Constructs a no-prefix instance.
- *
+ *
* @param out {@code non-null;} writer to send final output to
* @param width {@code >= 0;} the maximum output width (not including
* {@code prefix}), or {@code 0} for no maximum
diff --git a/dx/src/com/android/dx/util/IntList.java b/dx/src/com/android/dx/util/IntList.java
index c51c028..089fead 100644
--- a/dx/src/com/android/dx/util/IntList.java
+++ b/dx/src/com/android/dx/util/IntList.java
@@ -40,7 +40,7 @@
/**
* Constructs a new immutable instance with the given element.
- *
+ *
* @param value the sole value in the list
*/
public static IntList makeImmutable(int value) {
@@ -54,7 +54,7 @@
/**
* Constructs a new immutable instance with the given elements.
- *
+ *
* @param value0 the first value in the list
* @param value1 the second value in the list
*/
@@ -77,7 +77,7 @@
/**
* Constructs an empty instance.
- *
+ *
* @param initialCapacity {@code >= 0;} initial capacity of the list
*/
public IntList(int initialCapacity) {
@@ -164,7 +164,7 @@
/**
* Gets the indicated value.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @return the indicated element's value
*/
@@ -183,7 +183,7 @@
/**
* Sets the value at the given index.
- *
+ *
* @param n {@code >= 0, < size();} which element
* @param value value to store
*/
@@ -208,7 +208,7 @@
/**
* Adds an element to the end of the list. This will increase the
* list's capacity if necessary.
- *
+ *
* @param value the value to add
*/
public void add(int value) {
@@ -301,7 +301,7 @@
result = get(size-1);
size--;
- return result;
+ return result;
}
/**
@@ -318,7 +318,7 @@
/**
* Shrinks the size of the list.
- *
+ *
* @param newSize {@code >= 0;} the new size
*/
public void shrink(int newSize) {
@@ -337,7 +337,7 @@
/**
* Makes and returns a mutable copy of the list.
- *
+ *
* @return {@code non-null;} an appropriately-constructed instance
*/
public IntList mutableCopy() {
@@ -440,9 +440,9 @@
* Returns whether or not the given value appears in the list.
* This will do a binary search if the list is sorted or a linear
* search if not.
- *
+ *
* @see #sort
- *
+ *
* @param value value to look for
* @return whether the list contains the given value
*/
diff --git a/dx/src/com/android/dx/util/LabeledList.java b/dx/src/com/android/dx/util/LabeledList.java
index 28a148b..5b6e125 100644
--- a/dx/src/com/android/dx/util/LabeledList.java
+++ b/dx/src/com/android/dx/util/LabeledList.java
@@ -156,6 +156,6 @@
if (item != null) {
addLabelIndex(item.getLabel(), n);
- }
+ }
}
}
diff --git a/dx/src/com/android/dx/util/Leb128Utils.java b/dx/src/com/android/dx/util/Leb128Utils.java
index 6ed3a61..5d450ea 100644
--- a/dx/src/com/android/dx/util/Leb128Utils.java
+++ b/dx/src/com/android/dx/util/Leb128Utils.java
@@ -30,13 +30,13 @@
/**
* Gets the number of bytes in the unsigned LEB128 encoding of the
* given value.
- *
+ *
* @param value the value in question
* @return its write size, in bytes
*/
public static int unsignedLeb128Size(int value) {
// TODO: This could be much cleverer.
-
+
int remaining = value >> 7;
int count = 0;
@@ -51,7 +51,7 @@
/**
* Gets the number of bytes in the signed LEB128 encoding of the
* given value.
- *
+ *
* @param value the value in question
* @return its write size, in bytes
*/
diff --git a/dx/src/com/android/dx/util/ListIntSet.java b/dx/src/com/android/dx/util/ListIntSet.java
index 6d28a18..2b4fc21 100644
--- a/dx/src/com/android/dx/util/ListIntSet.java
+++ b/dx/src/com/android/dx/util/ListIntSet.java
@@ -54,7 +54,7 @@
/** @inheritDoc */
public boolean has(int value) {
- return ints.indexOf(value) >= 0;
+ return ints.indexOf(value) >= 0;
}
/** @inheritDoc */
@@ -70,7 +70,7 @@
while (j < szOther && i < szThis) {
while (j < szOther && o.ints.get(j) < ints.get(i)) {
add(o.ints.get(j++));
- }
+ }
if (j == szOther) {
break;
}
diff --git a/dx/src/com/android/dx/util/Output.java b/dx/src/com/android/dx/util/Output.java
index 5e737ae..402fa83 100644
--- a/dx/src/com/android/dx/util/Output.java
+++ b/dx/src/com/android/dx/util/Output.java
@@ -17,7 +17,7 @@
package com.android.dx.util;
/**
- * Interface for a sink for binary output. This is similar to
+ * Interface for a sink for binary output. This is similar to
* {@code java.util.DataOutput}, but no {@code IOExceptions}
* are declared, and multibyte output is defined to be little-endian.
*/
@@ -25,44 +25,44 @@
/**
* Gets the current cursor position. This is the same as the number of
* bytes written to this instance.
- *
+ *
* @return {@code >= 0;} the cursor position
*/
public int getCursor();
/**
* Asserts that the cursor is the given value.
- *
+ *
* @param expectedCursor the expected cursor value
* @throws RuntimeException thrown if {@code getCursor() !=
* expectedCursor}
*/
public void assertCursor(int expectedCursor);
-
+
/**
* Writes a {@code byte} to this instance.
- *
+ *
* @param value the value to write; all but the low 8 bits are ignored
*/
public void writeByte(int value);
/**
* Writes a {@code short} to this instance.
- *
+ *
* @param value the value to write; all but the low 16 bits are ignored
*/
public void writeShort(int value);
/**
* Writes an {@code int} to this instance.
- *
+ *
* @param value the value to write
*/
public void writeInt(int value);
/**
* Writes a {@code long} to this instance.
- *
+ *
* @param value the value to write
*/
public void writeLong(long value);
@@ -89,14 +89,14 @@
/**
* Writes a {@link ByteArray} to this instance.
- *
+ *
* @param bytes {@code non-null;} the array to write
*/
public void write(ByteArray bytes);
/**
* Writes a portion of a {@code byte[]} to this instance.
- *
+ *
* @param bytes {@code non-null;} the array to write
* @param offset {@code >= 0;} offset into {@code bytes} for the first
* byte to write
@@ -107,22 +107,22 @@
/**
* Writes a {@code byte[]} to this instance. This is just
* a convenient shorthand for {@code write(bytes, 0, bytes.length)}.
- *
+ *
* @param bytes {@code non-null;} the array to write
*/
public void write(byte[] bytes);
- /**
+ /**
* Writes the given number of {@code 0} bytes.
- *
+ *
* @param count {@code >= 0;} the number of zeroes to write
*/
public void writeZeroes(int count);
- /**
+ /**
* Adds extra bytes if necessary (with value {@code 0}) to
* force alignment of the output cursor as given.
- *
+ *
* @param alignment {@code > 0;} the alignment; must be a power of two
*/
public void alignTo(int alignment);
diff --git a/dx/src/com/android/dx/util/TwoColumnOutput.java b/dx/src/com/android/dx/util/TwoColumnOutput.java
index a155c15..ed2ab9f 100644
--- a/dx/src/com/android/dx/util/TwoColumnOutput.java
+++ b/dx/src/com/android/dx/util/TwoColumnOutput.java
@@ -49,7 +49,7 @@
/**
* Turns the given two strings (with widths) and spacer into a formatted
* two-column string.
- *
+ *
* @param s1 {@code non-null;} first string
* @param width1 {@code > 0;} width of the first column
* @param spacer {@code non-null;} spacer string
@@ -79,7 +79,7 @@
/**
* Constructs an instance.
- *
+ *
* @param out {@code non-null;} writer to send final output to
* @param leftWidth {@code > 0;} width of the left column, in characters
* @param rightWidth {@code > 0;} width of the right column, in characters
@@ -117,7 +117,7 @@
/**
* Constructs an instance.
- *
+ *
* @param out {@code non-null;} stream to send final output to
* @param leftWidth {@code >= 1;} width of the left column, in characters
* @param rightWidth {@code >= 1;} width of the right column, in characters
@@ -130,7 +130,7 @@
/**
* Gets the writer to use to write to the left column.
- *
+ *
* @return {@code non-null;} the left column writer
*/
public Writer getLeft() {
@@ -139,7 +139,7 @@
/**
* Gets the writer to use to write to the right column.
- *
+ *
* @return {@code non-null;} the right column writer
*/
public Writer getRight() {
@@ -225,12 +225,12 @@
/**
* Appends a newline to the given buffer via the given writer, but
* only if it isn't empty and doesn't already end with one.
- *
+ *
* @param buf {@code non-null;} the buffer in question
* @param out {@code non-null;} the writer to use
*/
private static void appendNewlineIfNecessary(StringBuffer buf,
- Writer out)
+ Writer out)
throws IOException {
int len = buf.length();
@@ -241,7 +241,7 @@
/**
* Writes the given number of spaces to the given writer.
- *
+ *
* @param out {@code non-null;} where to write
* @param amt {@code >= 0;} the number of spaces to write
*/
diff --git a/dx/src/com/android/dx/util/Writers.java b/dx/src/com/android/dx/util/Writers.java
index 632b082..eba845c 100644
--- a/dx/src/com/android/dx/util/Writers.java
+++ b/dx/src/com/android/dx/util/Writers.java
@@ -34,7 +34,7 @@
* Makes a {@code PrintWriter} for the given {@code Writer},
* returning the given writer if it already happens to be the right
* class.
- *
+ *
* @param writer {@code non-null;} writer to (possibly) wrap
* @return {@code non-null;} an appropriate instance
*/
diff --git a/dx/src/com/android/dx/util/_tests/_ListIntSet.java b/dx/src/com/android/dx/util/_tests/_ListIntSet.java
index aed79b0..ccd5991 100644
--- a/dx/src/com/android/dx/util/_tests/_ListIntSet.java
+++ b/dx/src/com/android/dx/util/_tests/_ListIntSet.java
@@ -39,7 +39,7 @@
assertTrue(set.has(31));
assertEquals(3, set.elements());
-
+
assertFalse(set.has(2));
assertFalse(set.has(7));
assertFalse(set.has(30));
@@ -79,7 +79,7 @@
IntIterator iter = set.iterator();
- assertFalse(iter.hasNext());
+ assertFalse(iter.hasNext());
}
public void test_remove() {
diff --git a/dx/tests/010-class-attrib-InnerClasses/small-class.txt b/dx/tests/010-class-attrib-InnerClasses/small-class.txt
index 6ad13a4..54fd19d 100644
--- a/dx/tests/010-class-attrib-InnerClasses/small-class.txt
+++ b/dx/tests/010-class-attrib-InnerClasses/small-class.txt
@@ -35,4 +35,3 @@
0003 0000 0001 0002 # Small / null / "Small" / private
0003 0007 0000 0004 # Small / Zorch / null / protected
0007 0003 0006 ffff # Zorch / Small / "Zorch" / all-bits
-
diff --git a/dx/tests/021-code-attrib-LineNumberTable/info.txt b/dx/tests/021-code-attrib-LineNumberTable/info.txt
index 3e81d29..2ffc798 100644
--- a/dx/tests/021-code-attrib-LineNumberTable/info.txt
+++ b/dx/tests/021-code-attrib-LineNumberTable/info.txt
@@ -5,4 +5,3 @@
The salient bit of parsing tested here is that the class has a single
method with a simple Code attribute, which itself has a syntactically
valid LineNumberTable attribute.
-
diff --git a/dx/tests/022-code-attrib-LocalVariableTable/info.txt b/dx/tests/022-code-attrib-LocalVariableTable/info.txt
index d1afa33..5b44286 100644
--- a/dx/tests/022-code-attrib-LocalVariableTable/info.txt
+++ b/dx/tests/022-code-attrib-LocalVariableTable/info.txt
@@ -5,4 +5,3 @@
The salient bit of parsing tested here is that the class has a single
method with a simple Code attribute, which itself has a syntactically
valid LocalVariableTable attribute.
-
diff --git a/dx/tests/023-code-exception-table/info.txt b/dx/tests/023-code-exception-table/info.txt
index f4bb35e..2dbb5da 100644
--- a/dx/tests/023-code-exception-table/info.txt
+++ b/dx/tests/023-code-exception-table/info.txt
@@ -5,4 +5,3 @@
The salient bit of parsing tested here is that the class has a single
method with a minimal but syntactically valid Code attribute, which
sports a non-empty syntactically valid exception table.
-
diff --git a/dx/tests/028-class-attrib-EnclosingMethod/info.txt b/dx/tests/028-class-attrib-EnclosingMethod/info.txt
index 206a43e..9600803 100644
--- a/dx/tests/028-class-attrib-EnclosingMethod/info.txt
+++ b/dx/tests/028-class-attrib-EnclosingMethod/info.txt
@@ -6,4 +6,3 @@
class-level EnclosingMethod attribute, which is syntactically valid. There
are two possible variants (method may be null), and this test contains one
of each.
-
diff --git a/dx/tests/031-bb-dead-code/blort.j b/dx/tests/031-bb-dead-code/blort.j
index d3e20d0..b6854f2 100644
--- a/dx/tests/031-bb-dead-code/blort.j
+++ b/dx/tests/031-bb-dead-code/blort.j
@@ -180,4 +180,3 @@
blort:
return
.end method
-
diff --git a/dx/tests/032-bb-live-code/blort.j b/dx/tests/032-bb-live-code/blort.j
index a1ec1dc..05790bb 100644
--- a/dx/tests/032-bb-live-code/blort.j
+++ b/dx/tests/032-bb-live-code/blort.j
@@ -340,4 +340,3 @@
multianewarray [[[I 2
return
.end method
-
diff --git a/dx/tests/038-dex-instance-method/info.txt b/dx/tests/038-dex-instance-method/info.txt
index c9ce0b1..6aa93c3 100644
--- a/dx/tests/038-dex-instance-method/info.txt
+++ b/dx/tests/038-dex-instance-method/info.txt
@@ -2,4 +2,3 @@
conversion runs without failure, though the contents of the converted
file are not checked for correctness. This test is of a classfile with
just an instance method.
-
diff --git a/dx/tests/042-dex-ignore-result/Blort.java b/dx/tests/042-dex-ignore-result/Blort.java
index 21370ed..2df4e66 100644
--- a/dx/tests/042-dex-ignore-result/Blort.java
+++ b/dx/tests/042-dex-ignore-result/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
static public int hello() {
return 10;
diff --git a/dx/tests/043-dex-two-classes/Blort.java b/dx/tests/043-dex-two-classes/Blort.java
index 1d9de84..235907d 100644
--- a/dx/tests/043-dex-two-classes/Blort.java
+++ b/dx/tests/043-dex-two-classes/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
// This space intentionally left blank.
}
diff --git a/dx/tests/044-dex-math-ops/Blort.java b/dx/tests/044-dex-math-ops/Blort.java
index bf73c33..75095b5 100644
--- a/dx/tests/044-dex-math-ops/Blort.java
+++ b/dx/tests/044-dex-math-ops/Blort.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
private volatile int i;
private volatile long l;
private volatile float f;
private volatile double d;
-
+
public void blort(int i1, int i2) {
i = -i1;
i = ~i1;
@@ -69,5 +69,5 @@
d = d1 * d2;
d = d1 / d2;
d = d1 % d2;
- }
+ }
}
diff --git a/dx/tests/045-dex-switch-ops/Blort.java b/dx/tests/045-dex-switch-ops/Blort.java
index fed741f..598bd69 100644
--- a/dx/tests/045-dex-switch-ops/Blort.java
+++ b/dx/tests/045-dex-switch-ops/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public int switchTest1(int x) {
switch (x) {
diff --git a/dx/tests/046-dex-exceptions/Blort.java b/dx/tests/046-dex-exceptions/Blort.java
index 8d040c4..a0b6c0b 100644
--- a/dx/tests/046-dex-exceptions/Blort.java
+++ b/dx/tests/046-dex-exceptions/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int maybeThrow(int x) {
if (x < 10) {
@@ -23,7 +23,7 @@
return x;
}
-
+
public static int exTest1(int x) {
try {
maybeThrow(x);
diff --git a/dx/tests/047-dex-wide-args/Blort.java b/dx/tests/047-dex-wide-args/Blort.java
index e7fc9b5..fa0f1d8 100644
--- a/dx/tests/047-dex-wide-args/Blort.java
+++ b/dx/tests/047-dex-wide-args/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static long test1(int w, long x, int y, long z) {
return w + x + y + z;
diff --git a/dx/tests/048-dex-new-array/Blort.java b/dx/tests/048-dex-new-array/Blort.java
index 312370c..1af0cde 100644
--- a/dx/tests/048-dex-new-array/Blort.java
+++ b/dx/tests/048-dex-new-array/Blort.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static void sink(Object x) {
// Do nothing.
}
-
+
public static void test() {
sink(new boolean[0]);
sink(new byte[1]);
diff --git a/dx/tests/049-dex-instanceof/Blort.java b/dx/tests/049-dex-instanceof/Blort.java
index 2d46cd1..ad41f30 100644
--- a/dx/tests/049-dex-instanceof/Blort.java
+++ b/dx/tests/049-dex-instanceof/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static boolean test(Object x) {
return x instanceof Blort;
diff --git a/dx/tests/050-dex-checkcast/Blort.java b/dx/tests/050-dex-checkcast/Blort.java
index 893c3a3..5441eec 100644
--- a/dx/tests/050-dex-checkcast/Blort.java
+++ b/dx/tests/050-dex-checkcast/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static Blort test(Object x) {
return (Blort) x;
diff --git a/dx/tests/051-dex-explicit-null/Blort.java b/dx/tests/051-dex-explicit-null/Blort.java
index f3bb333..9045c50 100644
--- a/dx/tests/051-dex-explicit-null/Blort.java
+++ b/dx/tests/051-dex-explicit-null/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static Object test1() {
return null;
diff --git a/dx/tests/052-dex-static-var-access/Blort.java b/dx/tests/052-dex-static-var-access/Blort.java
index fdbefb4..3dd0e78 100644
--- a/dx/tests/052-dex-static-var-access/Blort.java
+++ b/dx/tests/052-dex-static-var-access/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static boolean staticBoolean;
public static byte staticByte;
diff --git a/dx/tests/053-dex-instance-var-access/Blort.java b/dx/tests/053-dex-instance-var-access/Blort.java
index 1f68737..eb62d62 100644
--- a/dx/tests/053-dex-instance-var-access/Blort.java
+++ b/dx/tests/053-dex-instance-var-access/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public boolean insBoolean;
public byte insByte;
diff --git a/dx/tests/054-dex-high16/Blort.java b/dx/tests/054-dex-high16/Blort.java
index e8976fa..9fba972 100644
--- a/dx/tests/054-dex-high16/Blort.java
+++ b/dx/tests/054-dex-high16/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static void sink(int i) {
// Do nothing.
diff --git a/dx/tests/055-dex-explicit-throw/Blort.java b/dx/tests/055-dex-explicit-throw/Blort.java
index a47ba90..e6720d9 100644
--- a/dx/tests/055-dex-explicit-throw/Blort.java
+++ b/dx/tests/055-dex-explicit-throw/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
private static RuntimeException theException = new RuntimeException();
diff --git a/dx/tests/056-dex-call-interface/Blort.java b/dx/tests/056-dex-call-interface/Blort.java
index 75775e6..4175f05 100644
--- a/dx/tests/056-dex-call-interface/Blort.java
+++ b/dx/tests/056-dex-call-interface/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int test(Zorch z, double d) {
z.zorch1();
diff --git a/dx/tests/057-dex-call-virtual/Blort.java b/dx/tests/057-dex-call-virtual/Blort.java
index e32135b..75ee7d8 100644
--- a/dx/tests/057-dex-call-virtual/Blort.java
+++ b/dx/tests/057-dex-call-virtual/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int test(Zorch z) {
z.zorch1();
diff --git a/dx/tests/057-dex-call-virtual/Zorch.java b/dx/tests/057-dex-call-virtual/Zorch.java
index 718601f..867eaed 100644
--- a/dx/tests/057-dex-call-virtual/Zorch.java
+++ b/dx/tests/057-dex-call-virtual/Zorch.java
@@ -16,7 +16,7 @@
public class Zorch
{
- public void zorch1() {
+ public void zorch1() {
// This space intentionally left blank.
}
diff --git a/dx/tests/058-dex-call-direct/Blort.java b/dx/tests/058-dex-call-direct/Blort.java
index 77e224c..6d7fa7f 100644
--- a/dx/tests/058-dex-call-direct/Blort.java
+++ b/dx/tests/058-dex-call-direct/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int test(Blort b) {
b.zorch1();
diff --git a/dx/tests/059-dex-call-super/Blort.java b/dx/tests/059-dex-call-super/Blort.java
index 599440b..efb451e 100644
--- a/dx/tests/059-dex-call-super/Blort.java
+++ b/dx/tests/059-dex-call-super/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
extends Zorch
{
public int test1() {
diff --git a/dx/tests/059-dex-call-super/Zorch.java b/dx/tests/059-dex-call-super/Zorch.java
index 2f8951a..aa668ab 100644
--- a/dx/tests/059-dex-call-super/Zorch.java
+++ b/dx/tests/059-dex-call-super/Zorch.java
@@ -16,7 +16,7 @@
public class Zorch
{
- public void zorch1() {
+ public void zorch1() {
// This space intentionally left blank.
}
diff --git a/dx/tests/060-dex-call-static/Blort.java b/dx/tests/060-dex-call-static/Blort.java
index 2b9bb48..8ad2e27 100644
--- a/dx/tests/060-dex-call-static/Blort.java
+++ b/dx/tests/060-dex-call-static/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int test() {
Zorch.zorch1();
diff --git a/dx/tests/061-dex-try-catch/Blort.java b/dx/tests/061-dex-try-catch/Blort.java
index b63a41e..903f40e 100644
--- a/dx/tests/061-dex-try-catch/Blort.java
+++ b/dx/tests/061-dex-try-catch/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static void caught() {
// This space intentionally left blank.
diff --git a/dx/tests/062-dex-synch-method/Blort.java b/dx/tests/062-dex-synch-method/Blort.java
index 823c2ca..4aca417 100644
--- a/dx/tests/062-dex-synch-method/Blort.java
+++ b/dx/tests/062-dex-synch-method/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public synchronized void testInstance1() {
// This space intentionally left blank.
diff --git a/dx/tests/063-dex-empty-switch/Blort.java b/dx/tests/063-dex-empty-switch/Blort.java
index 2d996f3..f538995 100644
--- a/dx/tests/063-dex-empty-switch/Blort.java
+++ b/dx/tests/063-dex-empty-switch/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public int test1(int x) {
switch (x) {
diff --git a/dx/tests/064-dex-array-access/Blort.java b/dx/tests/064-dex-array-access/Blort.java
index 3f1d1d8..fa03ec0 100644
--- a/dx/tests/064-dex-array-access/Blort.java
+++ b/dx/tests/064-dex-array-access/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public boolean test01(boolean[] x) {
x[0] = true;
diff --git a/dx/tests/065-dex-new-array/Blort.java b/dx/tests/065-dex-new-array/Blort.java
index 93af87f..7a7eaa4 100644
--- a/dx/tests/065-dex-new-array/Blort.java
+++ b/dx/tests/065-dex-new-array/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public boolean[] test1() {
return new boolean[1];
diff --git a/dx/tests/066-dex-try-catch-rethrow/Blort.java b/dx/tests/066-dex-try-catch-rethrow/Blort.java
index cefc0fd..cdb00ea 100644
--- a/dx/tests/066-dex-try-catch-rethrow/Blort.java
+++ b/dx/tests/066-dex-try-catch-rethrow/Blort.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static Object zorch1(String s) {
return null;
}
-
+
public static void test1() {
try {
zorch1("x");
@@ -43,7 +43,7 @@
public static int zorch3(String s) {
return 0;
}
-
+
public static void test3() {
try {
zorch3("x");
@@ -55,7 +55,7 @@
public static Object zorch4(int x) {
return null;
}
-
+
public static void test4() {
try {
zorch4(1);
@@ -67,7 +67,7 @@
public static Object zorch5(int x) {
return null;
}
-
+
public static Object test5() {
try {
return zorch5(1);
diff --git a/dx/tests/067-dex-switch-and-try/Blort.java b/dx/tests/067-dex-switch-and-try/Blort.java
index d90bd32..e6435e1 100644
--- a/dx/tests/067-dex-switch-and-try/Blort.java
+++ b/dx/tests/067-dex-switch-and-try/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
static public void blort() {
// This space intentionally left blank.
diff --git a/dx/tests/068-dex-infinite-loop/Blort.java b/dx/tests/068-dex-infinite-loop/Blort.java
index 09c45a4..f026407 100644
--- a/dx/tests/068-dex-infinite-loop/Blort.java
+++ b/dx/tests/068-dex-infinite-loop/Blort.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static boolean zorch() {
return true;
}
-
+
public static void test1() {
for (;;) {
// This space intentionally left blank.
@@ -43,7 +43,7 @@
if (zorch()) {
break;
}
-
+
while (zorch()) {
zorch();
}
diff --git a/dx/tests/069-dex-source-position/Blort.java b/dx/tests/069-dex-source-position/Blort.java
index 5cede03..8c0c5c0 100644
--- a/dx/tests/069-dex-source-position/Blort.java
+++ b/dx/tests/069-dex-source-position/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int test(int x) {
if (x == 0) { // line 6
diff --git a/dx/tests/070-dex-multianewarray/Blort.java b/dx/tests/070-dex-multianewarray/Blort.java
index 500b14c..ef812cf 100644
--- a/dx/tests/070-dex-multianewarray/Blort.java
+++ b/dx/tests/070-dex-multianewarray/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static Object test01() {
Object[][] x = new Object[2][5];
diff --git a/dx/tests/072-dex-switch-edge-cases/Blort.java b/dx/tests/072-dex-switch-edge-cases/Blort.java
index ba2e033..2d4d107 100644
--- a/dx/tests/072-dex-switch-edge-cases/Blort.java
+++ b/dx/tests/072-dex-switch-edge-cases/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
// Empty switch statement. (Note: This is the same as a default-only
// switch statement, since under the covers every switch statement
@@ -44,7 +44,7 @@
return 1;
}
-
+
// Single element: Integer.MAX_VALUE.
public int test4(int x) {
switch (x) {
diff --git a/dx/tests/073-dex-null-array-refs/Blort.java b/dx/tests/073-dex-null-array-refs/Blort.java
index b6678c0..e16e0f4 100644
--- a/dx/tests/073-dex-null-array-refs/Blort.java
+++ b/dx/tests/073-dex-null-array-refs/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static Object test1() {
return ((Object[]) null)[0];
@@ -50,7 +50,7 @@
return arr[0];
}
-
+
public static void test8(Object[] arr) {
if (check()) {
arr = null;
diff --git a/dx/tests/074-dex-form35c-edge-case/Blort.java b/dx/tests/074-dex-form35c-edge-case/Blort.java
index 60efc63..979263f 100644
--- a/dx/tests/074-dex-form35c-edge-case/Blort.java
+++ b/dx/tests/074-dex-form35c-edge-case/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public void test()
{
diff --git a/dx/tests/075-dex-cat2-value-merge/Blort.java b/dx/tests/075-dex-cat2-value-merge/Blort.java
index d1bf0be..0aa4c5a 100644
--- a/dx/tests/075-dex-cat2-value-merge/Blort.java
+++ b/dx/tests/075-dex-cat2-value-merge/Blort.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static void test(long[] arr)
{
long x = 0;
-
+
for (;;) {
x += arr[0];
}
diff --git a/dx/tests/076-dex-synch-and-stack/Blort.java b/dx/tests/076-dex-synch-and-stack/Blort.java
index 6ba9757..8a83492 100644
--- a/dx/tests/076-dex-synch-and-stack/Blort.java
+++ b/dx/tests/076-dex-synch-and-stack/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public synchronized void test() {
new Object();
diff --git a/dx/tests/077-dex-code-alignment/Blort.java b/dx/tests/077-dex-code-alignment/Blort.java
index 862cd51..3ec041a 100644
--- a/dx/tests/077-dex-code-alignment/Blort.java
+++ b/dx/tests/077-dex-code-alignment/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static void justReturn1() {
// This space intentionally left blank.
diff --git a/dx/tests/078-dex-local-variable-table/Blort.java b/dx/tests/078-dex-local-variable-table/Blort.java
index d9f006f..7291445 100644
--- a/dx/tests/078-dex-local-variable-table/Blort.java
+++ b/dx/tests/078-dex-local-variable-table/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static void test01(Object x) {
x.hashCode();
diff --git a/dx/tests/079-dex-local-variable-renumbering/Blort.java b/dx/tests/079-dex-local-variable-renumbering/Blort.java
index 629da90..c8453a2 100644
--- a/dx/tests/079-dex-local-variable-renumbering/Blort.java
+++ b/dx/tests/079-dex-local-variable-renumbering/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public static int test1(int x) {
float f0 = 0.0f;
diff --git a/dx/tests/080-dex-exception-tables/Blort.java b/dx/tests/080-dex-exception-tables/Blort.java
index f406bee..2143f7f 100644
--- a/dx/tests/080-dex-exception-tables/Blort.java
+++ b/dx/tests/080-dex-exception-tables/Blort.java
@@ -30,7 +30,7 @@
return 10;
} catch (RuntimeException ex) {
return 11;
- }
+ }
call3();
return 12;
@@ -141,13 +141,13 @@
call1();
} catch (RuntimeException ex) {
return 10;
- }
+ }
try {
call2();
} catch (RuntimeException ex) {
return 11;
- }
+ }
return 12;
}
@@ -158,14 +158,14 @@
call2();
} catch (RuntimeException ex) {
return 10;
- }
+ }
try {
call3();
call4();
} catch (RuntimeException ex) {
return 11;
- }
+ }
return 12;
}
@@ -195,5 +195,5 @@
return 14;
}
-
+
}
diff --git a/dx/tests/083-ssa-phi-placement/Blort.java b/dx/tests/083-ssa-phi-placement/Blort.java
index b314290..ed3264d 100644
--- a/dx/tests/083-ssa-phi-placement/Blort.java
+++ b/dx/tests/083-ssa-phi-placement/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
public int phiTest() {
@@ -22,7 +22,7 @@
int j = 1;
int k = 0;
- while (k < 100) {
+ while (k < 100) {
if (j < 20) {
j = i;
k++;
@@ -64,4 +64,3 @@
}
}
}
-
diff --git a/dx/tests/084-dex-high-register-moves/Blort.java b/dx/tests/084-dex-high-register-moves/Blort.java
index 736cefb..e68ebd8 100644
--- a/dx/tests/084-dex-high-register-moves/Blort.java
+++ b/dx/tests/084-dex-high-register-moves/Blort.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
private static int i;
private static long l;
private static Object o;
-
+
public static void test() {
int i0 = 0;
int i1 = 0;
diff --git a/dx/tests/085-dex-jsr-ret/blort.j b/dx/tests/085-dex-jsr-ret/blort.j
index 2f4bf38..2616723 100644
--- a/dx/tests/085-dex-jsr-ret/blort.j
+++ b/dx/tests/085-dex-jsr-ret/blort.j
@@ -67,5 +67,3 @@
.catch java/lang/Throwable from j2 to j2a using catchBlock
.end method
-
-
diff --git a/dx/tests/085-dex-jsr-ret/info.txt b/dx/tests/085-dex-jsr-ret/info.txt
index 4542fde..8e164d6 100644
--- a/dx/tests/085-dex-jsr-ret/info.txt
+++ b/dx/tests/085-dex-jsr-ret/info.txt
@@ -1,2 +1 @@
Tests handling of the Java jsr/jsr_w/ret bytecodes.
-
diff --git a/dx/tests/086-ssa-edge-split/Blort.java b/dx/tests/086-ssa-edge-split/Blort.java
index 5e54dfd..d12b3f9 100644
--- a/dx/tests/086-ssa-edge-split/Blort.java
+++ b/dx/tests/086-ssa-edge-split/Blort.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
/**
* This method requires the edge-splitter to add a node
* to get to the finally block, since there are
* two exception sources.
- *
+ *
*/
public int edgeSplitPredTest(int x) {
int y = 1;
@@ -45,7 +45,7 @@
* a unique predecessor
*/
void edgeSplitMoveException() {
- try {
+ try {
hashCode();
hashCode();
} catch (Throwable tr) {
@@ -60,7 +60,7 @@
*/
int edgeSplitSuccessor(int x) {
int y = 0;
-
+
switch(x) {
case 1: y++;
break;
@@ -72,4 +72,3 @@
return y;
}
}
-
diff --git a/dx/tests/087-ssa-local-vars/Blort.java b/dx/tests/087-ssa-local-vars/Blort.java
index f149790..7ce8a91 100644
--- a/dx/tests/087-ssa-local-vars/Blort.java
+++ b/dx/tests/087-ssa-local-vars/Blort.java
@@ -24,7 +24,7 @@
System.out.println("object -> string (modified)");
objectArray[4] = new Object();
try {
- System.arraycopy(objectArray, 0, stringArray, 0,stringArray.length);
+ System.arraycopy(objectArray, 0, stringArray, 0,stringArray.length);
} catch (ArrayStoreException ase) {
// "ase" is an unused local which still must be preserved
System.out.println("caught ArrayStoreException (expected)");
@@ -40,7 +40,7 @@
System.err.println(foo);
}
/**
- * Stolen from
+ * Stolen from
* java/android/org/apache/http/impl/io/AbstractMessageParser.java
* Simplified.
*
@@ -76,7 +76,7 @@
}
i++;
}
- if (maxLineLen > 0
+ if (maxLineLen > 0
&& previous.length() + 1 + current.length() - i > maxLineLen) {
throw new IOException("Maximum line length limit exceeded");
}
@@ -92,4 +92,3 @@
}
}
}
-
diff --git a/dx/tests/088-ssa-combine-blocks/Blort.java b/dx/tests/088-ssa-combine-blocks/Blort.java
index 6449883..bf49dbe 100644
--- a/dx/tests/088-ssa-combine-blocks/Blort.java
+++ b/dx/tests/088-ssa-combine-blocks/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
/**
* just because this should do nothing
@@ -27,7 +27,7 @@
* a unique predecessor
*/
void edgeSplitMoveException() {
- try {
+ try {
hashCode();
hashCode();
} catch (Throwable tr) {
@@ -42,4 +42,3 @@
}
}
}
-
diff --git a/dx/tests/089-dex-define-object/Object.java b/dx/tests/089-dex-define-object/Object.java
index e4d9e3c..575c736 100644
--- a/dx/tests/089-dex-define-object/Object.java
+++ b/dx/tests/089-dex-define-object/Object.java
@@ -17,15 +17,15 @@
package java.lang;
public class Object {
- public Object() {
+ public Object() {
// This space intentionally left blank.
}
public boolean equals(Object o) {
- return true;
+ return true;
}
- protected void finalize() {
+ protected void finalize() {
// This space intentionally left blank.
}
@@ -35,7 +35,7 @@
public final native void notifyAll();
public String toString() {
- return "blort";
+ return "blort";
}
public final void wait() {
diff --git a/dx/tests/090-dex-unify-arrays/Blort.java b/dx/tests/090-dex-unify-arrays/Blort.java
index 47e1745..507153e 100644
--- a/dx/tests/090-dex-unify-arrays/Blort.java
+++ b/dx/tests/090-dex-unify-arrays/Blort.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-public class Blort
+public class Blort
{
/*
* Note: The use of the casts after the "?" in the following are
diff --git a/dx/tests/091-ssa-const-collector/Blort.java b/dx/tests/091-ssa-const-collector/Blort.java
index 40626e2..ea99a0d 100644
--- a/dx/tests/091-ssa-const-collector/Blort.java
+++ b/dx/tests/091-ssa-const-collector/Blort.java
@@ -4,7 +4,7 @@
enum Foo {
ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT
}
-
+
/** all uses of 10 should be combined except the local assignment */
void testNumeric() {
int foo = 10;
@@ -62,4 +62,3 @@
}
}
-
diff --git a/dx/tests/092-ssa-cfg-edge-cases/Blort.java b/dx/tests/092-ssa-cfg-edge-cases/Blort.java
index a1f264e..8b3602f 100644
--- a/dx/tests/092-ssa-cfg-edge-cases/Blort.java
+++ b/dx/tests/092-ssa-cfg-edge-cases/Blort.java
@@ -1,6 +1,6 @@
class Blort {
-
+
void testMultipleIdenticalSuccessors(int foo) {
switch(foo) {
case 1:
@@ -18,4 +18,3 @@
}
}
}
-
diff --git a/dx/tests/093-ssa-invoke-range/Blort.java b/dx/tests/093-ssa-invoke-range/Blort.java
index a75e31f..f2bb66c 100644
--- a/dx/tests/093-ssa-invoke-range/Blort.java
+++ b/dx/tests/093-ssa-invoke-range/Blort.java
@@ -1,10 +1,10 @@
class Blort {
-
+
static void methodThatNeedsInvokeRange
(int a, int b, int c, int d, int e, int f) {
}
-
+
void testNoLocals() {
methodThatNeedsInvokeRange(5, 0, 5, 0, 5, 0);
}
@@ -50,7 +50,7 @@
methodThatNeedsInvokeRange(src, 0, dest, 1, 5, 0);
methodThatNeedsInvokeRange(dest, 0, src, 1, 5, 0);
}
-
+
// ensure that an attempt to combine registers for a local
// with a differing category doesn't mess us up.
long testMixedCategory(boolean foo) {
@@ -67,4 +67,3 @@
}
}
}
-
diff --git a/dx/tests/094-scala-locals/blort.j b/dx/tests/094-scala-locals/blort.j
index 0d3cae5..7c711ef 100644
--- a/dx/tests/094-scala-locals/blort.j
+++ b/dx/tests/094-scala-locals/blort.j
@@ -42,4 +42,3 @@
end:
return
.end method
-
diff --git a/dx/tests/095-dex-const-string-jumbo/run b/dx/tests/095-dex-const-string-jumbo/run
index d984333..a1c7365 100644
--- a/dx/tests/095-dex-const-string-jumbo/run
+++ b/dx/tests/095-dex-const-string-jumbo/run
@@ -39,4 +39,3 @@
$JAVAC -d . *.java
dx --debug --dex --no-optimize --positions=none --no-locals \
--dump-method=Blort.test *.class
-
diff --git a/dx/tests/098-dex-jsr-ret-throw/info.txt b/dx/tests/098-dex-jsr-ret-throw/info.txt
index 41636a2..9dcd39d 100644
--- a/dx/tests/098-dex-jsr-ret-throw/info.txt
+++ b/dx/tests/098-dex-jsr-ret-throw/info.txt
@@ -2,4 +2,3 @@
It contains an example of a subroutine being exited by a "throw" instruction in
such a way that it caused the frame merge and subroutine inliner
algorithms to not converge. This was bug #1137450.
-
diff --git a/dx/tests/104-verify-return-ops/run b/dx/tests/104-verify-return-ops/run
index 471d490..fbce332 100644
--- a/dx/tests/104-verify-return-ops/run
+++ b/dx/tests/104-verify-return-ops/run
@@ -36,4 +36,3 @@
oneop sig_ireturn
oneop sig_lreturn
oneop sig_return
-
diff --git a/dx/tests/105-verify-load-store-ops/info.txt b/dx/tests/105-verify-load-store-ops/info.txt
index 85b7311..a3a41d6 100644
--- a/dx/tests/105-verify-load-store-ops/info.txt
+++ b/dx/tests/105-verify-load-store-ops/info.txt
@@ -1,3 +1,2 @@
This tests that load and store opcodes verify that their arguments are
actually of the appropriate types.
-
diff --git a/dx/tests/111-use-null-as-array/Blort.java b/dx/tests/111-use-null-as-array/Blort.java
index c16684f..79d2b4f 100644
--- a/dx/tests/111-use-null-as-array/Blort.java
+++ b/dx/tests/111-use-null-as-array/Blort.java
@@ -105,4 +105,3 @@
arr[15] = (short) 16;
}
}
-
diff --git a/dexdump/OpCodeNames.h b/dx/tests/113-old-style-inner-class/Blort.java
similarity index 64%
copy from dexdump/OpCodeNames.h
copy to dx/tests/113-old-style-inner-class/Blort.java
index 1aec0d1..89b1ba0 100644
--- a/dexdump/OpCodeNames.h
+++ b/dx/tests/113-old-style-inner-class/Blort.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * Dalvik opcode names.
- */
-#ifndef _DEXDUMP_OPCODENAMES
-#define _DEXDUMP_OPCODENAMES
-#include "libdex/OpCode.h"
+public class Blort {
+ public static Runnable theRunnable = new Runnable() {
+ public void run() { }
+ };
-const char* getOpcodeName(OpCode op);
-
-#endif /*_DEXDUMP_OPCODENAMES*/
+ public Runnable create() {
+ return new Runnable() {
+ public void run() { }
+ };
+ }
+}
diff --git a/dx/tests/113-old-style-inner-class/expected.txt b/dx/tests/113-old-style-inner-class/expected.txt
new file mode 100644
index 0000000..d58d6db
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/expected.txt
@@ -0,0 +1,2 @@
+warning:
+warning:
diff --git a/dx/tests/113-old-style-inner-class/info.txt b/dx/tests/113-old-style-inner-class/info.txt
new file mode 100644
index 0000000..91b3aad
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/info.txt
@@ -0,0 +1,3 @@
+This is a smoke test of dex conversion, which makes sure that
+converstion of old-style anonymous inner classes (whose representation
+is information-lossy) causes a warning to be issued.
diff --git a/dx/tests/113-old-style-inner-class/run b/dx/tests/113-old-style-inner-class/run
new file mode 100644
index 0000000..c93661f
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/run
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# We compile for a 1.4 target to suppress the use of EnclosingMethod
+# attributes.
+${JAVAC} -source 1.4 -target 1.4 -d . Blort.java
+
+# We expect there to be two warning lines, one for each of the inner classes.
+dx --debug --dex *.class 2>&1 | awk '/^warning:/ { print $1 }'
diff --git a/dx/tests/run-all-tests b/dx/tests/run-all-tests
index 1ade761..68062c2 100755
--- a/dx/tests/run-all-tests
+++ b/dx/tests/run-all-tests
@@ -55,4 +55,3 @@
for i in $failNames; do
echo "failed: $i"
done
-
diff --git a/hit/src/com/android/hit/ArrayInstance.java b/hit/src/com/android/hit/ArrayInstance.java
index cdb5616..42e8803 100644
--- a/hit/src/com/android/hit/ArrayInstance.java
+++ b/hit/src/com/android/hit/ArrayInstance.java
@@ -24,8 +24,8 @@
private int mType;
private int mNumEntries;
private byte[] mData;
-
- public ArrayInstance(long id, StackTrace stack, int type, int numEntries,
+
+ public ArrayInstance(long id, StackTrace stack, int type, int numEntries,
byte[] data) {
mId = id;
mStack = stack;
@@ -38,17 +38,17 @@
if (mType != Types.OBJECT) {
return;
}
-
+
/*
* mData holds a stream of object instance ids
* Spin through them all and list ourselves as a reference holder.
*/
int idSize = Types.getTypeSize(mType);
final int N = mNumEntries;
-
+
ByteArrayInputStream bais = new ByteArrayInputStream(mData);
DataInputStream dis = new DataInputStream(bais);
-
+
for (int i = 0; i < N; i++) {
long id;
@@ -60,7 +60,7 @@
}
Instance instance = state.findReference(id);
-
+
if (instance != null) {
instance.addParent(this);
}
@@ -81,7 +81,7 @@
if (resultSet.contains(this)) {
return;
}
-
+
if (null != filter) {
if (filter.accept(this)) {
resultSet.add(this);
@@ -93,30 +93,30 @@
if (mType != Types.OBJECT) {
return;
}
-
+
/*
* mData holds a stream of object instance ids
* Spin through them all and visit them
*/
int idSize = Types.getTypeSize(mType);
final int N = mNumEntries;
-
+
ByteArrayInputStream bais = new ByteArrayInputStream(mData);
DataInputStream dis = new DataInputStream(bais);
State state = mHeap.mState;
-
+
for (int i = 0; i < N; i++) {
long id;
-
+
try {
if (idSize == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
Instance instance = state.findReference(id);
-
+
if (instance != null) {
instance.visit(resultSet, filter);
}
@@ -141,48 +141,48 @@
if (mType != Types.OBJECT) {
return super.describeReferenceTo(referent);
}
-
+
int idSize = Types.getTypeSize(mType);
final int N = mNumEntries;
int numRefs = 0;
StringBuilder result = new StringBuilder("Elements [");
ByteArrayInputStream bais = new ByteArrayInputStream(mData);
DataInputStream dis = new DataInputStream(bais);
-
+
/*
* Spin through all the objects and build up a string describing
* all of the array elements that refer to the target object.
*/
for (int i = 0; i < N; i++) {
long id;
-
+
try {
if (idSize == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
if (id == referent) {
numRefs++;
-
+
if (numRefs > 1) {
result.append(", ");
}
-
+
result.append(i);
}
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
-
+
if (numRefs == 0) {
return super.describeReferenceTo(referent);
}
result.append("]");
-
+
return result.toString();
}
}
diff --git a/hit/src/com/android/hit/ClassInstance.java b/hit/src/com/android/hit/ClassInstance.java
index 36525be..0869769 100644
--- a/hit/src/com/android/hit/ClassInstance.java
+++ b/hit/src/com/android/hit/ClassInstance.java
@@ -29,7 +29,7 @@
mStack = stack;
mClassId = classId;
}
-
+
public final void loadFieldData(DataInputStream in, int numBytes)
throws IOException {
mFieldValues = new byte[numBytes];
@@ -44,7 +44,7 @@
resolve(state, isa, isa.mFieldTypes, mFieldValues);
}
- private void resolve(State state, ClassObj isa, int[] types,
+ private void resolve(State state, ClassObj isa, int[] types,
byte[] values) {
ByteArrayInputStream bais = new ByteArrayInputStream(values);
DataInputStream dis = new DataInputStream(bais);
@@ -61,15 +61,15 @@
if (type == Types.OBJECT) {
long id;
-
+
if (size == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
Instance instance = state.findReference(id);
-
+
if (instance != null) {
instance.addParent(this);
}
@@ -85,7 +85,7 @@
@Override
public final int getSize() {
ClassObj isa = mHeap.mState.findClass(mClassId);
-
+
return isa.getSize();
}
@@ -94,7 +94,7 @@
if (resultSet.contains(this)) {
return;
}
-
+
if (filter != null) {
if (filter.accept(this)) {
resultSet.add(this);
@@ -109,7 +109,7 @@
ByteArrayInputStream bais = new ByteArrayInputStream(mFieldValues);
DataInputStream dis = new DataInputStream(bais);
final int N = types.length;
-
+
/*
* Spin through the list of fields, find all object references,
* and list ourselves as a reference holder.
@@ -118,18 +118,18 @@
for (int i = 0; i < N; i++) {
int type = types[i];
int size = Types.getTypeSize(type);
-
+
if (type == Types.OBJECT) {
long id;
-
+
if (size == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
Instance instance = state.findReference(id);
-
+
if (instance != null) {
instance.visit(resultSet, filter);
}
@@ -145,7 +145,7 @@
@Override
public final String getTypeName() {
ClassObj theClass = mHeap.mState.findClass(mClassId);
-
+
return theClass.mClassName;
}
@@ -163,7 +163,7 @@
final int N = types.length;
StringBuilder result = new StringBuilder("Referenced in field(s):");
int numReferences = 0;
-
+
/*
* Spin through the list of fields, add info about the field
* references to the output text.
@@ -172,16 +172,16 @@
for (int i = 0; i < N; i++) {
int type = types[i];
int size = Types.getTypeSize(type);
-
+
if (type == Types.OBJECT) {
long id;
-
+
if (size == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
if (id == referent) {
numReferences++;
result.append("\n ");
@@ -202,7 +202,7 @@
if (numReferences == 0) {
return super.describeReferenceTo(referent);
}
-
+
return result.toString();
}
}
diff --git a/hit/src/com/android/hit/ClassObj.java b/hit/src/com/android/hit/ClassObj.java
index 388af4a..1e3ac28 100644
--- a/hit/src/com/android/hit/ClassObj.java
+++ b/hit/src/com/android/hit/ClassObj.java
@@ -51,7 +51,7 @@
DataInputStream dis = new DataInputStream(bais);
int[] types = mStaticFieldTypes;
final int N = types.length;
-
+
/*
* Spin through the list of static fields, find all object references,
* and list ourselves as a reference holder. Also add them to
@@ -61,18 +61,18 @@
for (int i = 0; i < N; i++) {
int type = types[i];
int size = Types.getTypeSize(type);
-
+
if (type == Types.OBJECT) {
long id;
-
+
if (size == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
RootObj root = new RootObj(RootType.JAVA_STATIC, id);
-
+
if (id == 0) {
root.mComment = String.format(
"Static field %s:%s null",
@@ -80,9 +80,9 @@
mStaticFieldNames[i]);
} else {
Instance instance = state.findReference(id);
-
+
instance.addParent(this);
-
+
root.mComment = String.format(
"Static field %s:%s %s [%s] 0x%08x",
mClassName,
@@ -105,7 +105,7 @@
// Lastly, add ourself as a subclass of our superclass
if (mSuperclassId != 0) {
ClassObj superclass = state.findClass(mSuperclassId);
-
+
superclass.addSubclass(this);
}
}
@@ -135,7 +135,7 @@
public final void setFieldNames(String[] names) {
mFieldNames = names;
}
-
+
public final void setFieldTypes(int[] types) {
mFieldTypes = types;
}
@@ -143,11 +143,11 @@
public final void setStaticFieldNames(String[] names) {
mStaticFieldNames = names;
}
-
+
public final void setStaticFieldTypes(int[] types) {
mStaticFieldTypes = types;
}
-
+
public final void setStaticFieldValues(byte[] values) {
mStaticFieldValues = values;
}
@@ -156,14 +156,14 @@
System.out.println("+---------- ClassObj dump for: " + mClassName);
System.out.println("+----- Static fields");
-
+
for (int i = 0; i < mStaticFieldNames.length; i++) {
- System.out.println(mStaticFieldNames[i] + ": "
+ System.out.println(mStaticFieldNames[i] + ": "
+ mStaticFieldTypes[i]);
}
System.out.println("+----- Instance fields");
-
+
for (int i = 0; i < mFieldNames.length; i++) {
System.out.println(mFieldNames[i] + ": " + mFieldTypes[i]);
}
@@ -179,7 +179,7 @@
if (resultSet.contains(this)) {
return;
}
-
+
if (filter != null) {
if (filter.accept(this)) {
resultSet.add(this);
@@ -187,14 +187,14 @@
} else {
resultSet.add(this);
}
-
+
ByteArrayInputStream bais =
new ByteArrayInputStream(mStaticFieldValues);
DataInputStream dis = new DataInputStream(bais);
int[] types = mStaticFieldTypes;
final int N = types.length;
State state = mHeap.mState;
-
+
/*
* Spin through the list of static fields, find all object references,
* and visit them.
@@ -203,18 +203,18 @@
for (int i = 0; i < N; i++) {
int type = types[i];
int size = Types.getTypeSize(type);
-
+
if (type == Types.OBJECT) {
long id;
-
+
if (size == 4) {
id = dis.readInt();
} else {
id = dis.readLong();
}
-
+
Instance instance = state.findReference(id);
-
+
if (instance != null) {
instance.visit(resultSet, filter);
}
@@ -235,7 +235,7 @@
if (! (o instanceof ClassObj)) {
return false;
}
-
+
return 0 == compareTo((ClassObj) o);
}
}
diff --git a/hit/src/com/android/hit/Heap.java b/hit/src/com/android/hit/Heap.java
index 82dde8e..37b15dd 100644
--- a/hit/src/com/android/hit/Heap.java
+++ b/hit/src/com/android/hit/Heap.java
@@ -21,16 +21,16 @@
public class Heap {
String mName;
-
+
// List of individual stack frames
HashMap<Long, StackFrame> mFrames = new HashMap<Long, StackFrame>();
-
+
// List stack traces, which are lists of stack frames
HashMap<Integer, StackTrace> mTraces = new HashMap<Integer, StackTrace>();
-
+
// Root objects such as interned strings, jni locals, etc
ArrayList<RootObj> mRoots = new ArrayList<RootObj>();
-
+
// List of threads
HashMap<Integer, ThreadObj> mThreads = new HashMap<Integer, ThreadObj>();
@@ -47,7 +47,7 @@
public Heap(String name) {
mName = name;
}
-
+
public final void addStackFrame(StackFrame theFrame) {
mFrames.put(theFrame.mId, theFrame);
}
@@ -64,14 +64,14 @@
return mTraces.get(traceSerialNumber);
}
- public final StackTrace getStackTraceAtDepth(int traceSerialNumber,
+ public final StackTrace getStackTraceAtDepth(int traceSerialNumber,
int depth) {
StackTrace trace = mTraces.get(traceSerialNumber);
-
+
if (trace != null) {
trace = trace.fromDepth(depth);
}
-
+
return trace;
}
@@ -83,7 +83,7 @@
public final void addThread(ThreadObj thread, int serialNumber) {
mThreads.put(serialNumber, thread);
}
-
+
public final ThreadObj getThread(int serialNumber) {
return mThreads.get(serialNumber);
}
@@ -91,7 +91,7 @@
public final void addInstance(long id, Instance instance) {
mInstances.put(id, instance);
}
-
+
public final Instance getInstance(long id) {
return mInstances.get(id);
}
@@ -100,7 +100,7 @@
mClassesById.put(id, theClass);
mClassesByName.put(theClass.mClassName, theClass);
}
-
+
public final ClassObj getClass(long id) {
return mClassesById.get(id);
}
@@ -112,7 +112,7 @@
public final void dumpInstanceCounts() {
for (ClassObj theClass: mClassesById.values()) {
int count = theClass.mInstances.size();
-
+
if (count > 0) {
System.out.println(theClass + ": " + count);
}
@@ -122,18 +122,18 @@
public final void dumpSubclasses() {
for (ClassObj theClass: mClassesById.values()) {
int count = theClass.mSubclasses.size();
-
+
if (count > 0) {
System.out.println(theClass);
theClass.dumpSubclasses();
}
}
}
-
+
public final void dumpSizes() {
for (ClassObj theClass: mClassesById.values()) {
int size = 0;
-
+
for (Instance instance: theClass.mInstances) {
size += instance.getCompositeSize();
}
@@ -144,7 +144,7 @@
}
}
}
-
+
/*
* Spin through all of the class instances and link them to their
* parent class definition objects. Then have each instance resolve
@@ -161,11 +161,11 @@
String name = theClass.mClassName;
String superclassName = "none";
ClassObj superClass = mClassesById.get(theClass.mSuperclassId);
-
+
if (superClass != null) {
superclassName = superClass.mClassName;
}
-
+
theClass.addInstance(instance);
instance.resolveReferences(state);
}
diff --git a/hit/src/com/android/hit/HprofParser.java b/hit/src/com/android/hit/HprofParser.java
index 2226001..98fef1e 100644
--- a/hit/src/com/android/hit/HprofParser.java
+++ b/hit/src/com/android/hit/HprofParser.java
@@ -53,7 +53,7 @@
private static final int ROOT_INSTANCE_DUMP = 0x21;
private static final int ROOT_OBJECT_ARRAY_DUMP = 0x22;
private static final int ROOT_PRIMITIVE_ARRAY_DUMP = 0x23;
-
+
/**
* Android format addition
*
@@ -63,7 +63,7 @@
* associated with the specified heap. The HEAP_DUMP_INFO data is reset
* at the end of the HEAP_DUMP[_SEGMENT]. Multiple HEAP_DUMP_INFO entries
* may appear in a single HEAP_DUMP[_SEGMENT].
- *
+ *
* Format:
* u1: Tag value (0xFE)
* u4: heap ID
@@ -103,12 +103,12 @@
try {
String s = readNullTerminatedString();
DataInputStream in = mInput;
-
+
mIdSize = in.readInt();
Types.setIdSize(mIdSize);
-
+
in.readLong(); // Timestamp, ignored for now
-
+
while (true) {
int tag = in.readUnsignedByte();
int timestamp = in.readInt();
@@ -118,7 +118,7 @@
case STRING_IN_UTF8:
loadString(length - 4);
break;
-
+
case LOAD_CLASS:
loadClass();
break;
@@ -135,7 +135,7 @@
loadHeapDump(length);
mState.setToDefaultHeap();
break;
-
+
case HEAP_DUMP_SEGMENT:
loadHeapDump(length);
mState.setToDefaultHeap();
@@ -153,7 +153,7 @@
}
mState.resolveReferences();
-
+
return state;
}
@@ -164,7 +164,7 @@
for (int c = in.read(); c != 0; c = in.read()) {
s.append((char) c);
}
-
+
return s.toString();
}
@@ -175,13 +175,13 @@
case 4: return ((long) mInput.readInt()) & 0x00000000ffffffffL;
case 8: return mInput.readLong();
}
-
+
throw new IllegalArgumentException("ID Length must be 1, 2, 4, or 8");
}
private String readUTF8(int length) throws IOException {
byte[] b = new byte[length];
-
+
mInput.read(b);
return new String(b, "utf-8");
@@ -190,7 +190,7 @@
private void loadString(int length) throws IOException {
long id = readId();
String string = readUTF8(length);
-
+
mStrings.put(id, string);
}
@@ -200,7 +200,7 @@
long id = readId();
int stackTrace = in.readInt(); // unused
String name = mStrings.get(readId());
-
+
mClassNames.put(id, name);
}
@@ -211,8 +211,8 @@
String sourceFile = mStrings.get(readId());
int serial = mInput.readInt();
int lineNumber = mInput.readInt();
-
- StackFrame frame = new StackFrame(id, methodName, methodSignature,
+
+ StackFrame frame = new StackFrame(id, methodName, methodSignature,
sourceFile, serial, lineNumber);
mState.addStackFrame(frame);
@@ -223,12 +223,12 @@
int threadSerialNumber = mInput.readInt();
final int numFrames = mInput.readInt();
StackFrame[] frames = new StackFrame[numFrames];
-
+
for (int i = 0; i < numFrames; i++) {
frames[i] = mState.getStackFrame(readId());
}
-
- StackTrace trace = new StackTrace(serialNumber, threadSerialNumber,
+
+ StackTrace trace = new StackTrace(serialNumber, threadSerialNumber,
frames);
mState.addStackTrace(trace);
@@ -236,62 +236,62 @@
private void loadHeapDump(int length) throws IOException {
DataInputStream in = mInput;
-
+
while (length > 0) {
int tag = in.readUnsignedByte();
length--;
-
+
switch (tag) {
case ROOT_UNKNOWN:
length -= loadBasicObj(RootType.UNKNOWN);
break;
-
+
case ROOT_JNI_GLOBAL:
length -= loadBasicObj(RootType.NATIVE_STATIC);
readId(); // ignored
length -= mIdSize;
break;
-
+
case ROOT_JNI_LOCAL:
length -= loadJniLocal();
break;
-
+
case ROOT_JAVA_FRAME:
length -= loadJavaFrame();
break;
-
+
case ROOT_NATIVE_STACK:
length -= loadNativeStack();
break;
-
+
case ROOT_STICKY_CLASS:
length -= loadBasicObj(RootType.SYSTEM_CLASS);
break;
-
+
case ROOT_THREAD_BLOCK:
length -= loadThreadBlock();
break;
-
+
case ROOT_MONITOR_USED:
length -= loadBasicObj(RootType.BUSY_MONITOR);
break;
-
+
case ROOT_THREAD_OBJECT:
length -= loadThreadObject();
break;
-
+
case ROOT_CLASS_DUMP:
length -= loadClassDump();
break;
-
+
case ROOT_INSTANCE_DUMP:
length -= loadInstanceDump();
break;
-
+
case ROOT_OBJECT_ARRAY_DUMP:
length -= loadObjectArrayDump();
break;
-
+
case ROOT_PRIMITIVE_ARRAY_DUMP:
length -= loadPrimitiveArrayDump();
break;
@@ -302,66 +302,66 @@
throw new IllegalArgumentException(
"Don't know how to load a nodata array");
-
+
case ROOT_HEAP_DUMP_INFO:
int heapId = mInput.readInt();
long heapNameId = readId();
String heapName = mStrings.get(heapNameId);
-
+
mState.setHeapTo(heapId, heapName);
length -= 4 + mIdSize;
break;
-
+
case ROOT_INTERNED_STRING:
length -= loadBasicObj(RootType.INTERNED_STRING);
break;
-
+
case ROOT_FINALIZING:
length -= loadBasicObj(RootType.FINALIZING);
break;
-
+
case ROOT_DEBUGGER:
length -= loadBasicObj(RootType.DEBUGGER);
break;
-
+
case ROOT_REFERENCE_CLEANUP:
length -= loadBasicObj(RootType.REFERENCE_CLEANUP);
break;
-
+
case ROOT_VM_INTERNAL:
length -= loadBasicObj(RootType.VM_INTERNAL);
break;
-
+
case ROOT_JNI_MONITOR:
length -= loadJniMonitor();
break;
-
+
case ROOT_UNREACHABLE:
length -= loadBasicObj(RootType.UNREACHABLE);
break;
-
+
default:
throw new IllegalArgumentException(
- "loadHeapDump loop with unknown tag " + tag
- + " with " + mInput.available()
+ "loadHeapDump loop with unknown tag " + tag
+ + " with " + mInput.available()
+ " bytes possibly remaining");
}
}
}
-
+
private int loadJniLocal() throws IOException {
long id = readId();
int threadSerialNumber = mInput.readInt();
int stackFrameNumber = mInput.readInt();
ThreadObj thread = mState.getThread(threadSerialNumber);
- StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
+ StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
stackFrameNumber);
- RootObj root = new RootObj(RootType.NATIVE_LOCAL, id,
+ RootObj root = new RootObj(RootType.NATIVE_LOCAL, id,
threadSerialNumber, trace);
-
+
root.setHeap(mState.mCurrentHeap);
mState.addRoot(root);
-
+
return mIdSize + 4 + 4;
}
@@ -370,38 +370,38 @@
int threadSerialNumber = mInput.readInt();
int stackFrameNumber = mInput.readInt();
ThreadObj thread = mState.getThread(threadSerialNumber);
- StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
+ StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
stackFrameNumber);
- RootObj root = new RootObj(RootType.JAVA_LOCAL, id, threadSerialNumber,
+ RootObj root = new RootObj(RootType.JAVA_LOCAL, id, threadSerialNumber,
trace);
-
+
root.setHeap(mState.mCurrentHeap);
mState.addRoot(root);
-
+
return mIdSize + 4 + 4;
}
-
+
private int loadNativeStack() throws IOException {
long id = readId();
int threadSerialNumber = mInput.readInt();
ThreadObj thread = mState.getThread(threadSerialNumber);
StackTrace trace = mState.getStackTrace(thread.mStackTrace);
- RootObj root = new RootObj(RootType.NATIVE_STACK, id,
+ RootObj root = new RootObj(RootType.NATIVE_STACK, id,
threadSerialNumber, trace);
-
+
root.setHeap(mState.mCurrentHeap);
mState.addRoot(root);
-
+
return mIdSize + 4;
}
private int loadBasicObj(RootType type) throws IOException {
long id = readId();
RootObj root = new RootObj(type, id);
-
+
root.setHeap(mState.mCurrentHeap);
mState.addRoot(root);
-
+
return mIdSize;
}
@@ -410,12 +410,12 @@
int threadSerialNumber = mInput.readInt();
ThreadObj thread = mState.getThread(threadSerialNumber);
StackTrace stack = mState.getStackTrace(thread.mStackTrace);
- RootObj root = new RootObj(RootType.THREAD_BLOCK, id,
+ RootObj root = new RootObj(RootType.THREAD_BLOCK, id,
threadSerialNumber, stack);
-
+
root.setHeap(mState.mCurrentHeap);
mState.addRoot(root);
-
+
return mIdSize + 4;
}
@@ -424,9 +424,9 @@
int threadSerialNumber = mInput.readInt();
int stackSerialNumber = mInput.readInt();
ThreadObj thread = new ThreadObj(id, stackSerialNumber);
-
+
mState.addThread(thread, threadSerialNumber);
-
+
return mIdSize + 4 + 4;
}
@@ -449,7 +449,7 @@
// Skip over the constant pool
int numEntries = in.readUnsignedShort();
bytesRead += 2;
-
+
for (int i = 0; i < numEntries; i++) {
in.readUnsignedShort();
bytesRead += 2 + skipValue();
@@ -463,7 +463,7 @@
int[] staticFieldTypes = new int[numEntries];
ByteArrayOutputStream staticFieldValues = new ByteArrayOutputStream();
byte[] buffer = mFieldBuffer;
-
+
for (int i = 0; i < numEntries; i++) {
staticFieldNames[i] = mStrings.get(readId());
@@ -476,14 +476,14 @@
bytesRead += mIdSize + 1 + fieldSize;
}
-
+
// Instance fields
numEntries = in.readUnsignedShort();
bytesRead += 2;
-
+
String[] names = new String[numEntries];
int[] types = new int[numEntries];
-
+
for (int i = 0; i < numEntries; i++) {
long fieldName = readId();
int type = in.readUnsignedByte();
@@ -493,7 +493,7 @@
bytesRead += mIdSize + 1;
}
-
+
ClassObj theClass = new ClassObj(id, stack, mClassNames.get(id));
theClass.setStaticFieldNames(staticFieldNames);
@@ -504,11 +504,11 @@
theClass.setFieldNames(names);
theClass.setFieldTypes(types);
theClass.setSize(instanceSize);
-
+
theClass.setHeap(mState.mCurrentHeap);
mState.addClass(id, theClass);
-
+
return bytesRead;
}
@@ -523,7 +523,7 @@
instance.loadFieldData(mInput, remaining);
instance.setHeap(mState.mCurrentHeap);
mState.addInstance(id, instance);
-
+
return mIdSize + 4 + mIdSize + 4 + remaining;
}
@@ -536,19 +536,19 @@
int totalBytes = numElements * mIdSize;
byte[] data = new byte[totalBytes];
String className = mClassNames.get(classId);
-
+
mInput.readFully(data);
- ArrayInstance array = new ArrayInstance(id, stack, Types.OBJECT,
+ ArrayInstance array = new ArrayInstance(id, stack, Types.OBJECT,
numElements, data);
-
+
array.mClassId = classId;
array.setHeap(mState.mCurrentHeap);
mState.addInstance(id, array);
return mIdSize + 4 + 4 + mIdSize + totalBytes;
}
-
+
private int loadPrimitiveArrayDump() throws IOException {
long id = readId();
int stackId = mInput.readInt();
@@ -558,15 +558,15 @@
int size = Types.getTypeSize(type);
int totalBytes = numElements * size;
byte[] data = new byte[totalBytes];
-
+
mInput.readFully(data);
- ArrayInstance array = new ArrayInstance(id, stack, type, numElements,
+ ArrayInstance array = new ArrayInstance(id, stack, type, numElements,
data);
-
+
array.setHeap(mState.mCurrentHeap);
mState.addInstance(id, array);
-
+
return mIdSize + 4 + 4 + 1 + totalBytes;
}
@@ -575,21 +575,21 @@
int threadSerialNumber = mInput.readInt();
int stackDepth = mInput.readInt();
ThreadObj thread = mState.getThread(threadSerialNumber);
- StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
+ StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
stackDepth);
- RootObj root = new RootObj(RootType.NATIVE_MONITOR, id,
+ RootObj root = new RootObj(RootType.NATIVE_MONITOR, id,
threadSerialNumber, trace);
-
+
root.setHeap(mState.mCurrentHeap);
mState.addRoot(root);
-
+
return mIdSize + 4 + 4;
}
private int skipValue() throws IOException {
int type = mInput.readUnsignedByte();
int size = Types.getTypeSize(type);
-
+
skipFully(size);
return size + 1;
@@ -604,7 +604,7 @@
private void skipFully(long numBytes) throws IOException {
while (numBytes > 0) {
long skipped = mInput.skip(numBytes);
-
+
numBytes -= skipped;
}
}
diff --git a/hit/src/com/android/hit/Instance.java b/hit/src/com/android/hit/Instance.java
index 24db38d..6afa2b2 100644
--- a/hit/src/com/android/hit/Instance.java
+++ b/hit/src/com/android/hit/Instance.java
@@ -25,10 +25,10 @@
// Id of the ClassObj of which this object is an instance
long mClassId;
-
+
// The stack in which this object was allocated
StackTrace mStack;
-
+
// The heap in which this object was allocated (app, zygote, etc)
Heap mHeap;
@@ -41,7 +41,7 @@
// List of all objects that hold a live reference to this object
private ArrayList<Instance> mParents;
-
+
/*
* After the whole HPROF file is read and parsed this method will be
* called on all heap objects so that they can resolve their internal
@@ -67,15 +67,15 @@
public final int getCompositeSize() {
HashSet<Instance> set = new HashSet<Instance>();
-
+
visit(set, null);
-
+
int size = 0;
-
+
for (Instance instance: set) {
size += instance.getSize();
}
-
+
return size;
}
@@ -89,21 +89,21 @@
public void setHeap(Heap heap) {
mHeap = heap;
}
-
+
// Add to the list of objects that have a hard reference to this Instance
public void addParent(Instance parent) {
if (mParents == null) {
mParents = new ArrayList<Instance>();
}
-
+
mParents.add(parent);
}
-
+
public ArrayList<Instance> getParents() {
if (mParents == null) {
mParents = new ArrayList<Instance>();
}
-
+
return mParents;
}
@@ -112,6 +112,6 @@
* a String describing the reference in detail.
*/
public String describeReferenceTo(long id) {
- return "No reference to 0x" + Long.toHexString(id);
+ return "No reference to 0x" + Long.toHexString(id);
}
}
diff --git a/hit/src/com/android/hit/Main.java b/hit/src/com/android/hit/Main.java
index eebadfe..4ed5c11 100644
--- a/hit/src/com/android/hit/Main.java
+++ b/hit/src/com/android/hit/Main.java
@@ -28,16 +28,16 @@
FileInputStream fis;
BufferedInputStream bis;
DataInputStream dis;
-
+
try {
fis = new FileInputStream(argv[0]);
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
-
+
State state = (new HprofParser(dis)).parse();
dis.close();
-
+
testClassesQuery(state);
testAllClassesQuery(state);
testFindInstancesOf(state);
@@ -53,28 +53,28 @@
"javax.",
"org.xml.sax"
};
-
+
Map<String, Set<ClassObj>> someClasses = Queries.classes(state, x);
-
+
for (String thePackage: someClasses.keySet()) {
System.out.println("------------------- " + thePackage);
-
+
Set<ClassObj> classes = someClasses.get(thePackage);
-
+
for (ClassObj theClass: classes) {
System.out.println(" " + theClass.mClassName);
}
}
}
-
+
private static void testAllClassesQuery(State state) {
Map<String, Set<ClassObj>> allClasses = Queries.allClasses(state);
-
+
for (String thePackage: allClasses.keySet()) {
System.out.println("------------------- " + thePackage);
-
+
Set<ClassObj> classes = allClasses.get(thePackage);
-
+
for (ClassObj theClass: classes) {
System.out.println(" " + theClass.mClassName);
}
@@ -83,14 +83,14 @@
private static void testFindInstancesOf(State state) {
Instance[] instances = Queries.instancesOf(state, "java.lang.String");
-
+
System.out.println("There are " + instances.length + " Strings.");
}
private static void testFindAllInstancesOf(State state) {
- Instance[] instances = Queries.allInstancesOf(state,
+ Instance[] instances = Queries.allInstancesOf(state,
"android.graphics.drawable.Drawable");
-
+
System.out.println("There are " + instances.length
+ " instances of Drawables and its subclasses.");
}
diff --git a/hit/src/com/android/hit/Queries.java b/hit/src/com/android/hit/Queries.java
index cc692b0..0dac796 100644
--- a/hit/src/com/android/hit/Queries.java
+++ b/hit/src/com/android/hit/Queries.java
@@ -27,7 +27,7 @@
public class Queries {
/*
- * NOTES: Here's a list of the queries that can be done in hat and
+ * NOTES: Here's a list of the queries that can be done in hat and
* how you'd perform a similar query here in hit:
*
* hat hit
@@ -67,7 +67,7 @@
return classes(state, null);
}
- public static Map<String, Set<ClassObj>> classes(State state,
+ public static Map<String, Set<ClassObj>> classes(State state,
String[] excludedPrefixes) {
TreeMap<String, Set<ClassObj>> result =
new TreeMap<String, Set<ClassObj>>();
@@ -78,16 +78,16 @@
for (Heap heap: state.mHeaps.values()) {
classes.addAll(heap.mClassesById.values());
}
-
+
// Filter it if needed
if (excludedPrefixes != null) {
final int N = excludedPrefixes.length;
Iterator<ClassObj> iter = classes.iterator();
-
+
while (iter.hasNext()) {
ClassObj theClass = iter.next();
String classPath = theClass.toString();
-
+
for (int i = 0; i < N; i++) {
if (classPath.startsWith(excludedPrefixes[i])) {
iter.remove();
@@ -96,29 +96,29 @@
}
}
}
-
+
// Now that we have a final list of classes, group them by package
for (ClassObj theClass: classes) {
String packageName = DEFAULT_PACKAGE;
int lastDot = theClass.mClassName.lastIndexOf('.');
-
+
if (lastDot != -1) {
packageName = theClass.mClassName.substring(0, lastDot);
}
-
+
Set<ClassObj> classSet = result.get(packageName);
-
+
if (classSet == null) {
classSet = new TreeSet<ClassObj>();
result.put(packageName, classSet);
}
-
+
classSet.add(theClass);
}
-
+
return result;
}
-
+
/*
* It's sorta sad that this is a pass-through call, but it seems like
* having all of the hat-like query methods in one place is a good thing
@@ -134,14 +134,14 @@
*/
public static Instance[] instancesOf(State state, String baseClassName) {
ClassObj theClass = state.findClass(baseClassName);
-
+
if (theClass == null) {
throw new IllegalArgumentException("Class not found: "
+ baseClassName);
}
-
+
Instance[] instances = new Instance[theClass.mInstances.size()];
-
+
return theClass.mInstances.toArray(instances);
}
@@ -151,38 +151,38 @@
*/
public static Instance[] allInstancesOf(State state, String baseClassName) {
ClassObj theClass = state.findClass(baseClassName);
-
+
if (theClass == null) {
throw new IllegalArgumentException("Class not found: "
+ baseClassName);
}
ArrayList<ClassObj> classList = new ArrayList<ClassObj>();
-
+
classList.add(theClass);
classList.addAll(traverseSubclasses(theClass));
-
+
ArrayList<Instance> instanceList = new ArrayList<Instance>();
-
+
for (ClassObj someClass: classList) {
instanceList.addAll(someClass.mInstances);
}
-
+
Instance[] result = new Instance[instanceList.size()];
-
+
instanceList.toArray(result);
-
+
return result;
}
-
+
private static ArrayList<ClassObj> traverseSubclasses(ClassObj base) {
ArrayList<ClassObj> result = new ArrayList<ClassObj>();
-
+
for (ClassObj subclass: base.mSubclasses) {
result.add(subclass);
result.addAll(traverseSubclasses(subclass));
}
-
+
return result;
}
@@ -192,33 +192,33 @@
*/
public static Instance findObject(State state, String id) {
long id2 = Long.parseLong(id, 16);
-
+
return state.findReference(id2);
}
public static Collection<RootObj> getRoots(State state) {
HashSet<RootObj> result = new HashSet<RootObj>();
-
+
for (Heap heap: state.mHeaps.values()) {
result.addAll(heap.mRoots);
}
-
+
return result;
}
public static final Instance[] newInstances(State older, State newer) {
ArrayList<Instance> resultList = new ArrayList<Instance>();
-
+
for (Heap newHeap: newer.mHeaps.values()) {
Heap oldHeap = older.getHeap(newHeap.mName);
-
+
if (oldHeap == null) {
continue;
}
-
+
for (Instance instance: newHeap.mInstances.values()) {
Instance oldInstance = oldHeap.getInstance(instance.mId);
-
+
/*
* If this instance wasn't in the old heap, or was there,
* but that ID was for an obj of a different type, then we have
@@ -231,9 +231,9 @@
}
}
}
-
+
Instance[] resultArray = new Instance[resultList.size()];
-
+
return resultList.toArray(resultArray);
}
}
diff --git a/hit/src/com/android/hit/RootObj.java b/hit/src/com/android/hit/RootObj.java
index 1f9d539..a9acd35 100644
--- a/hit/src/com/android/hit/RootObj.java
+++ b/hit/src/com/android/hit/RootObj.java
@@ -37,7 +37,7 @@
public RootObj(RootType type, long id) {
this(type, id, 0, null);
}
-
+
public RootObj(RootType type, long id, int thread, StackTrace stack) {
mType = type;
mId = id;
@@ -47,7 +47,7 @@
public final String getClassName(State state) {
ClassObj theClass;
-
+
if (mType == RootType.SYSTEM_CLASS) {
theClass = state.findClass(mId);
} else {
@@ -59,24 +59,24 @@
if (theClass == null) {
return "no class defined!!";
}
-
+
return theClass.mClassName;
}
@Override
public final int getSize() {
Instance instance = null;
-
+
if (mType == RootType.SYSTEM_CLASS) {
instance = mHeap.mState.findClass(mId);
} else {
instance = mHeap.mState.findReference(mId);
}
-
+
if (instance == null) {
return 0;
}
-
+
return instance.getSize();
}
@@ -85,7 +85,7 @@
if (resultSet.contains(this)) {
return;
}
-
+
if (filter != null) {
if (filter.accept(this)) {
resultSet.add(this);
diff --git a/hit/src/com/android/hit/RootType.java b/hit/src/com/android/hit/RootType.java
index 01ebeff..209ed1b 100644
--- a/hit/src/com/android/hit/RootType.java
+++ b/hit/src/com/android/hit/RootType.java
@@ -34,19 +34,19 @@
JAVA_LOCAL (14, "java local"),
NATIVE_STACK (15, "native stack"),
JAVA_STATIC (16, "java static");
-
+
private final int mType;
private final String mName;
-
+
RootType(int type, String name) {
mType = type;
mName = name;
}
-
+
public final int getType() {
return mType;
}
-
+
public final String getName() {
return mName;
}
diff --git a/hit/src/com/android/hit/StackFrame.java b/hit/src/com/android/hit/StackFrame.java
index a40f607..2ae7f32 100644
--- a/hit/src/com/android/hit/StackFrame.java
+++ b/hit/src/com/android/hit/StackFrame.java
@@ -21,7 +21,7 @@
public static final int UNKNOWN_LOCATION = -1;
public static final int COMPILED_METHOD = -2;
public static final int NATIVE_METHOD = -3;
-
+
long mId;
String mMethodName;
String mSignature;
@@ -29,7 +29,7 @@
int mSerialNumber;
int mLineNumber;
- public StackFrame(long id, String method, String sig, String file,
+ public StackFrame(long id, String method, String sig, String file,
int serial, int line) {
mId = id;
mMethodName = method;
@@ -45,16 +45,16 @@
case UNKNOWN_LOCATION: return "Unknown line number";
case COMPILED_METHOD: return "Compiled method";
case NATIVE_METHOD: return "Native method";
-
+
default: return String.valueOf(mLineNumber);
}
}
public final String toString() {
- return mMethodName
- + mSignature.replace('/', '.')
- + " - "
- + mFilename + ":"
+ return mMethodName
+ + mSignature.replace('/', '.')
+ + " - "
+ + mFilename + ":"
+ lineNumberString();
}
}
diff --git a/hit/src/com/android/hit/StackTrace.java b/hit/src/com/android/hit/StackTrace.java
index 239a7b8..53cb86d 100644
--- a/hit/src/com/android/hit/StackTrace.java
+++ b/hit/src/com/android/hit/StackTrace.java
@@ -31,9 +31,9 @@
int mOffset = 0;
private StackTrace() {
-
+
}
-
+
public StackTrace(int serial, int thread, StackFrame[] frames) {
mSerialNumber = serial;
mThreadSerialNumber = thread;
@@ -42,21 +42,21 @@
public final StackTrace fromDepth(int startingDepth) {
StackTrace result = new StackTrace();
-
+
if (mParent != null) {
result.mParent = mParent;
} else {
result.mParent = this;
}
-
+
result.mOffset = startingDepth + mOffset;
-
+
return result;
}
-
+
public final void dump() {
final int N = mFrames.length;
-
+
for (int i = 0; i < N; i++) {
System.out.println(mFrames[i].toString());
}
diff --git a/hit/src/com/android/hit/State.java b/hit/src/com/android/hit/State.java
index 9b2060d..96c944d 100644
--- a/hit/src/com/android/hit/State.java
+++ b/hit/src/com/android/hit/State.java
@@ -41,13 +41,13 @@
public Heap setHeapTo(int id, String name) {
Heap heap = mHeaps.get(id);
-
+
if (heap == null) {
heap = new Heap(name);
heap.mState = this;
mHeaps.put(id, heap);
}
-
+
mCurrentHeap = heap;
return mCurrentHeap;
@@ -56,54 +56,54 @@
public Heap getHeap(int id) {
return mHeaps.get(id);
}
-
+
public Heap getHeap(String name) {
for (Heap heap: mHeaps.values()) {
if (heap.mName.equals(name)) {
return heap;
}
}
-
+
return null;
}
public final void addStackFrame(StackFrame theFrame) {
mCurrentHeap.addStackFrame(theFrame);
}
-
+
public final StackFrame getStackFrame(long id) {
return mCurrentHeap.getStackFrame(id);
}
-
+
public final void addStackTrace(StackTrace theTrace) {
mCurrentHeap.addStackTrace(theTrace);
}
-
+
public final StackTrace getStackTrace(int traceSerialNumber) {
return mCurrentHeap.getStackTrace(traceSerialNumber);
}
-
- public final StackTrace getStackTraceAtDepth(int traceSerialNumber,
+
+ public final StackTrace getStackTraceAtDepth(int traceSerialNumber,
int depth) {
return mCurrentHeap.getStackTraceAtDepth(traceSerialNumber, depth);
}
-
+
public final void addRoot(RootObj root) {
mCurrentHeap.addRoot(root);
}
-
+
public final void addThread(ThreadObj thread, int serialNumber) {
mCurrentHeap.addThread(thread, serialNumber);
}
-
+
public final ThreadObj getThread(int serialNumber) {
return mCurrentHeap.getThread(serialNumber);
}
-
+
public final void addInstance(long id, Instance instance) {
mCurrentHeap.addInstance(id, instance);
}
-
+
public final void addClass(long id, ClassObj theClass) {
mCurrentHeap.addClass(id, theClass);
}
@@ -111,40 +111,40 @@
public final Instance findReference(long id) {
for (Heap heap: mHeaps.values()) {
Instance instance = heap.getInstance(id);
-
+
if (instance != null) {
return instance;
}
}
-
+
// Couldn't find an instance of a class, look for a class object
return findClass(id);
}
-
+
public final ClassObj findClass(long id) {
for (Heap heap: mHeaps.values()) {
ClassObj theClass = heap.getClass(id);
-
+
if (theClass != null) {
return theClass;
}
}
-
+
return null;
}
-
+
public final ClassObj findClass(String name) {
for (Heap heap: mHeaps.values()) {
ClassObj theClass = heap.getClass(name);
-
+
if (theClass != null) {
return theClass;
}
}
-
+
return null;
}
-
+
public final void dumpInstanceCounts() {
for (Heap heap: mHeaps.values()) {
System.out.println(
@@ -152,7 +152,7 @@
heap.dumpInstanceCounts();
}
}
-
+
public final void dumpSizes() {
for (Heap heap: mHeaps.values()) {
System.out.println(
@@ -168,7 +168,7 @@
heap.dumpSubclasses();
}
}
-
+
public final void resolveReferences() {
for (Heap heap: mHeaps.values()) {
heap.resolveInstanceRefs(this);
diff --git a/hit/src/com/android/hit/Types.java b/hit/src/com/android/hit/Types.java
index ef316a9..62228ce 100644
--- a/hit/src/com/android/hit/Types.java
+++ b/hit/src/com/android/hit/Types.java
@@ -45,7 +45,7 @@
case 'S': return 2; // short
case 'I': return 4; // int
case 'J': return 8; // long
-
+
case OBJECT: return mIdSize;
case BOOLEAN: return 1;
case CHAR: return 2;
@@ -56,10 +56,10 @@
case INT: return 4;
case LONG: return 8;
}
-
+
throw new IllegalArgumentException("Illegal type signature: " + type);
}
-
+
public static final String getTypeName(int type) {
switch (type) {
case '[': return "array";
@@ -72,7 +72,7 @@
case 'S': return "short";
case 'I': return "int";
case 'J': return "long";
-
+
case OBJECT: return "object";
case BOOLEAN: return "boolean";
case CHAR: return "char";
@@ -83,7 +83,7 @@
case INT: return "int";
case LONG: return "long";
}
-
+
throw new IllegalArgumentException("Illegal type signature: " + type);
}
}
diff --git a/libcore-disabled/NOTICE b/libcore-disabled/NOTICE
deleted file mode 100644
index a0a06da..0000000
--- a/libcore-disabled/NOTICE
+++ /dev/null
@@ -1,16 +0,0 @@
- =========================================================================
- == NOTICE file corresponding to the section 4 d of ==
- == the Apache License, Version 2.0, ==
- == in this case for the Apache Harmony distribution. ==
- =========================================================================
-
-Apache Harmony
-Copyright 2006 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-Portions of Harmony were originally developed by
-Intel Corporation and are licensed to the Apache Software
-Foundation under the "Software Grant and Corporate Contribution
-License Agreement", informally known as the "Intel Harmony CLA".
diff --git a/libcore-disabled/SoundTest/Android.mk b/libcore-disabled/SoundTest/Android.mk
deleted file mode 100644
index bd628a5..0000000
--- a/libcore-disabled/SoundTest/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_JAVA_LIBRARIES := framework core
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-#define all-core-resource-dirs
-#$(shell cd $(LOCAL_PATH) && find resources)
-#endef
-
-#LOCAL_JAVA_RESOURCE_DIRS := $(call all-core-resource-dirs)
-
-LOCAL_PACKAGE_NAME := SoundTest
-
-include $(BUILD_PACKAGE)
diff --git a/libcore-disabled/SoundTest/AndroidManifest.xml b/libcore-disabled/SoundTest/AndroidManifest.xml
deleted file mode 100644
index 6c8d257..0000000
--- a/libcore-disabled/SoundTest/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tests.soundtest">
- - <application>
- <!-- icon="@drawable/logo" -->
- <activity android:name="SoundTest" android:label="SoundTest">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/libcore-disabled/SoundTest/assets/fx_foghorn.mp3 b/libcore-disabled/SoundTest/assets/fx_foghorn.mp3
deleted file mode 100644
index 71226cf..0000000
--- a/libcore-disabled/SoundTest/assets/fx_foghorn.mp3
+++ /dev/null
Binary files differ
diff --git a/libcore-disabled/SoundTest/res/layout/riproaring_activity.xml b/libcore-disabled/SoundTest/res/layout/riproaring_activity.xml
deleted file mode 100644
index a21599e..0000000
--- a/libcore-disabled/SoundTest/res/layout/riproaring_activity.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content">
- <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" />
-
- <TextView android:id="@+id/label" android:textStyle="bold" android:textColor="#00000000" android:textSize="16sp"
- android:layout_weight="1"
- android:text="@string/textview_text" />
-
- <EditText android:id="@+id/entry"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@android:drawable/editbox_background"
- android:text="@string/edittext_text"
- android:layout_below="@id/label"/>
-
- <Button android:id="@+id/ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/entry"
- android:layout_alignParentRight="true"
- android:text="@string/button_text" />
-
-</LinearLayout>
diff --git a/libcore-disabled/SoundTest/res/values/strings.xml b/libcore-disabled/SoundTest/res/values/strings.xml
deleted file mode 100644
index 6ad4891..0000000
--- a/libcore-disabled/SoundTest/res/values/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2007 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<resources>
-
- <string name="textview_text">I am a TextView</string>
- <string name="edittext_text">I am an EditText</string>
- <string name="button_text">I am a Button</string>
-
-</resources>
diff --git a/libcore-disabled/SoundTest/src/com/android/tests/soundtest/SoundTest.java b/libcore-disabled/SoundTest/src/com/android/tests/soundtest/SoundTest.java
deleted file mode 100644
index 3be10a0..0000000
--- a/libcore-disabled/SoundTest/src/com/android/tests/soundtest/SoundTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tests.soundtest;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.HandlerInterface;
-import android.os.Message;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.Button;
-import android.widget.LinearLayout;
-
-import java.io.InputStream;
-
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.Sequencer;
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.DataLine;
-import javax.sound.sampled.SourceDataLine;
-
-
-public class SoundTest extends Activity implements HandlerInterface {
-
- public Context mContext;
- private LinearLayout mLinearLayout;
- public LayoutParams mParams;
- Button button, button2;
-
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- Window wp = getWindow();
- mContext = wp.getContext();
- mParams = wp.getAttributes();
-
- mLinearLayout = new LinearLayout(this);
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- setContentView(mLinearLayout);
-
- button = new Button(mContext);
- button.setMinimumWidth(300);
- button.setMinimumHeight(70);
- button.setTextSize(14);
- button.setText("Play sample");
- button.setOnClickListener(buttonListener);
-
- mLinearLayout.addView(button, new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
-
- button2 = new Button(mContext);
- button2.setMinimumWidth(300);
- button2.setMinimumHeight(70);
- button2.setTextSize(14);
- button2.setText("Play MIDI");
- button2.setOnClickListener(buttonListener2);
-
- mLinearLayout.addView(button2, new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
-
- }
-
- private OnClickListener buttonListener = new OnClickListener() {
- public void onClick(View v) {
- try {
- button.setText(button.getText() + ".");
-
- int RENDER_BUFF_SIZE = 1024*48;
-
- InputStream is = getAssets().open("fx_foghorn.mp3");
-
- AudioInputStream ais = null;
-
- ais = AudioSystem.getAudioInputStream(is);
-
- AudioFormat af = ais.getFormat();
- SourceDataLine sdl = null;
- DataLine.Info dli = new DataLine.Info(SourceDataLine.class, af);
- sdl = (SourceDataLine)AudioSystem.getLine(dli);
-
- sdl.open(af);
- sdl.start();
-
- int bytesReaded = 0;
- byte samplesBuff[] = new byte[RENDER_BUFF_SIZE];
-
- while (bytesReaded != -1) {
- bytesReaded = ais.read(samplesBuff, 0, samplesBuff.length);
- if (bytesReaded > 0) {
- sdl.write(samplesBuff, 0, bytesReaded);
- }
- }
-
- sdl.drain();
- sdl.close();
- } catch (Exception ee) {
- ee.printStackTrace();
- }
- }
- };
-
- private OnClickListener buttonListener2 = new OnClickListener() {
- public void onClick(View v) {
- try {
- button2.setText(button2.getText() + ".");
-
- int RENDER_BUFF_SIZE = 1024*48;
-
- InputStream is = getAssets().open("Dancing_Queen.mid");
-
- Sequencer s = MidiSystem.getSequencer();
- s.open();
- s.setSequence(is);
- s.setLoopCount(1);
- s.start();
-
- } catch (Exception ee) {
- ee.printStackTrace();
- }
- }
- };
-
- public void handleMessage(Message arg0) {
- }
-}
diff --git a/libcore-disabled/instrument/MODULE_LICENSE_APACHE2 b/libcore-disabled/instrument/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcore-disabled/instrument/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassDefinition.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassDefinition.java
deleted file mode 100644
index 0780ca0..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassDefinition.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-import org.apache.harmony.instrument.internal.nls.Messages;
-
-/**
- * Wraps a {@link java.lang.Class} that is to be redefined together with the
- * byte array which constitutes the updated version of the class.
- *
- */
-public final class ClassDefinition {
-
- /**
- * The <code>Class</code> object for the class that will be instrumented.
- */
- private Class<?> definitionClass;
-
- /**
- * The new version of the class file bytes for the class being instrumented.
- */
- private byte[] definitionClassFile;
-
- /**
- * Constructs a new instance of <code>ClassDefinition</code> with the
- * supplied {@link Class} object and byte array representing the new class
- * file bytes.
- *
- * @param theClass
- * the <code>Class</code> object for the class to be redefined
- * @param theClassFile
- * an array of bytes containing the updated version of the class
- * to be redefined.
- * @throws NullPointerException
- * if either <code>theClass</code> or
- * <code>theClassFile</code> are <code>null</code>.
- */
- public ClassDefinition(Class<?> theClass, byte[] theClassFile) {
- if (theClass == null) {
- throw new NullPointerException(Messages.getString("instrument.1")); //$NON-NLS-1$
- }
- if (theClassFile == null) {
- throw new NullPointerException(Messages.getString("instrument.2")); //$NON-NLS-1$
- }
- this.definitionClass = theClass;
- this.definitionClassFile = theClassFile;
- }
-
- /**
- * Returns the {@link Class} object for the class to be redefined.
- *
- * @return the <code>Class</code> object
- */
- public Class<?> getDefinitionClass() {
- return this.definitionClass;
- }
-
- /**
- * Returns a reference to the byte array containing the re-engineered
- * version of the class.
- *
- * @return byte array containing the new version of the class
- */
- public byte[] getDefinitionClassFile() {
- return this.definitionClassFile;
- }
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassFileTransformer.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassFileTransformer.java
deleted file mode 100644
index 429184d..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassFileTransformer.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-import java.security.ProtectionDomain;
-
-/**
- * This interface must be implemented by types used to instrument classes as
- * they are loaded by a running VM. Implementations are registered by agents in
- * the {@link java.lang.instrument.Instrumentation#addTransformer} operation.
- * Once registered, a <code>ClassFileTransformer</code> has the opportunity to
- * instrument every class that is loaded or redefined by the VM provided that
- * the transformer does not have a dependency on that class.
- * <p>
- * Transformations of classes takes place just prior to them being defined by
- * the VM.
- * </p>
- *
- */
-public interface ClassFileTransformer {
-
- /**
- * Receives a <code>byte</code> array containing the raw contents of a
- * class for <i>possible</i> transformation into a new <code>byte</code>
- * array which gets returned to the caller. It is left up to the
- * implementation to decide what, if any, transformations are carried out
- * and returned.
- * <p>
- * Requests for class transformations can occur in two situations.
- * <ul>
- * <li>the attempted defining of a class using
- * {@link ClassLoader#defineClass(java.lang.String, byte[], int, int)}
- * <li>the attempted re-defining of a previously defined class using
- * {@link Instrumentation#redefineClasses(ClassDefinition[])}
- * </ul>
- * In both cases this operation will be called before the verification of
- * the specified bytes in the <code>Class</code> file format. Each
- * registered <code>ClassFileTransformer</code> instance will have this
- * operation called on it. The order of the invocations matches the order in
- * which the transformers were registered using the method
- * {@link Instrumentation#addTransformer(ClassFileTransformer)}.
- * </p>
- * <p>
- * Provided that the implementation of this method wishes to carry out a
- * transformation, the return is a newly allocated <code>byte</code> array
- * which contains <i>a copy of</i> the <code>classfileBuffer</code>
- * argument plus the transformations to the array specific to the method
- * implementation. If the transformer is written so as to pass on the
- * opportunity to modify a given input then the return value should be
- * <code>null</code>.
- * </p>
- *
- * @param loader
- * the <i>defining</i> <code>ClassLoader</code> for the
- * candidate class to be transformed.
- * @param className
- * the fully qualified name of the candidate class to be
- * transformed in the <i>fully/qualified/Name</i> format.
- * @param classBeingRedefined
- * if a class redefinition is in process then this argument will
- * be the <code>Class</code> object for the class. Otherwise,
- * if a class definition is in process, a <code>null</code>.
- * @param protectionDomain
- * the security protection domain for the class being defined or
- * redefined.
- * @param classfileBuffer
- * a <code>byte</code> array containing the class to be
- * transformed in <code>Class</code> file format.
- * <em>This argument
- * must not be modified</em>.
- * @return if transformation occurs, a newly allocated <code>byte</code>
- * array containing the modified version of
- * <code>classfileBuffer</code>, otherwise <code>null</code>.
- * @throws IllegalClassFormatException
- * if the <code>classfileBuffer</code> does not contain a
- * well-formed representation of a class in the
- * <code>Class</code> file format. Note that if an invocation
- * of this operation ends on an exception throw then (a) the
- * remaining transformers in the "chain" will still
- * have this method called, and (b) the class definition or
- * redefinition that was the catalyst for the transformation
- * opportunities will still be attempted.
- */
- public byte[] transform(ClassLoader loader, String className,
- Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
- byte[] classfileBuffer) throws IllegalClassFormatException;
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java
deleted file mode 100644
index 9696bfe..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * This exception may be thrown from implementations of the method
- * {@link java.lang.instrument.ClassFileTransformer#transform} when the class
- * file bytes supplied to it are found to be corrupted or otherwise in a format
- * which does not adhere to the expected Java class file format.
- *
- */
-public class IllegalClassFormatException extends Exception {
-
- private static final long serialVersionUID = -3841736710924794009L;
-
- /**
- * Constructs a new instance of <code>IllegalClassFormatException</code>
- * with no explanatory message.
- */
- public IllegalClassFormatException() {
- super();
- }
-
- /**
- * Constructs a new instance of <code>IllegalClassFormatException</code>
- * with the supplied message, <code>s</code>, for explanation.
- *
- * @param s
- * a string containing information on why the exception is being
- * created.
- */
- public IllegalClassFormatException(String s) {
- super(s);
- }
-}
\ No newline at end of file
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java
deleted file mode 100644
index 6dd053f..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * Instances of this interface may be used by Java instrumentation agent code
- * for support in carrying out the runtime instrumentation of classes. Using
- * such an approach, classes may be enhanced with services such as profiling,
- * logging or tracing which were not included in the source of the original
- * class.
- * <p>
- * A concrete instance of this interface is made available as an input argument
- * to all Java instrumentation agents'
- * <code>premain(String agentArgs, Instrumentation inst)</code> method.
- * </p>
- *
- */
-public interface Instrumentation {
-
- /**
- * Registers the supplied <code>transformer</code> argument with the VM.
- * Any classes that are to be defined or re-defined (if supported) in the VM
- * will then be offered to the transformer for it to carry out any byte code
- * modifications. The exception to this scheme is if the class to be defined /
- * re-defined is a dependency of the transformer.
- * <p>
- * This operation can be carried out multiple times on a concrete
- * <code>Instrumentation</code>. The order of registration is important
- * as it defines the order in which the transformers' transformation
- * operation gets called.
- * <p>
- * <p>
- * It is possible for any given instance of
- * <code>ClassFileTransformer</code> to be registered more than once with
- * this operation.
- *
- * @param transformer
- * a class file transformer
- * @throws NullPointerException
- * if <code>transformer</code> is <code>null</code>.
- */
- public void addTransformer(ClassFileTransformer transformer);
-
- /**
- * Returns an array of all of the classes that have been loaded into the VM.
- *
- * @return an array of <code>Class</code> objects with each element
- * identifying a class that has been loaded into the VM.
- */
- public Class[] getAllLoadedClasses();
-
- /**
- * Returns an array of all of the classes for which <code>loader</code> is
- * the <i>initiating</i> class loader.
- *
- * @param loader
- * a class loader. In order to obtain the array of classes
- * initiated by the bootstrap class loader this argument should
- * be <code>null</code>.
- * @return an array of <code>Class</code> objects with each element
- * identifying a class that has been initiated by the specified
- * class loader.
- */
- public Class[] getInitiatedClasses(ClassLoader loader);
-
- /**
- * Returns the number of bytes in memory required by this VM for the
- * supplied object <code>objectToSize</code>. The returned value should
- * be taken as an estimation only which is susceptible to change between
- * separate launches of the VM.
- *
- * @param objectToSize
- * any object
- * @return an approximation of the number of bytes in memory taken up by
- * <code>objectToSize</code>.
- * @throws NullPointerException
- * if the given object is null.
- */
- public long getObjectSize(Object objectToSize);
-
- /**
- * Returns a boolean indication of whether or not this VM supports the
- * on-the-fly redefining of classes that have been already loaded.
- *
- * @return <code>true</code> if class redefining is supported, otherwise
- * <code>false</code>.
- */
- public boolean isRedefineClassesSupported();
-
- /**
- * Receives an array of {@link ClassDefinition} instances and attempts to
- * carry out on-the-fly redefining on each of the associated classes.
- * Redefining in this manner may be used to update the following parts of an
- * already loaded class:
- * <ul>
- * <li>attributes
- * <li>constant pool
- * <li>method implementations
- * </ul>
- * If any invocations of a redefined method are already active in the VM
- * when this call is made then they will run to completion and be unaffected
- * by the outcome of this method. Provided the method redefinition is
- * successful, all subsequent calls on the method will run the new version.
- * <br>
- * Redefining a class may <em>not</em> be used to make changes to any
- * other aspects of a previously loaded class such as its inheritance
- * hierarchy, the names or signatures of any of its methods, the names of
- * any fields, the values of any static variables etc.
- * <p>
- * If a class associated with a <code>ClassDefinition</code> is
- * successfully redefined then there will be no resulting re-run of any of
- * its initialization code. Similarly, any instances of the class that were
- * created before the redefining will not be changed in any way. That is,
- * they will remain in the VM as instances of the previous version of the
- * class.
- * </p>
- * <p>
- * Note that before the requested redefinitions are attempted, each
- * {@link ClassFileTransformer} registered with the VM will be given the
- * opportunity to carry out their own custom transformations of the new
- * version of the class.
- * </p>
- *
- * @param definitions
- * an array of <code>ClassDefinition</code> objects wrapping
- * the details of the classes to be redefined. A zero-length
- * array value will not cause an error but, instead, will
- * silently do nothing.
- * @throws ClassNotFoundException
- * if any of the classes specified in the contents of
- * <code>definitions</code> cannot be located.
- * @throws UnmodifiableClassException
- * if any of the classes specified in the contents of
- * <code>definitions</code> cannot be modified.
- * @throws UnsupportedOperationException
- * if this method is not supported in by the VM. May be checked
- * in advance by calling {@link #isRedefineClassesSupported()}.
- * @throws ClassFormatError
- * if any of the <code>definitions</code> elements has been
- * created with a <code>byte</code> array containing a badly
- * formed class file.
- * @throws NoClassDefFoundError
- * if there is disagreement between the name of a class to be
- * redefined and the name of the class from the corresponding
- * class file format byte array.
- * @throws UnsupportedClassVersionError
- * if the version of any of the classes to be redefined is not
- * supported by the VM.
- * @throws ClassCircularityError
- * if a circular dependency is detected among the classes to be
- * redefined.
- * @throws LinkageError
- * if a linkage error situation is detected such that there is
- * an incompatability between dependent classes.
- * @throws NullPointerException
- * if <code>definitions</code> or any of its elements are
- * found to be <code>null</code>.
- * @see #isRedefineClassesSupported()
- */
- public void redefineClasses(ClassDefinition[] definitions)
- throws ClassNotFoundException, UnmodifiableClassException;
-
- /**
- * Removes <i>the most recently added instance of</i> the
- * <code>ClassFileTransformer</code> object from the VM's list of
- * registered transformers. After this call completes, the specified
- * <code>ClassFileTransformer</code> object will no longer have its
- * <code>transform()<code> method automatically invoked when class definitions or
- * redefinitions are attempted.
- *
- * @param transformer
- * a previously registered <code>ClassFileTransformer</code>.
- * @return <code>true</code> if <code>transformer</code> was located in
- * the list of registered transformers and successfully removed.
- * Otherwise, <code>false</code>.
- * @throws NullPointerException
- * if <code>transformer</code> is <code>null</code>.
- */
- public boolean removeTransformer(ClassFileTransformer transformer);
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java
deleted file mode 100644
index e8c8d57..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * This exception may be thrown from implementations of the method
- * {@link java.lang.instrument.Instrumentation#redefineClasses} when one of the
- * desired class redefinition operations cannot be carried out. Such a situation
- * may arise if a redefinition attempts to alter the members of a class or its
- * inheritance hierarchy.
- *
- */
-public class UnmodifiableClassException extends Exception {
-
- private static final long serialVersionUID = 1716652643585309178L;
-
- /**
- * Constructs a new instance of <code>UnmodifiableClassException</code>
- * with no explanatory message.
- */
- public UnmodifiableClassException() {
- super();
- }
-
- /**
- * Constructs a new instance of <code>UnmodifiableClassException</code>
- * with the supplied message, <code>s</code>, for explanation.
- *
- * @param s
- * a string containing information on why the exception is being
- * created.
- */
- public UnmodifiableClassException(String s) {
- super(s);
- }
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html b/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html
deleted file mode 100644
index 50224d7..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
- <body>
- <p>
- Provides classes and interfaces needed for instrumenting applications.
- <p>
- </body>
-</html>
\ No newline at end of file
diff --git a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java b/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java
deleted file mode 100644
index cdde768..0000000
--- a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
- * All changes made to this file manually will be overwritten
- * if this tool runs again. Better make changes in the template file.
- */
-
-package org.apache.harmony.instrument.internal.nls;
-
-// BEGIN android-added
-import org.apache.harmony.luni.util.MsgHelp;
-// END android-added
-
-/**
- * This class retrieves strings from a resource bundle and returns them,
- * formatting them with MessageFormat when required.
- * <p>
- * It is used by the system classes to provide national language support, by
- * looking up messages in the <code>
- * org.apache.harmony.instrument.internal.nls.messages
- * </code>
- * resource bundle. Note that if this file is not available, or an invalid key
- * is looked up, or resource bundle support is not available, the key itself
- * will be returned as the associated message. This means that the <em>KEY</em>
- * should a reasonable human-readable (english) string.
- *
- */
-public class Messages {
-
- // BEGIN android-changed
- private static final String sResource =
- "org.apache.harmony.instrument.internal.nls.messages";
- // END android-changed
-
- /**
- * Retrieves a message which has no arguments.
- *
- * @param msg
- * String the key to look up.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg) {
- // BEGIN android-changed
- return MsgHelp.getString(sResource, msg);
- // END android-changed
- }
-
- /**
- * Retrieves a message which takes 1 argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * Object the object to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object arg) {
- return getString(msg, new Object[] { arg });
- }
-
- /**
- * Retrieves a message which takes 1 integer argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * int the integer to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, int arg) {
- return getString(msg, new Object[] { Integer.toString(arg) });
- }
-
- /**
- * Retrieves a message which takes 1 character argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * char the character to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, char arg) {
- return getString(msg, new Object[] { String.valueOf(arg) });
- }
-
- /**
- * Retrieves a message which takes 2 arguments.
- *
- * @param msg
- * String the key to look up.
- * @param arg1
- * Object an object to insert in the formatted output.
- * @param arg2
- * Object another object to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object arg1, Object arg2) {
- return getString(msg, new Object[] { arg1, arg2 });
- }
-
- /**
- * Retrieves a message which takes several arguments.
- *
- * @param msg
- * String the key to look up.
- * @param args
- * Object[] the objects to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object[] args) {
- // BEGIN android-changed
- return MsgHelp.getString(sResource, msg, args);
- // END android-changed
- }
-}
diff --git a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties b/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties
deleted file mode 100644
index 6c59186..0000000
--- a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties
+++ /dev/null
@@ -1,21 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# messages for EN locale
-instrument.1=Received null class argument.
-instrument.2=Received null class file argument.
-instrument.3=Redefinition operation is not supported!
-instrument.4=Fatal error: failed to execute premain class of java agent.
diff --git a/libcore-disabled/sound/MODULE_LICENSE_APACHE2 b/libcore-disabled/sound/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcore-disabled/sound/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java
deleted file mode 100644
index fb6b0e5..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MidiFileFormat;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.spi.MidiFileReader;
-
-/**
- * Implements a MidiFileReader for Android. We need to cache data coming from an
- * arbitrary InputStream, since the Android MediaPlayer expects us to pass in a
- * file or a URL.
- */
-public class AndroidMidiFileReader extends MidiFileReader {
-
- @Override
- public MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException, IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException,
- IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException, IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Sequence getSequence(File file) throws InvalidMidiDataException, IOException {
- return new AndroidSequence(file.toURL());
- }
-
- @Override
- public Sequence getSequence(InputStream stream) throws InvalidMidiDataException, IOException {
- File file = File.createTempFile("javax.sound.midi-", null);
- file.deleteOnExit();
-
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
- byte[] buffer = new byte[1024];
-
- int count = stream.read(buffer);
- while (count >= 0) {
- out.write(buffer, 0, count);
- count = stream.read(buffer);
- }
-
- out.flush();
- out.close();
-
- return getSequence(file);
- }
-
- @Override
- public Sequence getSequence(URL url) throws InvalidMidiDataException, IOException {
- return new AndroidSequence(url);
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java
deleted file mode 100644
index 861f970..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.Sequence;
-
-/**
- * Implements a MIDI Sequence for Android. Its set of tracks etc. will always
- * be empty (at least we don't care about the contents). Instead, we store the
- * URL to the original MIDI data in it, so we can feed it into the Android
- * MediaPlayer.
- */
-public class AndroidSequence extends Sequence {
-
- /**
- * Holds the URL to the MIDI data.
- */
- private URL url;
-
- /**
- * Creates a new AndroidSequence.
- *
- * @param url The URL that points to the MIDI data.
- *
- * @throws InvalidMidiDataException If the MIDI data is invalid (which we
- * actually don't check at all).
- */
- public AndroidSequence(URL url) throws InvalidMidiDataException {
- super(0.0f, 1);
-
- this.url = url;
- }
-
- /**
- * Returns the URL pointing to the MIDI data.
- *
- * @return The URL.
- */
- URL getURL() {
- return url;
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java
deleted file mode 100644
index 6b3ea20..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.sound.midi.ControllerEventListener;
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MetaEventListener;
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiUnavailableException;
-import javax.sound.midi.Receiver;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.Sequencer;
-import javax.sound.midi.Track;
-import javax.sound.midi.Transmitter;
-
-/**
- * Implements a MIDI Sequencer for Android. Since Android's MediaPlayer is
- * somewhat limited, we only support MIDI playback, but not recording or the
- * querying of MIDI information. Many of the methods hence throw
- * {@link java.lang.UnsupportedOperationException} or return dummy results.
- */
-public class AndroidSequencer implements Sequencer {
-
- /**
- * Defines the DeviceInfo for our AndroidSequencer.
- */
- private class Info extends MidiDevice.Info {
- public Info() {
- super("Android Sequencer", "Android Sequencer", "The Android Project", "1.0");
- }
- }
-
- /**
- * Holds the Android MediaPlayer we use.
- */
- private MediaPlayer player;
-
- /**
- * Holds the Android Sequence we want to play.
- */
- private AndroidSequence sequence;
-
- public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers) {
- throw new UnsupportedOperationException();
- }
-
- public boolean addMetaEventListener(MetaEventListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public int getLoopCount() {
- throw new UnsupportedOperationException();
- }
-
- public long getLoopEndPoint() {
- throw new UnsupportedOperationException();
- }
-
- public long getLoopStartPoint() {
- throw new UnsupportedOperationException();
- }
-
- public SyncMode getMasterSyncMode() {
- throw new UnsupportedOperationException();
- }
-
- public SyncMode[] getMasterSyncModes() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondLength() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondPosition() {
- throw new UnsupportedOperationException();
- }
-
- public Sequence getSequence() {
- return sequence;
- }
-
- public SyncMode getSlaveSyncMode() {
- throw new UnsupportedOperationException();
- }
-
- public SyncMode[] getSlaveSyncModes() {
- throw new UnsupportedOperationException();
- }
-
- public float getTempoFactor() {
- throw new UnsupportedOperationException();
- }
-
- public float getTempoInBPM() {
- throw new UnsupportedOperationException();
- }
-
- public float getTempoInMPQ() {
- throw new UnsupportedOperationException();
- }
-
- public long getTickLength() {
- throw new UnsupportedOperationException();
- }
-
- public long getTickPosition() {
- throw new UnsupportedOperationException();
- }
-
- public boolean getTrackMute(int track) {
- throw new UnsupportedOperationException();
- }
-
- public boolean getTrackSolo(int track) {
- throw new UnsupportedOperationException();
- }
-
- public boolean isRecording() {
- return false;
- }
-
- public boolean isRunning() {
- return player != null && player.isPlaying();
- }
-
- public void recordDisable(Track track) {
- throw new UnsupportedOperationException();
- }
-
- public void recordEnable(Track track, int channel) {
- throw new UnsupportedOperationException();
- }
-
- public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers) {
- throw new UnsupportedOperationException();
- }
-
- public void removeMetaEventListener(MetaEventListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopCount(int count) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopEndPoint(long tick) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopStartPoint(long tick) {
- throw new UnsupportedOperationException();
- }
-
- public void setMasterSyncMode(SyncMode sync) {
- throw new UnsupportedOperationException();
- }
-
- public void setMicrosecondPosition(long microseconds) {
- throw new UnsupportedOperationException();
- }
-
- public void setSequence(InputStream stream) throws IOException, InvalidMidiDataException {
- setSequence(new AndroidMidiFileReader().getSequence(stream));
- }
-
- public void setSequence(Sequence sequence) throws InvalidMidiDataException {
- if (!(sequence instanceof AndroidSequence)) {
- throw new InvalidMidiDataException("Sequence must be an AndroidSequence");
- }
-
- if (isRunning()) {
- stop();
- }
-
- this.sequence = (AndroidSequence)sequence;
- }
-
- public void setSlaveSyncMode(SyncMode sync) {
- throw new UnsupportedOperationException();
- }
-
- public void setTempoFactor(float factor) {
- throw new UnsupportedOperationException();
- }
-
- public void setTempoInBPM(float bpm) {
- throw new UnsupportedOperationException();
- }
-
- public void setTempoInMPQ(float mpq) {
- throw new UnsupportedOperationException();
- }
-
- public void setTickPosition(long tick) {
- throw new UnsupportedOperationException();
- }
-
- public void setTrackMute(int track, boolean mute) {
- throw new UnsupportedOperationException();
- }
-
- public void setTrackSolo(int track, boolean solo) {
- throw new UnsupportedOperationException();
- }
-
- public void start() {
- if (!isOpen()) {
- throw new IllegalStateException("Sequencer must be open");
- }
-
- if (sequence == null) {
- throw new IllegalStateException("Need a Sequence to play");
- }
-
- if (!isRunning()) {
- /*
- * This is ugly, but there is no way around it: The javax.sound API
- * doesn't expect to throw an exception at this point for illegal
- * MIDI sequences. Since we don't really construct the MIDI sequence
- * from the original binary data, but only refer to its URL, the
- * MediaPlayer can actually bail out at this point. We wrap the
- * exception into a RuntimeException, to at least keep the API
- * contract.
- */
- try {
- String s = this.sequence.getURL().toExternalForm();
-
- /*
- * TODO Workaround for 1107794: MediaPlayer doesn't handle
- * "file:" URLs. Get rid of this.
- */
- if (s.startsWith("file:")) {
- s = s.substring(5);
- }
-
- player.setDataSource(s);
- player.setAudioStreamType(AudioManager.STREAM_MUSIC);
- player.prepare();
- } catch (IOException ex) {
- throw new RuntimeException(ex.toString());
- }
-
- player.start();
- }
- }
-
- public void startRecording() {
- throw new UnsupportedOperationException();
- }
-
- public void stop() {
- if (!isOpen()) {
- throw new IllegalStateException("Sequencer must be open");
- }
-
- if (isRunning()) {
- player.stop();
- }
- }
-
- public void stopRecording() {
- throw new UnsupportedOperationException();
- }
-
- public void close() {
- if (isOpen()) {
- stop();
- player = null;
- }
- }
-
- public Info getDeviceInfo() {
- return new Info();
- }
-
- public int getMaxReceivers() {
- return 0;
- }
-
- public int getMaxTransmitters() {
- return 0;
- }
-
- public Receiver getReceiver() throws MidiUnavailableException {
- throw new MidiUnavailableException("No receiver available");
- }
-
- public List<Receiver> getReceivers() {
- return new ArrayList<Receiver>();
- }
-
- public Transmitter getTransmitter() throws MidiUnavailableException {
- throw new MidiUnavailableException("No receiver available");
- }
-
- public List<Transmitter> getTransmitters() {
- return new ArrayList<Transmitter>();
- }
-
- public boolean isOpen() {
- return player != null;
- }
-
- public void open() throws MidiUnavailableException {
- try {
- player = new MediaPlayer();
- } catch (Exception ex) {
- throw new MidiUnavailableException(ex.toString());
- }
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java
deleted file mode 100644
index f9b1d47..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.UnsupportedAudioFileException;
-import javax.sound.sampled.spi.AudioFileReader;
-
-/**
- * Implements an AudioFileReader for Android. We need to cache data coming from
- * an arbitrary InputStream, since the Android MediaPlayer expects us to pass in
- * a file or URL.
- */
-public class AndroidAudioFileReader extends AudioFileReader {
-
- @Override
- public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException,
- IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AudioFileFormat getAudioFileFormat(InputStream stream)
- throws UnsupportedAudioFileException, IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException,
- IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException,
- IOException {
- return new AndroidAudioInputStream(file.toURL());
- }
-
- @Override
- public AudioInputStream getAudioInputStream(InputStream stream)
- throws UnsupportedAudioFileException, IOException {
- File file = File.createTempFile("javax.sound.sampled-", null);
- file.deleteOnExit();
-
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
- byte[] buffer = new byte[1024];
-
- int count = stream.read(buffer);
- while (count >= 0) {
- out.write(buffer, 0, count);
- count = stream.read(buffer);
- }
-
- out.flush();
- out.close();
-
- return getAudioInputStream(file);
- }
-
- @Override
- public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException,
- IOException {
- return new AndroidAudioInputStream(url);
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java
deleted file mode 100644
index ba97021..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import java.net.URL;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-
-/**
- * Implements an AudioInputStream for Android. Its internal InputStream is
- * unused (at least we don't care about the contents). Instead, we store the
- * URL to the original audio data in it, so we can feed it into the Android
- * MediaPlayer.
- */
-public class AndroidAudioInputStream extends AudioInputStream {
-
- /**
- * Holds the URL to the MIDI data.
- */
- private URL url;
-
- /**
- * Creates a new AndroidAudioInputStream.
- *
- * @param url The URL that points to the audio data.
- */
- public AndroidAudioInputStream(URL url) {
- super(null, new AudioFormat(0.0f, 0, 0, false, false), 0);
-
- this.url = url;
- }
-
- /**
- * Returns the URL pointing to the audio data.
- *
- * @return The URL.
- */
- URL getURL() {
- return url;
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java
deleted file mode 100644
index d70eec1..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.Clip;
-import javax.sound.sampled.Control;
-import javax.sound.sampled.Line;
-import javax.sound.sampled.LineListener;
-import javax.sound.sampled.LineUnavailableException;
-import javax.sound.sampled.Control.Type;
-
-/**
- * Implements an audio Clip for Android. Since Android's MediaPlayer is somewhat
- * limited, we only support sample playback, but not recording or the querying
- * of sample information. Many of the methods hence throw
- * {@link java.lang.UnsupportedOperationException} or return dummy results.
- */
-public class AndroidClip implements Clip {
-
- /**
- * Holds the Android MediaPlayer we use.
- */
- private MediaPlayer player;
-
- /**
- * Holds the AndroidAudioInputStream we want to play.
- */
- private AndroidAudioInputStream stream;
-
- public int getFrameLength() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondLength() {
- throw new UnsupportedOperationException();
- }
-
- public void loop(int count) {
- throw new UnsupportedOperationException();
- }
-
- public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
- throws LineUnavailableException {
- InputStream stream = new ByteArrayInputStream(data, offset, bufferSize);
-
- open();
-
- try {
- this.stream = (AndroidAudioInputStream)(new AndroidAudioFileReader().getAudioInputStream(stream));
- } catch (Exception ex) {
- throw new LineUnavailableException(ex.toString());
- }
- }
-
- public void open(AudioInputStream stream) throws LineUnavailableException, IOException {
- open();
-
- if (!(stream instanceof AndroidAudioInputStream)) {
- try {
- stream = new AndroidAudioFileReader().getAudioInputStream(stream);
- } catch (Exception ex) {
- throw new LineUnavailableException(ex.toString());
- }
- }
-
- this.stream = (AndroidAudioInputStream)stream;
- }
-
- public void setFramePosition(int frames) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopPoints(int start, int end) {
- throw new UnsupportedOperationException();
- }
-
- public void setMicrosecondPosition(long microseconds) {
- if (!isOpen()) {
- throw new IllegalStateException("Clip must be open");
- }
-
- player.seekTo((int)(microseconds / 1000));
- }
-
- public int available() {
- throw new UnsupportedOperationException();
- }
-
- public void drain() {
- }
-
- public void flush() {
- }
-
- public int getBufferSize() {
- throw new UnsupportedOperationException();
- }
-
- public AudioFormat getFormat() {
- throw new UnsupportedOperationException();
- }
-
- public int getFramePosition() {
- throw new UnsupportedOperationException();
- }
-
- public float getLevel() {
- throw new UnsupportedOperationException();
- }
-
- public long getLongFramePosition() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondPosition() {
- if (isOpen()) {
- return player.getCurrentPosition() * 1000;
- } else {
- return 0;
- }
- }
-
- public boolean isActive() {
- return false;
- }
-
- public boolean isRunning() {
- return player != null && player.isPlaying();
- }
-
- public void start() {
- if (!isOpen()) {
- throw new IllegalStateException("Clip must be open");
- }
-
- if (stream == null) {
- throw new IllegalStateException("Need an AudioInputStream to play");
- }
-
- if (!isRunning()) {
- /*
- * This is ugly, but there is no way around it: The javax.sound API
- * doesn't expect to throw an exception at this point for illegal
- * MIDI sequences. Since we don't really construct the MIDI sequence
- * from the original binary data, but only refer to its URL, the
- * MediaPlayer can actually bail out at this point. We wrap the
- * exception into a RuntimeException, to at least keep the API
- * contract.
- */
- try {
- String s = this.stream.getURL().toExternalForm();
-
- /*
- * TODO Workaround for 1107794: MediaPlayer doesn't handle
- * "file:" URLs. Get rid of this.
- */
- if (s.startsWith("file:")) {
- s = s.substring(5);
- }
-
- player.setDataSource(s);
- player.setAudioStreamType(AudioManager.STREAM_MUSIC);
- player.prepare();
- } catch (IOException ex) {
- throw new RuntimeException(ex.toString());
- }
-
- player.start();
- }
- }
-
- public void stop() {
- if (!isOpen()) {
- throw new IllegalStateException("Clip must be open");
- }
-
- if (isRunning()) {
- player.stop();
- }
- }
-
- public void addLineListener(LineListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void close() {
- if (isOpen()) {
- stop();
- player = null;
- }
- }
-
- public Control getControl(Type control) {
- throw new IllegalArgumentException("No controls available");
- }
-
- public Control[] getControls() {
- return new Control[0];
- }
-
- public javax.sound.sampled.Line.Info getLineInfo() {
- return new Line.Info(this.getClass());
- }
-
- public boolean isControlSupported(Type control) {
- return false;
- }
-
- public boolean isOpen() {
- return player != null;
- }
-
- public void open() throws LineUnavailableException {
- try {
- player = new MediaPlayer();
- } catch (Exception ex) {
- throw new LineUnavailableException(ex.toString());
- }
- }
-
- public void removeLineListener(LineListener listener) {
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java
deleted file mode 100644
index 318139d..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.EventListener;
-
-public interface ControllerEventListener extends EventListener {
- void controlChange(ShortMessage event);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java
deleted file mode 100644
index 397e53e..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public abstract class Instrument extends SoundbankResource {
- private Patch patch;
-
- protected Instrument(Soundbank soundbank, Patch patch, String name, Class<?> dataClass) {
- super(soundbank, name, dataClass);
- this.patch = patch;
- }
-
- public Patch getPatch() {
- return patch;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java
deleted file mode 100644
index bc1cb83..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class InvalidMidiDataException extends Exception {
- private static final long serialVersionUID = 2780771756789932067L;
-
- public InvalidMidiDataException() {
- super();
- }
-
- public InvalidMidiDataException(String message) {
- super(message);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java
deleted file mode 100644
index 0cf0d38..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.EventListener;
-
-public interface MetaEventListener extends EventListener {
- void meta(MetaMessage meta);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java
deleted file mode 100644
index fe5d9cf..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class MetaMessage extends MidiMessage {
- public static final int META = 255;
-
- private int dsp; //displacement from begin of array that
- //return by method getData() from begin
- //of array that contain data
-
- public MetaMessage() {
- super(new byte[] {-1, 0});
- }
-
- protected MetaMessage(byte[] data) {
- super(data);
- if (data == null) {
- throw new NullPointerException();
- }
- if (super.length > 3) {
- int n = 3;
- while ((n <= super.length) && (super.data[n - 1] < 0)) {
- n++;
- }
- dsp = n;
- }
- }
-
- @Override
- public Object clone() {
- return new MetaMessage(this.getMessage());
- }
-
- public byte[] getData() {
- if ((super.data != null) && (super.length > 3)) {
- byte[] bt = new byte[super.length - dsp];
- for (int i = dsp; i < super.length; i++) {
- bt[i - dsp] = super.data[i];
- }
- return bt;
- }
- return new byte[0];
- }
-
- public int getType() {
- if ((super.data != null) && (super.length >= 2)) {
- return super.data[1] & 0xFF;
- }
- return 0;
- }
-
- public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException {
- if (type < 0 || type >= 128) {
- // sound.0A=Invalid meta event with type {0}
- throw new InvalidMidiDataException(Messages.getString("sound.0A", type)); //$NON-NLS-1$
- }
- if (length < 0 || (data != null && length > data.length)) {
- // sound.03=length out of bounds: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.03", length)); //$NON-NLS-1$
- }
- try {
- if (data == null) {
- if (length != 0) {
- throw new NullPointerException();
- }
- super.setMessage(new byte[] { -1, (byte) type, 0 }, 3);
- } else {
- int div = 128;
- int n = 1;
- int ost;
- int sm = 0;
- while (length / div != 0) {
- n++;
- div *= 128;
- }
- int ln = n;
- byte[] tdata = new byte[length + ln + 2];
- div = 1;
- ost = (length / div) % 128;
- while (n != 0) {
- tdata[n - 1 + 2] = (byte) (ost + sm);
- n--;
- div *= 128;
- ost = (length / div) % 128;
- sm = 128;
- }
- tdata[0] = -1;
- tdata[1] = (byte) type;
- if (length > 0) {
- for (int i = 0; i < length; i++) {
- tdata[2 + ln + i] = data[i];
- }
- }
- super.setMessage(tdata, length + 2 + ln);
- dsp = ln + 2;
- }
- } catch (InvalidMidiDataException e) {
- throw e;
- }
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java
deleted file mode 100644
index e970641..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface MidiChannel {
- void allNotesOff();
-
- void allSoundOff();
-
- void controlChange(int controller, int value);
-
- int getChannelPressure();
-
- int getController(int controller);
-
- boolean getMono();
-
- boolean getMute();
-
- boolean getOmni();
-
- int getPitchBend();
-
- int getPolyPressure(int noteNumber);
-
- int getProgram();
-
- boolean getSolo();
-
- boolean localControl(boolean on);
-
- void noteOff(int noteNumber);
-
- void noteOff(int noteNumber, int velocity);
-
- void noteOn(int noteNumber, int velocity);
-
- void programChange(int program);
-
- void programChange(int bank, int program);
-
- void resetAllControllers();
-
- void setChannelPressure(int pressure);
-
- void setMono(boolean on);
-
- void setMute(boolean mute);
-
- void setOmni(boolean on);
-
- void setPitchBend(int bend);
-
- void setPolyPressure(int noteNumber, int pressure);
-
- void setSolo(boolean soloState);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java
deleted file mode 100644
index 9eb5169..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.List;
-
-public interface MidiDevice {
- class Info {
- private String name;
-
- private String vendor;
-
- private String description;
-
- private String version;
-
- protected Info(String name, String vendor, String description, String version) {
- this.name = name;
- this.vendor = vendor;
- this.description = description;
- this.version = version;
- }
-
- /*
- * returns true when objects are the same
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public final boolean equals(Object obj) {
- return this == obj;
- }
-
- public final String getDescription() {
- return description;
- }
-
- public final String getName() {
- return name;
- }
-
- public final String getVendor() {
- return vendor;
- }
-
- public final String getVersion() {
- return version;
- }
-
- @Override
- public final int hashCode() {
- final int PRIME = 31;
- int result = super.hashCode();
- result = PRIME * result + ((description == null) ? 0 : description.hashCode());
- result = PRIME * result + ((name == null) ? 0 : name.hashCode());
- result = PRIME * result + ((vendor == null) ? 0 : vendor.hashCode());
- result = PRIME * result + ((version == null) ? 0 : version.hashCode());
- return result;
- }
-
- @Override
- public final String toString() {
- return name;
- }
- }
-
- void close();
-
- MidiDevice.Info getDeviceInfo();
-
- int getMaxReceivers();
-
- int getMaxTransmitters();
-
- long getMicrosecondPosition();
-
- Receiver getReceiver() throws MidiUnavailableException;
-
- List<Receiver> getReceivers();
-
- Transmitter getTransmitter() throws MidiUnavailableException;
-
- List<Transmitter> getTransmitters();
-
- boolean isOpen();
-
- void open() throws MidiUnavailableException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java
deleted file mode 100644
index 145529b..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class MidiEvent {
- private MidiMessage message;
-
- private long tick;
-
- public MidiEvent(MidiMessage message, long tick) {
- this.message = message;
- this.tick = tick;
- }
-
- public MidiMessage getMessage() {
- return message;
- }
-
- public long getTick() {
- return tick;
- }
-
- public void setTick(long tick) {
- this.tick = tick;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java
deleted file mode 100644
index e4e9498..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class MidiFileFormat {
- public static final int UNKNOWN_LENGTH = -1;
-
- protected int byteLength;
-
- protected float divisionType;
-
- protected long microsecondLength;
-
- protected int resolution;
-
- protected int type;
-
- private HashMap<String, Object> properties;
-
- public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
- long microseconds) {
- this.type = type;
- this.divisionType = divisionType;
- this.resolution = resolution;
- this.byteLength = bytes;
- this.microsecondLength = microseconds;
- this.properties = new HashMap<String, Object>();
- }
-
- public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
- long microseconds, Map<String, Object> properties) {
- this.type = type;
- this.divisionType = divisionType;
- this.resolution = resolution;
- this.byteLength = bytes;
- this.microsecondLength = microseconds;
-
- this.properties = new HashMap<String, Object>();
- this.properties.putAll(properties);
- }
-
- public int getByteLength() {
- return byteLength;
- }
-
- public float getDivisionType() {
- return divisionType;
- }
-
- public long getMicrosecondLength() {
- return microsecondLength;
- }
-
- public Object getProperty(String key) {
- return properties.get(key);
- }
-
- public int getResolution() {
- return resolution;
- }
-
- public int getType() {
- return type;
- }
-
- public Map<String, Object> properties() {
- return Collections.unmodifiableMap(properties);
-
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java
deleted file mode 100644
index 1629ee1..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class MidiMessage implements Cloneable {
-
- protected byte[] data;
-
- protected int length;
-
- protected MidiMessage(byte[] data) {
- if (data == null) {
- length = 0;
- } else {
- length = data.length;
- this.data = data;
- }
- }
-
- @Override
- public abstract Object clone();
-
- public int getLength() {
- return length;
- }
-
- public byte[] getMessage() {
- if (data == null) {
- throw new NullPointerException();
- }
- return data.clone();
- }
-
- public int getStatus() {
- if ((data == null) || (length == 0)) {
- return 0;
- }
- return data[0] & 0xFF;
- }
-
- protected void setMessage(byte[] data, int length) throws InvalidMidiDataException {
- if ((length < 0) || (length > data.length)) {
- // sound.03=length out of bounds: {0}
- throw new IndexOutOfBoundsException(Messages.getString("sound.03", length)); //$NON-NLS-1$
- }
-
- this.data = new byte[length];
- if (length != 0) {
- for (int i = 0; i < length; i++) {
- this.data[i] = data[i];
- }
- }
- this.length = length;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java
deleted file mode 100644
index eede0a9..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-
-import javax.sound.midi.MidiDevice.Info;
-import javax.sound.midi.spi.MidiDeviceProvider;
-import javax.sound.midi.spi.MidiFileReader;
-import javax.sound.midi.spi.MidiFileWriter;
-import javax.sound.midi.spi.SoundbankReader;
-
-import org.apache.harmony.sound.utils.ProviderService;
-
-public class MidiSystem {
- //path to javax.sound.midi.spi.MidiDeviceProvider file in the jar-file
- private final static String midiDeviceProviderPath =
- "META-INF/services/javax.sound.midi.spi.MidiDeviceProvider";
-
- //path to javax.sound.midi.spi.MidiFileReader file in the jar-file
- private final static String midiFileReaderPath =
- "META-INF/services/javax.sound.midi.spi.MidiFileReader";
-
- //path to javax.sound.midi.spi.MidiFileWriter file in the jar-file
- private final static String midiFileWriterPath =
- "META-INF/services/javax.sound.midi.spi.MidiFileWriter";
-
- //path to javax.sound.midi.spi.SoundbankReader file in the jar-file
- private final static String soundbankReaderPath =
- "META-INF/services/javax.sound.midi.spi.SoundbankReader";
-
- //key to find default receiver in the sound.properties file
- private final static String receiverName = "javax.sound.midi.Receiver";
-
- //key to find default sequencer in the sound.properties file
- private final static String sequencerName = "javax.sound.midi.Sequencer";
-
- //key to find default synthesizer in the sound.properties file
- private final static String synthesizerName = "javax.sound.midi.Synthesizer";
-
- //key to find default transmitter in the sound.properties file
- private final static String transmitterName = "javax.sound.midi.Transmitter";
-
- public static MidiDevice getMidiDevice(MidiDevice.Info info)
- throws MidiUnavailableException {
- //FIXME
- /*
- * this method must to throw out MidiUnavailableException if requested device
- * is not available
- */
-
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- /*
- * find device that describes by parameter info and return it
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.equals(info)) {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(info);
- }
- }
- }
- /*
- * if we can't find device with requested info, we throw out IllegalArgumentException
- */
- throw new IllegalArgumentException("Requested device not installed: " + info.getName());
- }
-
- public static MidiDevice.Info[] getMidiDeviceInfo() {
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- //variable to save MidiDevice.Info
- List<MidiDevice.Info> infos = new ArrayList<MidiDevice.Info>();
- /*
- * look through list of providers and save info of devices
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- infos.add(element);
- }
- }
-
- MidiDevice.Info[] temp = new MidiDevice.Info[infos.size()];
- return infos.toArray(temp);
- }
-
- public static MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(file);
- }
-
- public static MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(stream);
- }
-
- public static MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(url);
- }
-
- public static int[] getMidiFileTypes() {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).getMidiFileTypes();
- }
-
- public static int[] getMidiFileTypes(Sequence sequence) {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).getMidiFileTypes(sequence);
- }
-
- public static Receiver getReceiver() throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Receiver
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(receiverName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- String provName;
- int deviceNum = -1;
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Recivers installed on your system!");
- }
-
- public static Sequence getSequence(File file) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- // BEGIN android-added
- try {
- ((List)fileReaderProviders).add((Object)Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(file);
- }
-
- public static Sequence getSequence(InputStream stream) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- // BEGIN android-added
- try {
- ((List)fileReaderProviders).add(Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(stream);
- }
-
- public static Sequence getSequence(URL url) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- // BEGIN android-added
- try {
- ((List)fileReaderProviders).add(Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(url);
- }
-
- public static Sequencer getSequencer() throws MidiUnavailableException {
- /*
- * this method is equals to method MidiSystem.getSequencer(true)
- */
- return getSequencer(true);
- }
-
- public static Sequencer getSequencer(boolean connected) throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Sequencer
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(sequencerName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-
- Sequencer sequencer;
- Transmitter seqTrans;
- Synthesizer synth;
- Receiver recv;
- String provName;
- int deviceNum = -1;
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- // BEGIN android-added
- try {
- return (Sequencer)(Class.forName("com.android.internal.sound.midi.AndroidSequencer").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Synthesizers installed on your system!");
- }
-
- public static Soundbank getSoundbank(File file) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of SoundbankReaderProviders
- */
- List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
- if (soundbankReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no SoundbankReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(file);
- }
-
- public static Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of SoundbankReaderProviders
- */
- List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
- if (soundbankReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no SoundbankReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(stream);
- }
-
- public static Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of SoundbankReaderProviders
- */
- List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
- if (soundbankReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no SoundbankReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(url);
- }
-
- public static Synthesizer getSynthesizer() throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Synthesizer
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(synthesizerName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- String provName;
- int deviceNum = -1;
-
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Synthesizers installed on your system!");
- }
-
- public static Transmitter getTransmitter() throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Transmitter
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(transmitterName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- String provName;
- int deviceNum = -1;
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Transmitters installed on your system!");
- }
-
- public static boolean isFileTypeSupported(int fileType) {
- /*
- * obtain the list of MidiFileWriterProviders;
- * if we already obtain the list of providers, we don't obtain it again
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).isFileTypeSupported(fileType);
- }
-
- public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).isFileTypeSupported(fileType, sequence);
- }
-
- public static int write(Sequence in, int type, File out) throws IOException {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).write(in, type, out);
- }
-
- public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).write(in, fileType, out);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiUnavailableException.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiUnavailableException.java
deleted file mode 100644
index bd50af5..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiUnavailableException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class MidiUnavailableException extends Exception {
- private static final long serialVersionUID = 6093809578628944323L;
-
- public MidiUnavailableException() {
- super();
- }
-
- public MidiUnavailableException(String message) {
- super(message);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Patch.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Patch.java
deleted file mode 100644
index fc1d280..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Patch.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class Patch {
- private int bank;
-
- private int program;
-
- public Patch(int bank, int program) {
- this.bank = bank;
- this.program = program;
- }
-
- public int getBank() {
- return bank;
- }
-
- public int getProgram() {
- return program;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Receiver.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Receiver.java
deleted file mode 100644
index 014c05f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Receiver.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Receiver {
- void close();
-
- void send(MidiMessage message, long timeStamp);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequence.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequence.java
deleted file mode 100644
index 0a12834..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequence.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.Vector;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class Sequence {
- public static final float PPQ = 0.0f;
-
- public static final float SMPTE_24 = 24.0f;
-
- public static final float SMPTE_25 = 25.0f;
-
- public static final float SMPTE_30 = 30.0f;
-
- public static final float SMPTE_30DROP = 29.969999313354492f;
-
- protected float divisionType;
-
- protected int resolution;
-
- protected Vector<Track> tracks;
-
- private Vector<Patch> patches;
-
- public Sequence(float divisionType, int resolution) throws InvalidMidiDataException {
- if (divisionType != Sequence.PPQ &&
- divisionType != Sequence.SMPTE_24 &&
- divisionType != Sequence.SMPTE_25 &&
- divisionType != Sequence.SMPTE_30 &&
- divisionType != Sequence.SMPTE_30DROP ) {
- // sound.0B=Unsupported division type: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.0B", divisionType)); //$NON-NLS-1$
- }
- this.divisionType = divisionType;
- this.resolution = resolution;
- this.tracks = new Vector<Track>();
- this.patches = new Vector<Patch>();
-
- }
-
- public Sequence(float divisionType, int resolution, int numTracks)
- throws InvalidMidiDataException {
- if (divisionType != Sequence.PPQ &&
- divisionType != Sequence.SMPTE_24 &&
- divisionType != Sequence.SMPTE_25 &&
- divisionType != Sequence.SMPTE_30 &&
- divisionType != Sequence.SMPTE_30DROP ) {
- // sound.0B=Unsupported division type: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.0B", divisionType)); //$NON-NLS-1$
- }
- this.divisionType = divisionType;
- this.resolution = resolution;
- this.patches = new Vector<Patch>();
- this.tracks = new Vector<Track>();
- if (numTracks > 0) {
- for (int i = 0; i < numTracks; i++) {
- tracks.add(new Track());
- }
- }
- }
-
- public Track createTrack() {
- /*
- * new Tracks accrue to the end of vector
- */
- Track tr = new Track();
- tracks.add(tr);
- return tr;
- }
-
- public boolean deleteTrack(Track track) {
- return tracks.remove(track);
- }
-
- public float getDivisionType() {
- return divisionType;
- }
-
- public long getMicrosecondLength() {
- float divisionType;
- if (this.divisionType == 0.0f) {
- divisionType = 2;
- } else {
- divisionType = this.divisionType;
- }
- return (long) (1000000.0 * getTickLength() /
- (divisionType * this.resolution * 1.0f));
- }
-
- public Patch[] getPatchList() {
- //FIXME
- /*
- * I don't understand how to works this method, and so
- * I simply return an empty array. 'patches' initializes
- * in the constructor as empty vector
- */
- Patch[] patch = new Patch[patches.size()];
- patches.toArray(patch);
- return patch;
- }
-
- public int getResolution() {
- return resolution;
- }
-
- public long getTickLength() {
- /*
- * this method return the biggest value of tick of
- * all tracks contain in the Sequence
- */
- long maxTick = 0;
- for (int i = 0; i < tracks.size(); i++) {
- if (maxTick < tracks.get(i).ticks()) {
- maxTick = tracks.get(i).ticks();
- }
- }
- return maxTick;
- }
-
- public Track[] getTracks() {
- Track[] track = new Track[tracks.size()];
- tracks.toArray(track);
- return track;
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequencer.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequencer.java
deleted file mode 100644
index 4f0d8f8..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequencer.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public interface Sequencer extends MidiDevice {
- int LOOP_CONTINUOUSLY = -1;
-
- class SyncMode {
- public static final SyncMode INTERNAL_CLOCK = new SyncMode("INTERNAL_CLOCK"); //$NON-NLS-1$
-
- public static final SyncMode MIDI_SYNC = new SyncMode("MIDI_SYNC"); //$NON-NLS-1$
-
- public static final SyncMode MIDI_TIME_CODE = new SyncMode("MIDI_TIME_CODE"); //$NON-NLS-1$
-
- public static final SyncMode NO_SYNC = new SyncMode("NO_SYNC"); //$NON-NLS-1$
-
- private String name;
-
- protected SyncMode(String name) {
- this.name = name;
- }
-
- @Override
- public final boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!super.equals(obj)) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final SyncMode other = (SyncMode) obj;
- if (name == null) {
- if (other.name != null) {
- return false;
- }
- } else if (!name.equals(other.name)) {
- return false;
- }
- return true;
- }
-
- @Override
- public final int hashCode() {
- final int PRIME = 31;
- int result = super.hashCode();
- result = PRIME * result + ((name == null) ? 0 : name.hashCode());
- return result;
- }
-
- @Override
- public final String toString() {
- return name;
- }
- }
-
- int[] addControllerEventListener(ControllerEventListener listener, int[] controllers);
-
- boolean addMetaEventListener(MetaEventListener listener);
-
- int getLoopCount();
-
- long getLoopEndPoint();
-
- long getLoopStartPoint();
-
- Sequencer.SyncMode getMasterSyncMode();
-
- Sequencer.SyncMode[] getMasterSyncModes();
-
- long getMicrosecondLength();
-
- long getMicrosecondPosition();
-
- Sequence getSequence();
-
- Sequencer.SyncMode getSlaveSyncMode();
-
- Sequencer.SyncMode[] getSlaveSyncModes();
-
- float getTempoFactor();
-
- float getTempoInBPM();
-
- float getTempoInMPQ();
-
- long getTickLength();
-
- long getTickPosition();
-
- boolean getTrackMute(int track);
-
- boolean getTrackSolo(int track);
-
- boolean isRecording();
-
- boolean isRunning();
-
- void recordDisable(Track track);
-
- void recordEnable(Track track, int channel);
-
- int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers);
-
- void removeMetaEventListener(MetaEventListener listener);
-
- void setLoopCount(int count);
-
- void setLoopEndPoint(long tick);
-
- void setLoopStartPoint(long tick);
-
- void setMasterSyncMode(Sequencer.SyncMode sync);
-
- void setMicrosecondPosition(long microseconds);
-
- void setSequence(InputStream stream) throws IOException, InvalidMidiDataException;
-
- void setSequence(Sequence sequence) throws InvalidMidiDataException;
-
- void setSlaveSyncMode(Sequencer.SyncMode sync);
-
- void setTempoFactor(float factor);
-
- void setTempoInBPM(float bpm);
-
- void setTempoInMPQ(float mpq);
-
- void setTickPosition(long tick);
-
- void setTrackMute(int track, boolean mute);
-
- void setTrackSolo(int track, boolean solo);
-
- void start();
-
- void startRecording();
-
- void stop();
-
- void stopRecording();
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/ShortMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/ShortMessage.java
deleted file mode 100644
index e75b784..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/ShortMessage.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class ShortMessage extends MidiMessage {
-
- public static final int ACTIVE_SENSING = 254;
-
- public static final int CHANNEL_PRESSURE = 208;
-
- public static final int CONTINUE = 251;
-
- public static final int CONTROL_CHANGE = 176;
-
- public static final int END_OF_EXCLUSIVE = 247;
-
- public static final int MIDI_TIME_CODE = 241;
-
- public static final int NOTE_OFF = 128;
-
- public static final int NOTE_ON = 144;
-
- public static final int PITCH_BEND = 224;
-
- public static final int POLY_PRESSURE = 160;
-
- public static final int PROGRAM_CHANGE = 192;
-
- public static final int SONG_POSITION_POINTER = 242;
-
- public static final int SONG_SELECT = 243;
-
- public static final int START = 250;
-
- public static final int STOP = 252;
-
- public static final int SYSTEM_RESET = 255;
-
- public static final int TIMING_CLOCK = 248;
-
- public static final int TUNE_REQUEST = 246;
-
- public ShortMessage() {
- super(new byte[] {-112, 64, 127});
- }
-
- protected ShortMessage(byte[] data) {
- super(data);
- }
-
- @Override
- public Object clone() {
- return new ShortMessage(this.getMessage());
- }
-
- public int getChannel() {
- /*
- * channel change from 0 up to 15
- */
- if ((data == null) || (data.length == 0)) {
- return 0;
- }
- return data[0] & 0x0F;
- }
-
- public int getCommand() {
- /*
- * command should be divisible by 16 without rest
- */
- if ((data == null) || (data.length == 0)) {
- return 0;
- }
- return (data[0] & 0xFF) - getChannel();
- }
-
- public int getData1() {
- if ((data == null) || (data.length == 0)) {
- return 0;
- } else if (data.length < 2) {
- return 0;
- } else {
- return data[1] & 0xFF;
- }
- }
-
- public int getData2() {
- if ((data == null) || (data.length == 0)) {
- return 0;
- } else if (data.length < 3) {
- return 0;
- } else {
- return data[2] & 0xFF;
- }
- }
-
- protected final int getDataLength(int status)
- throws InvalidMidiDataException {
- // FIXME
- /*
- * I have some question about this method. I didn't understand how
- * should to work this method, but some results I get by experimental
- * method. From 0 up to 127, from 256 up to 383 and so on this method
- * throw out exception, i.e. after 256 begin cycle with some small
- * differences in the first lap, from 0 up to 255. From the second lap
- * and so on this method, getDataLenght(int), throw out exception with
- * value of status from 496 up to 511, from 752 up to 767 and so on,
- * i.e. on the last 16 number of 256-lap. And now differences in the
- * first lap. This method don't throw out exception with value of status
- * from 240 up to 255. It has next behavior:
- * - value of status equals 240 -- throw out exception;
- * - 241 -- return 1;
- * - 242 -- return 2;
- * - 243 -- return 1;
- * - from 244 up to 245 -- throw out exception;
- * - from 246 up to 255 -- return 0;
- */
- if (status < 0) {
- // sound.04=Invalid status byte: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
- }
- if (((status % 256) >= 0) && ((status % 256) <= 127)) {
- // sound.04=Invalid status byte: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
- }
- if (((status / 256) == 0)
- && ((status == 240) || (status == 244) || (status == 245))) {
- // sound.04=Invalid status byte: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
- }
- if (((status / 256) != 0) && ((status % 256) >= 244)
- && ((status % 256) <= 255)) {
- // sound.04=Invalid status byte: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
- }
-
- if ((status / 256) == 0) {
- if ((status == 241) || (status == 243)) {
- return 1;
- } else if (status == 242) {
- return 2;
- } else if ((status >= 246) && (status <= 255)) {
- return 0;
- }
- }
- if (((status % 256) >= 128) && ((status % 256) <= 191)) {
- return 2;
- } else if (((status % 256) >= 192) && ((status % 256) <= 223)) {
- return 1;
- } else {
- return 2;
- }
- }
-
- public void setMessage(int status) throws InvalidMidiDataException {
- /*
- * value of variable status is more or equals 246 and less or equals 255
- */
- if ((status < 246) || (status > 255)) {
- // sound.04=Invalid status byte: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
- }
- super.setMessage(new byte[] {(byte) status}, 1);
- }
-
- public void setMessage(int status, int data1, int data2)
- throws InvalidMidiDataException {
- // FIXME
- /*
- * In the Sun's implementation variables data1 and data2 don't use; I
- * don't find situation when this variables influence on result of
- * functions getData1() and getData2(). But function getDataLength(int)
- * return 0 when I modify status byte from 246 up to 255, and so I think
- * it's true.
- */
- if ((status < 246) || (status > 255)) {
- // sound.04=Invalid status byte: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
- }
- super.setMessage(new byte[] {(byte) status}, 1);
- }
-
- public void setMessage(int command, int channel, int data1, int data2)
- throws InvalidMidiDataException {
- // FIXME
- /*
- * value of variable command is more or equals 128 and less or equals
- * 239
- */
- if ((command < 128) || (command > 239)) {
- /*
- * when this exception throw out, the value of variable command
- * should be the hexadecimal number
- */
- // sound.05=command out of range: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.05", command)); //$NON-NLS-1$
- }
- /*
- * value of variable channel is more or equals 0 and less or equals 15
- */
- if ((channel < 0) || (channel > 15)) {
- // sound.06=channel out of range: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.06", channel)); //$NON-NLS-1$
- }
- /*
- * value of data1 and data2 is more or equals 0 and less or equals 127,
- * but when command more or equals 192 and less or equals 223 the second
- * data, data2, is unused, because getDataLength(int) return 1 in this
- * case, and in other cases it return 2
- */
- if ((getDataLength(command) >= 1) && ((data1 < 0) || (data1 > 127))) {
- // sound.07=data1 out of range: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.07", data1)); //$NON-NLS-1$
- }
- if ((getDataLength(command) == 2) && ((data2 < 0) || (data2 > 127))) {
- // sound.08=data2 out of range: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.08", data2)); //$NON-NLS-1$
- }
-
- int tcom = command - (command % 16);
- if (getDataLength(command) == 1) {
- super.setMessage(new byte[] {(byte) (tcom + channel), (byte) data1}, 2);
- } else {
- super.setMessage(new byte[] {(byte) (tcom + channel), (byte) data1,
- (byte) data2}, 3);
- }
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Soundbank.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Soundbank.java
deleted file mode 100644
index c2a7a85..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Soundbank.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Soundbank {
- String getDescription();
-
- Instrument getInstrument(Patch patch);
-
- Instrument[] getInstruments();
-
- String getName();
-
- SoundbankResource[] getResources();
-
- String getVendor();
-
- String getVersion();
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/SoundbankResource.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/SoundbankResource.java
deleted file mode 100644
index d824d53..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/SoundbankResource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public abstract class SoundbankResource {
- private Soundbank soundbank;
- private String name;
- private Class<?> dataClass;
-
- protected SoundbankResource(Soundbank soundbank, String name, Class<?> dataClass) {
- super();
- this.soundbank = soundbank;
- this.name = name;
- this.dataClass = dataClass;
- }
-
- public abstract Object getData();
-
- public Class<?> getDataClass() {
- return dataClass;
- }
-
- public String getName() {
- return name;
- }
-
- public Soundbank getSoundbank() {
- return soundbank;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Synthesizer.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Synthesizer.java
deleted file mode 100644
index b203a85..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Synthesizer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Synthesizer extends MidiDevice {
- Instrument[] getAvailableInstruments();
-
- MidiChannel[] getChannels();
-
- Soundbank getDefaultSoundbank();
-
- long getLatency();
-
- Instrument[] getLoadedInstruments();
-
- int getMaxPolyphony();
-
- VoiceStatus[] getVoiceStatus();
-
- boolean isSoundbankSupported(Soundbank soundbank);
-
- boolean loadAllInstruments(Soundbank soundbank);
-
- boolean loadInstrument(Instrument instrument);
-
- boolean loadInstruments(Soundbank soundbank, Patch[] patchList);
-
- boolean remapInstrument(Instrument from, Instrument to);
-
- void unloadAllInstruments(Soundbank soundbank);
-
- void unloadInstrument(Instrument instrument);
-
- void unloadInstruments(Soundbank soundbank, Patch[] patchList);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/SysexMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/SysexMessage.java
deleted file mode 100644
index 8ba7b86..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/SysexMessage.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class SysexMessage extends MidiMessage {
- public static final int SPECIAL_SYSTEM_EXCLUSIVE = 247;
-
- public static final int SYSTEM_EXCLUSIVE = 240;
-
- public SysexMessage() {
- super(new byte[] {-16, -9});
- }
-
- protected SysexMessage(byte[] data) {
- super(data);
- }
-
- @Override
- public Object clone() {
- return new SysexMessage(this.getMessage());
- }
-
- public byte[] getData() {
- byte[] bt = new byte[super.length - 1];
- for(int i = 1; i < super.length; i++) {
- bt[i-1] = super.data[i];
- }
- return bt;
- }
-
- @Override
- public void setMessage(byte[] data, int length) throws InvalidMidiDataException {
- //FIXME
- /*
- * if this exception throw out, the value of wrong status byte
- * should be the hexadecimal value
- */
- if(((data[0] & 0xFF) != SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE) &&
- ((data[0] & 0xFF) != SysexMessage.SYSTEM_EXCLUSIVE)) {
- // sound.09=Invalid status byte for sysex message: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.09", //$NON-NLS-1$
- data[0] & 0xFF));
- }
- super.setMessage(data, length);
- }
-
- public void setMessage(int status, byte[] data, int length) throws InvalidMidiDataException {
- //FIXME
- /*
- * if this exception throw out, the value of wrong status byte
- * should be the hexadecimal value
- */
- if((status != SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE) &&
- (status != SysexMessage.SYSTEM_EXCLUSIVE)) {
- // sound.09=Invalid status byte for sysex message: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.09", //$NON-NLS-1$
- status));
- }
- if((length < 0) || (length > data.length)) {
- // sound.03=length out of bounds: {0}
- throw new IndexOutOfBoundsException(Messages.getString("sound.03", length)); //$NON-NLS-1$
- }
- byte[] bt = new byte[length + 1];
- bt[0] = (byte) status;
- for(int i = 0; i < length; i++) {
- bt[i+1] = data[i];
- }
- super.setMessage(bt, length + 1);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Track.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Track.java
deleted file mode 100644
index 27dab92..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Track.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.ArrayList;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class Track {
- private ArrayList<MidiEvent> events; //vector of events contain in the Track
-
- private MidiEvent badEvent; //variable to save event which I try to add
- //to empty Track; see description below
-
- private long tick;
-
- Track() {
- /*
- * create an empty Track; new Track must contain only meta-event End of Track.
- * MetaMessage with MetaMessage.data contains -1, 47 and 0 is meta-event
- */
- events = new ArrayList<MidiEvent>();
- events.add(new MidiEvent(new MetaMessage(new byte[] {-1, 47, 0}), 0));
- }
- public boolean add(MidiEvent event) {
- //FIXME
- /*
- * Some words about badEvent.
- * When I write tests, I find following situation in the RI:
- * if I want to add to empty Track new event that is not meta-event End of Track,
- * I catch exception ArrayIndexOutOfBoundsException with meaning -1, and my
- * event doesn't add to Track, but meta-event adds. If I try to add the same
- * event after it, method Track.add(MidiEvent) return 'false', and my event
- * doesn't add again. So, I want to delete this event and use method
- * Track.remove(MidiEvent) for it, but it return 'false' too! And only after
- * this "shamanism" I can add this event to Track normally.
- * And only for this situation I use variable badEvent.
- *
- * See test org.apache.harmony.sound.tests.javax.sound.midi.TrackTest
- * for more details
- */
-
- /*
- * if event equals null or badEvent, this method return 'false'
- */
- if (event == null || event == badEvent) {
- return false;
- }
- /*
- * If event equals meta-event End of Track and Track in this moment
- * doesn't contain some events, i.e. Track.size() return 0, this
- * event accrue to Track;
- * if Track is not empty, but it doesn't contain meta-event,
- * this event accrue to the end of Track;
- * in any case addition of this meta-event is successful, this method
- * return 'true' even if meta-event End of Track already contains in the Track
- */
- if (event.getMessage().getMessage()[0] == -1 &&
- event.getMessage().getMessage()[1] == 47 &&
- event.getMessage().getMessage()[2] == 0 ) {
- if (events.size() == 0) {
- return events.add(event);
- }
- byte[] bt = events.get(events.size() - 1).getMessage().getMessage();
- if ((bt[0] != -1) && (bt[1] != 47) && (bt[2] != 0)) {
- return events.add(event);
- }
- return true;
- }
- /*
- * after use method Track.add(MidiEvent) Track must contain meta-event
- * End of Track; so, at first I add this event to Track if it doesn't
- * contain meta-event and parameter 'event' is not meta-event
- */
- if (events.size() == 0) {
- events.add(new MidiEvent(new MetaMessage(new byte[] {-1, 47, 0}), 0));
- badEvent = event;
- // sounds.01=-1
- throw new ArrayIndexOutOfBoundsException(Messages.getString("sound.01")); //$NON-NLS-1$
- }
- byte[] bt = events.get(events.size() - 1).getMessage().getMessage();
- if ((bt[0] != -1) && (bt[1] != 47) && (bt[2] != 0)) {
- events.add(new MidiEvent(new MetaMessage(new byte[] {-1, 47, 0}), 0));
- }
-
- if (events.contains(event)) {
- return false;
- }
-
- /*
- * events in the Track must take up position in ascending ticks
- */
- if (events.size() == 1) {
- events.add(0, event);
- }
- for (int i = 0; i < events.size() - 1; i++ ) {
- if (events.get(i).getTick() <= event.getTick()) {
- continue;
- }
- events.add(i, event);
- break;
- }
- /*
- * method Track.ticks() return the biggest value of tick of all events
- * and save it even I remove event with the biggest values of tick
- */
- if (tick < event.getTick()) {
- tick = event.getTick();
- }
- return true;
- }
-
- public MidiEvent get(int index) throws ArrayIndexOutOfBoundsException {
- if (index < 0 || index >= events.size()) {
- // sound.02=Index: {0}, Size: {1}
- throw new ArrayIndexOutOfBoundsException(Messages.getString("sound.02", index, events.size())); //$NON-NLS-1$
- }
- return events.get(index);
- }
-
- public boolean remove(MidiEvent event) {
- /*
- * if I remove event that equals badEvent, I "delete" badEvent
- */
- if (event == badEvent) {
- badEvent = null;
- return false;
- }
- /*
- * method Track.ticks() always return the biggest value that ever has been
- * in the Track; so only when Track is empty Track.ticks() return 0
- */
- if (events.remove(event)) {
- if (events.size() == 0) {
- tick = 0;
- }
- return true;
- }
- return false;
- }
-
- public int size() {
- return events.size();
- }
-
- public long ticks() {
- return tick;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Transmitter.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Transmitter.java
deleted file mode 100644
index 1e89197..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Transmitter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Transmitter {
- void close();
-
- Receiver getReceiver();
-
- void setReceiver(Receiver receiver);
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/VoiceStatus.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/VoiceStatus.java
deleted file mode 100644
index 370f48e..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/VoiceStatus.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class VoiceStatus {
- public boolean active;
-
- public int bank;
-
- public int channel;
-
- public int note;
-
- public int program;
-
- public int volume;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiDeviceProvider.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiDeviceProvider.java
deleted file mode 100644
index 6112ec7..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiDeviceProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiDevice.Info;
-
-public abstract class MidiDeviceProvider {
-
- public abstract MidiDevice getDevice(MidiDevice.Info info);
-
- public abstract MidiDevice.Info[] getDeviceInfo();
-
- public boolean isDeviceSupported(MidiDevice.Info info) {
- MidiDevice.Info[] devices = getDeviceInfo();
- for (Info element : devices) {
- if (info.equals(element)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileReader.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileReader.java
deleted file mode 100644
index 0d61181..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileReader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MidiFileFormat;
-import javax.sound.midi.Sequence;
-
-public abstract class MidiFileReader {
-
- public abstract MidiFileFormat getMidiFileFormat(File file)
- throws InvalidMidiDataException, IOException;
-
- public abstract MidiFileFormat getMidiFileFormat(InputStream stream)
- throws InvalidMidiDataException, IOException;
-
- public abstract MidiFileFormat getMidiFileFormat(URL url)
- throws InvalidMidiDataException, IOException;
-
- public abstract Sequence getSequence(File file)
- throws InvalidMidiDataException, IOException;
-
- public abstract Sequence getSequence(InputStream stream)
- throws InvalidMidiDataException, IOException;
-
- public abstract Sequence getSequence(URL url)
- throws InvalidMidiDataException, IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileWriter.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileWriter.java
deleted file mode 100644
index e47d17c..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileWriter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import javax.sound.midi.Sequence;
-
-public abstract class MidiFileWriter {
-
- public abstract int[] getMidiFileTypes();
-
- public abstract int[] getMidiFileTypes(Sequence sequence);
-
- public boolean isFileTypeSupported(int fileType) {
- int[] supported = getMidiFileTypes();
- for (int element : supported) {
- if (fileType == element) {
- return true;
- }
- }
- return false;
- }
-
- public boolean isFileTypeSupported(int fileType, Sequence sequence) {
- int[] supported = getMidiFileTypes(sequence);
- for (int element : supported) {
- if (fileType == element) {
- return true;
- }
- }
- return false;
- }
-
- public abstract int write(Sequence in, int fileType, File out)
- throws IOException;
-
- public abstract int write(Sequence in, int fileType, OutputStream out)
- throws IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/SoundbankReader.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/SoundbankReader.java
deleted file mode 100644
index 4fd195a..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/SoundbankReader.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.Soundbank;
-
-public abstract class SoundbankReader {
-
- public abstract Soundbank getSoundbank(File file)
- throws InvalidMidiDataException, IOException;
-
- public abstract Soundbank getSoundbank(InputStream stream)
- throws InvalidMidiDataException, IOException;
-
- public abstract Soundbank getSoundbank(URL url)
- throws InvalidMidiDataException, IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFileFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFileFormat.java
deleted file mode 100644
index ce476f1..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFileFormat.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class AudioFileFormat {
-
- private AudioFileFormat.Type type;
- private int byteLength = AudioSystem.NOT_SPECIFIED;
- private AudioFormat format;
- private int frameLength;
- private HashMap<String, Object> prop;
-
- protected AudioFileFormat(AudioFileFormat.Type type,
- int byteLength,
- AudioFormat format,
- int frameLength) {
- this.type = type;
- this.byteLength = byteLength;
- this.format = format;
- this.frameLength = frameLength;
- }
-
- public AudioFileFormat(AudioFileFormat.Type type,
- AudioFormat format,
- int frameLength) {
- this.type = type;
- this.format = format;
- this.frameLength = frameLength;
- }
-
- public AudioFileFormat(AudioFileFormat.Type type,
- AudioFormat format,
- int frameLength,
- Map<String,Object> properties) {
- this.type = type;
- this.format = format;
- this.frameLength = frameLength;
- prop = new HashMap<String, Object>();
- prop.putAll(properties);
- }
-
- public AudioFileFormat.Type getType() {
- return type;
- }
-
- public int getByteLength() {
- return byteLength;
- }
-
- public AudioFormat getFormat() {
- return format;
- }
-
- public int getFrameLength() {
- return frameLength;
- }
-
- public Map<String,Object> properties() {
- if (prop == null) {
- return null;
- }
- return Collections.unmodifiableMap(prop);
- }
-
- public Object getProperty(String key) {
- if (prop == null) {
- return null;
- }
- return prop.get(key);
- }
-
- public String toString() {
- return type + " (." + type.getExtension() + ") file, data format: " + format + //$NON-NLS-1$ //$NON-NLS-2$
- " frame length: " + frameLength; //$NON-NLS-1$
- }
-
- public static class Type {
-
- private String name;
-
- private String extension;
-
- public static final Type AIFC = new Type("AIFF-C", "aifc"); //$NON-NLS-1$ //$NON-NLS-2$
-
- public static final Type AIFF = new Type("AIFF", "aif"); //$NON-NLS-1$ //$NON-NLS-2$
-
- public static final Type AU = new Type("AU", "au"); //$NON-NLS-1$ //$NON-NLS-2$
-
- public static final Type SND = new Type("SND", "snd"); //$NON-NLS-1$ //$NON-NLS-2$
-
- public static final Type WAVE = new Type("WAVE", "wav"); //$NON-NLS-1$ //$NON-NLS-2$
-
- public Type(String name, String extension) {
- this.name = name;
- this.extension = extension;
- }
-
- /*
- * according to the spec it should return true when objects are same but
- * RI seem to compare internals
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public final boolean equals(Object another) {
- if (this == another) {
- return true;
- }
-
- if (another == null || !(another instanceof Type)) {
- return false;
- }
-
- Type obj = (Type) another;
- return (name == null ? obj.name == null : name.equals(obj.name))
- && (extension == null ? obj.extension == null : extension
- .equals(obj.extension));
- }
-
- public String getExtension() {
- return extension;
- }
-
- @Override
- public final int hashCode() {
- return (name == null ? 0 : name.hashCode()) +
- (extension == null ? 0 : extension.hashCode());
- }
-
- @Override
- public final String toString() {
- return name;
- }
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFormat.java
deleted file mode 100644
index 721ed6a..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFormat.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class AudioFormat {
- public static class Encoding {
-
- public static final Encoding ALAW = new Encoding("ALAW"); //$NON-NLS-1$
-
- public static final Encoding PCM_SIGNED = new Encoding("PCM_SIGNED"); //$NON-NLS-1$
-
- public static final Encoding PCM_UNSIGNED = new Encoding("PCM_UNSIGNED"); //$NON-NLS-1$
-
- public static final Encoding ULAW = new Encoding("ULAW"); //$NON-NLS-1$
-
- private String name;
-
- public Encoding(String name) {
- this.name = name;
- }
-
- @Override
- public boolean equals(Object another) {
- if (this == another) {
- return true;
- }
-
- if (another == null || !(another instanceof Encoding)) {
- return false;
- }
-
- Encoding obj = (Encoding) another;
- return name == null ? obj.name == null : name.equals(obj.name);
- }
-
- @Override
- public final int hashCode() {
- return name == null ? 0 : name.hashCode();
- }
-
- @Override
- public final String toString() {
- return name;
- }
- }
-
- protected boolean bigEndian;
-
- protected int channels;
-
- protected Encoding encoding;
-
- protected float frameRate;
-
- protected int frameSize;
-
- protected float sampleRate;
-
- protected int sampleSizeInBits;
-
- private HashMap<String, Object> prop;
-
- public AudioFormat(AudioFormat.Encoding encoding,
- float sampleRate,
- int sampleSizeInBits,
- int channels,
- int frameSize,
- float frameRate,
- boolean bigEndian) {
-
- this.encoding = encoding;
- this.sampleRate = sampleRate;
- this.sampleSizeInBits = sampleSizeInBits;
- this.channels = channels;
- this.frameSize = frameSize;
- this.frameRate = frameRate;
- this.bigEndian = bigEndian;
-
- }
-
- public AudioFormat(AudioFormat.Encoding encoding,
- float sampleRate,
- int sampleSizeInBits,
- int channels,
- int frameSize,
- float frameRate,
- boolean bigEndian,
- Map<String,Object> properties) {
-
- this.encoding = encoding;
- this.sampleRate = sampleRate;
- this.sampleSizeInBits = sampleSizeInBits;
- this.channels = channels;
- this.frameSize = frameSize;
- this.frameRate = frameRate;
- this.bigEndian = bigEndian;
- prop = new HashMap<String, Object>();
- prop.putAll(properties);
-
- }
-
- public AudioFormat(float sampleRate,
- int sampleSizeInBits,
- int channels,
- boolean signed,
- boolean bigEndian) {
-
- this.encoding = (signed? Encoding.PCM_SIGNED : Encoding.PCM_UNSIGNED);
- this.sampleRate = sampleRate;
- this.sampleSizeInBits = sampleSizeInBits;
- this.channels = channels;
- this.frameSize = sampleSizeInBits >> 3;
- if ((sampleSizeInBits & 0x7) != 0) {
- this.frameSize++;
- }
- this.frameSize *= channels;
- this.frameRate = sampleRate;
- this.bigEndian = bigEndian;
-
- }
-
- public Encoding getEncoding() {
- return encoding;
- }
-
- public float getSampleRate() {
- return sampleRate;
- }
-
- public int getSampleSizeInBits() {
- return sampleSizeInBits;
- }
-
- public int getChannels() {
- return channels;
- }
-
- public int getFrameSize() {
- return frameSize;
- }
-
- public float getFrameRate() {
- return frameRate;
- }
-
- public boolean isBigEndian() {
- return bigEndian;
- }
-
- public Map<String,Object> properties() {
- if (prop != null) {
- return Collections.unmodifiableMap(prop);
- } else {
- return Collections.emptyMap();
- }
- }
-
- public Object getProperty(String key) {
- if (prop == null) {
- return null;
- }
- return prop.get(key);
- }
-
- public boolean matches(AudioFormat format) {
- if (!encoding.equals(format.getEncoding()) ||
- channels != format.getChannels() ||
- sampleSizeInBits != format.getSampleSizeInBits() ||
- frameSize != format.getFrameSize()) {
- return false;
- }
- if (format.getSampleRate() != AudioSystem.NOT_SPECIFIED &&
- sampleRate != format.getSampleRate()) {
- return false;
- }
-
- if (format.getFrameRate() != AudioSystem.NOT_SPECIFIED &&
- frameRate != format.getFrameRate()) {
- return false;
- }
-
- if ((sampleSizeInBits > 8)
- && (bigEndian != format.isBigEndian())) {
- return false;
- }
- return true;
-
- }
-
- public String toString() {
-
- String ch;
- switch (channels) {
- case 1:
- ch = "mono,"; //$NON-NLS-1$
- break;
- case 2:
- ch = "stereo,"; //$NON-NLS-1$
- default:
- ch = channels + " channels, "; //$NON-NLS-1$
- }
-
- return encoding + " " + sampleRate + " Hz, " + sampleSizeInBits + " bit, " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- + ch + frameSize + " bytes/frame, " + frameRate + " frames/second"; //$NON-NLS-1$ //$NON-NLS-2$
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioInputStream.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioInputStream.java
deleted file mode 100644
index 3105f94..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioInputStream.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class AudioInputStream extends InputStream {
-
- protected AudioFormat format;
-
- protected long frameLength;
-
- protected long framePos;
-
- protected int frameSize;
-
- private InputStream stream;
-
- private TargetDataLine line;
-
- private byte[] oneByte = new byte[1];
-
- private long marketFramePos;
-
- public AudioInputStream(InputStream stream, AudioFormat format, long length) {
- this.stream = stream;
- this.format = format;
- this.frameLength = length;
- this.frameSize = format.getFrameSize();
- }
-
- public AudioInputStream(TargetDataLine line) {
- this.line = line;
- this.format = line.getFormat();
- this.frameLength = AudioSystem.NOT_SPECIFIED; //TODO
- this.frameSize = this.format.getFrameSize();
- }
-
- public AudioFormat getFormat() {
- return format;
- }
-
- public long getFrameLength() {
- return frameLength;
- }
-
- public int read() throws IOException {
- if (frameSize != 1) {
- // sound.0C=Frame size must be one byte
- throw new IOException(Messages.getString("sound.0C")); //$NON-NLS-1$
- }
- int res;
- if (stream != null) { // InputStream
- if (framePos == frameLength) {
- return 0;
- }
- res = stream.read();
- if (res == -1) {
- return -1;
- }
- framePos += 1;
- return res;
- } else { // TargetDataLine
- if (line.read(oneByte, 0, 1) == 0) {
- return -1;
- }
- framePos = line.getLongFramePosition();
- return oneByte[0];
- }
- }
-
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- public int read(byte[] b, int off, int len) throws IOException {
- int l = Math.min(len, (int) ((frameLength - framePos) * frameSize));
- l = l - (l % frameSize);
- if (l == 0) {
- return 0;
- }
- int res;
- if (stream != null) { // InputStream
- res = stream.read(b, off, l);
- if (res == -1) {
- return -1;
- }
- framePos = framePos + res / frameSize;
- return res;
- } else { // TargetDataLine
- res = line.read(b, off, l);
- if (res == 0) {
- return -1;
- }
- framePos = line.getLongFramePosition();
- return res;
- }
-
- }
-
- public long skip(long n) throws IOException {
-
- if (n < frameSize) {
- return 0;
- }
- byte[] skipBuf = new byte[frameSize];
- long skipped = 0;
- while (skipped < n) {
- int read = read(skipBuf, 0, frameSize);
- if (read == -1) {
- return skipped;
- }
- skipped += read;
- if (n - skipped < frameSize) {
- return skipped;
- }
- }
- return skipped;
-
- }
-
- public int available() throws IOException {
- if (stream != null) { // InputStream
- return Math.min(stream.available(),
- (int)((frameLength - framePos) * frameSize));
- } else { // TargetDataLine
- return line.available();
- }
- }
-
- public void close() throws IOException {
- if (stream != null) { // InputStream
- stream.close();
- } else { // TargetDataLine
- line.close();
- }
- }
-
- public void mark(int readlimit) {
- if (stream != null) { //InputStream
- stream.mark(readlimit);
- marketFramePos = framePos;
- } else { // TargetDataLine
- // do nothing
- }
- }
-
- public void reset() throws IOException {
- if (stream != null) { //InputStream
- stream.reset();
- framePos = marketFramePos;
- } else { // TargetDataLine
- // do nothing
- }
- }
-
- public boolean markSupported() {
- if (stream != null) { //InputStream
- return stream.markSupported();
- } else { // TargetDataLine
- return false;
- }
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioPermission.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioPermission.java
deleted file mode 100644
index 04ddd94..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioPermission.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.security.BasicPermission;
-
-public class AudioPermission extends BasicPermission {
-
- private static final long serialVersionUID = -5518053473477801126L;
-
- public AudioPermission(String name) {
- super(name);
- }
-
- public AudioPermission(String name, String actions) {
- super(name, actions);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioSystem.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioSystem.java
deleted file mode 100644
index c279c17..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioSystem.java
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Iterator;
-import java.util.Properties;
-
-import javax.sound.sampled.spi.AudioFileReader;
-import javax.sound.sampled.spi.AudioFileWriter;
-import javax.sound.sampled.spi.FormatConversionProvider;
-import javax.sound.sampled.spi.MixerProvider;
-
-import org.apache.harmony.sound.utils.ProviderService;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class AudioSystem {
-
- public static final int NOT_SPECIFIED = -1;
-
- private final static String audioFileReaderPath = "META-INF/services/javax.sound.sampled.spi.AudioFileReader"; //$NON-NLS-1$
-
- private final static String audioFileWriterPath = "META-INF/services/javax.sound.sampled.spi.AudioFileWriter"; //$NON-NLS-1$
-
- private final static String formatConversionProviderPath = "META-INF/services/javax.sound.sampled.spi.FormatConversionProvider"; //$NON-NLS-1$
-
- private final static String mixerProviderPath = "META-INF/services/javax.sound.sampled.spi.MixerProvider"; //$NON-NLS-1$
-
- private final static String CLIP = "javax.sound.sampled.Clip"; //$NON-NLS-1$
-
- private final static String PORT = "javax.sound.sampled.Port"; //$NON-NLS-1$
-
- private final static String SOURCEDATALINE = "javax.sound.sampled.SourceDataLine"; //$NON-NLS-1$
-
- private final static String TARGETDATALINE = "javax.sound.sampled.TargetDataLine"; //$NON-NLS-1$
-
- public static Mixer.Info[] getMixerInfo() {
- List<Mixer.Info> result = new ArrayList<Mixer.Info>();
- for (Iterator providers = ProviderService.getProviders(
- mixerProviderPath).iterator(); providers.hasNext();) {
- try {
- Mixer.Info[] infos = ((MixerProvider) (providers.next()))
- .getMixerInfo();
- for (Mixer.Info info : infos) {
- result.add(info);
- }
- } catch (ClassCastException e) {}
- }
- Mixer.Info[] temp = new Mixer.Info[result.size()];
- return result.toArray(temp);
- }
-
- public static Mixer getMixer(Mixer.Info info) {
- Mixer.Info[] infos;
- Mixer.Info inf;
- if (info == null) {
- infos = getMixerInfo();
- if (infos == null) {
- throw new IllegalArgumentException(
- "No system default mixer installed"); //$NON-NLS-1$
- }
- inf = infos[0];
- } else {
- inf = info;
- }
-
- for (Iterator providers = ProviderService.getProviders(
- mixerProviderPath).iterator(); providers.hasNext();) {
- try {
- return ((MixerProvider) (providers.next())).getMixer(inf);
- } catch (ClassCastException e) {} catch (IllegalArgumentException e) {}
- }
- throw new IllegalArgumentException("Mixer not supported: " + inf); //$NON-NLS-1$
- }
-
- public static Line.Info[] getSourceLineInfo(Line.Info info) {
- List<Line.Info> result = new ArrayList<Line.Info>();
- for (Iterator providers = ProviderService.getProviders(
- mixerProviderPath).iterator(); providers.hasNext();) {
- try {
- MixerProvider pr = (MixerProvider) providers.next();
- Mixer.Info[] mixinfos = pr.getMixerInfo();
- for (Mixer.Info mixinfo : mixinfos) {
- Mixer mix = pr.getMixer(mixinfo);
- Line.Info[] linfos = mix.getSourceLineInfo(info);
- for (Line.Info linfo : linfos) {
- result.add(linfo);
- }
- }
- } catch (ClassCastException e) {}
- }
- Line.Info[] temp = new Line.Info[result.size()];
- return result.toArray(temp);
- }
-
- public static Line.Info[] getTargetLineInfo(Line.Info info) {
- List<Line.Info> result = new ArrayList<Line.Info>();
- for (Iterator providers = ProviderService.getProviders(
- mixerProviderPath).iterator(); providers.hasNext();) {
- try {
- MixerProvider pr = (MixerProvider) providers.next();
- Mixer.Info[] mixinfos = pr.getMixerInfo();
- for (Mixer.Info mixinfo : mixinfos) {
- Mixer mix = pr.getMixer(mixinfo);
- Line.Info[] linfos = mix.getTargetLineInfo(info);
- for (Line.Info linfo : linfos) {
- result.add(linfo);
- }
- }
- } catch (ClassCastException e) {}
- }
- Line.Info[] temp = new Line.Info[result.size()];
- return result.toArray(temp);
- }
-
- public static boolean isLineSupported(Line.Info info) {
-
- for (Iterator providers = ProviderService.getProviders(
- mixerProviderPath).iterator(); providers.hasNext();) {
- try {
- MixerProvider pr = (MixerProvider) providers.next();
- Mixer.Info[] mixinfos = pr.getMixerInfo();
- for (Mixer.Info mixinfo : mixinfos) {
- Mixer mix = pr.getMixer(mixinfo);
- if (mix.isLineSupported(info)) {
- return true;
- }
- }
- } catch (ClassCastException e) {}
- }
- return false;
- }
-
- private static Mixer getMixer(String propVal, Line.Info info,
- List<?> mixerProviders) {
-
- int index = propVal.indexOf("#"); //$NON-NLS-1$
- String className;
- String mixName;
- if (index == -1) {
- className = propVal.trim();
- mixName = ""; //$NON-NLS-1$
- } else {
- className = propVal.substring(0, index).trim();
- if (index == propVal.length()) {
- mixName = ""; //$NON-NLS-1$
- } else {
- mixName = propVal.substring(index + 1).trim();
- }
- }
- Mixer.Info[] minfos = null;
- if (!className.equals("")) { //$NON-NLS-1$
- for (Iterator providers = mixerProviders.iterator(); providers
- .hasNext();) {
- try {
- MixerProvider pr = (MixerProvider) (providers.next());
- if (className.equals(pr.getClass().getName())) {
- minfos = pr.getMixerInfo();
- break;
- }
- } catch (ClassCastException e) {}
- }
- }
- if (minfos == null) {
- minfos = getMixerInfo();
- }
-
- if (!mixName.equals("")) { //$NON-NLS-1$
- for (Mixer.Info minfo : minfos) {
- if (mixName.equals(minfo.getName())) {
- return getMixer(minfo);
- }
- }
- }
- if (minfos.length > 0) {
- return getMixer(minfos[0]);
- }
- return null;
- }
-
- public static Line getLine(Line.Info info) throws LineUnavailableException {
- String propName = null;
- Class lineClass = info.getLineClass();
-
- if (Clip.class.isAssignableFrom(lineClass)) {
- propName = CLIP;
- } else if (Port.class.isAssignableFrom(lineClass)) {
- propName = PORT;
- } else if (SourceDataLine.class.isAssignableFrom(lineClass)) {
- propName = SOURCEDATALINE;
- } else if (TargetDataLine.class.isAssignableFrom(lineClass)) {
- propName = TARGETDATALINE;
- }
- return getLine(propName, info);
- }
-
- private static Line getLine(String propName, Line.Info info)
- throws LineUnavailableException {
-
- List<?> mixerProviders = ProviderService
- .getProviders(mixerProviderPath);
-
- if (propName != null) {
- String propVal = System.getProperty(propName);
- if (propVal != null) {
- Mixer m = getMixer(propVal, info, mixerProviders);
- if (m != null) {
- Line l = m.getLine(info);
- if (l != null) {
- return l;
- }
- }
- }
-
- Properties soundProperties = ProviderService.getSoundProperties();
- propVal = soundProperties.getProperty(propName);
- if (propVal != null) {
- Mixer m = getMixer(propVal, info, mixerProviders);
- if (m != null) {
- Line l = m.getLine(info);
- if (l != null) {
- return l;
- }
- }
- }
- }
-
- for (Iterator providers = ProviderService.getProviders(
- mixerProviderPath).iterator(); providers.hasNext();) {
- try {
- MixerProvider pr = (MixerProvider) (providers.next());
- Mixer.Info[] mixinfos = pr.getMixerInfo();
- for (Mixer.Info mixinfo : mixinfos) {
- try {
- Mixer mix = pr.getMixer(mixinfo);
- return mix.getLine(info);
- } catch (IllegalArgumentException e) {
- // continue
- }
- }
- } catch (ClassCastException e) {}
- }
-
- // BEGIN android-added
- if (CLIP.equals(propName)) {
- try {
- return (Clip)(Class.forName("com.android.internal.sound.sampled.AndroidClip").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- }
- // END android-added
-
- // sound.11=Could not get line
- throw new IllegalArgumentException(Messages.getString("sound.11")); //$NON-NLS-1$
- }
-
- public static Clip getClip() throws LineUnavailableException {
- return (Clip) getLine(new Line.Info(Clip.class));
- }
-
- public static Clip getClip(Mixer.Info mixerInfo)
- throws LineUnavailableException {
- return (Clip) (getMixer(mixerInfo).getLine(new Line.Info(Clip.class)));
- }
-
- public static SourceDataLine getSourceDataLine(AudioFormat format)
- throws LineUnavailableException {
- SourceDataLine line = (SourceDataLine) getLine(new Line.Info(
- SourceDataLine.class));
- line.open(format);
- return line;
- }
-
- public static SourceDataLine getSourceDataLine(AudioFormat format,
- Mixer.Info mixerinfo) throws LineUnavailableException {
-
- SourceDataLine line = (SourceDataLine) getMixer(mixerinfo).getLine(
- new Line.Info(SourceDataLine.class));
- line.open(format);
- return line;
- }
-
- public static TargetDataLine getTargetDataLine(AudioFormat format)
- throws LineUnavailableException {
- TargetDataLine line = (TargetDataLine) getLine(new Line.Info(
- TargetDataLine.class));
- line.open(format);
- return line;
- }
-
- public static TargetDataLine getTargetDataLine(AudioFormat format,
- Mixer.Info mixerinfo) throws LineUnavailableException {
-
- TargetDataLine line = (TargetDataLine) getMixer(mixerinfo).getLine(
- new Line.Info(TargetDataLine.class));
- line.open(format);
- return line;
- }
-
- public static AudioFormat.Encoding[] getTargetEncodings(
- AudioFormat.Encoding sourceEncoding) {
-
- List<AudioFormat.Encoding> result = new ArrayList<AudioFormat.Encoding>();
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- try {
- FormatConversionProvider pr = (FormatConversionProvider) providers
- .next();
- if (!pr.isSourceEncodingSupported(sourceEncoding)) {
- continue;
- }
- AudioFormat.Encoding[] encodings = pr.getTargetEncodings();
- for (AudioFormat.Encoding encoding : encodings) {
- result.add(encoding);
- }
- } catch (ClassCastException e) {}
- }
- AudioFormat.Encoding[] temp = new AudioFormat.Encoding[result.size()];
- return result.toArray(temp);
- }
-
- public static AudioFormat.Encoding[] getTargetEncodings(
- AudioFormat sourceFormat) {
-
- List<AudioFormat.Encoding> result = new ArrayList<AudioFormat.Encoding>();
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- try {
- AudioFormat.Encoding[] encodings = ((FormatConversionProvider) (providers
- .next())).getTargetEncodings(sourceFormat);
- for (AudioFormat.Encoding encoding : encodings) {
- result.add(encoding);
- }
- } catch (ClassCastException e) {}
- }
- AudioFormat.Encoding[] temp = new AudioFormat.Encoding[result.size()];
- return result.toArray(temp);
- }
-
- public static boolean isConversionSupported(
- AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
-
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- if (((FormatConversionProvider) (providers.next()))
- .isConversionSupported(targetEncoding, sourceFormat)) {
- return true;
- }
- }
- return false;
- }
-
- public static AudioInputStream getAudioInputStream(
- AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream) {
-
- if (sourceStream.getFormat().getEncoding().equals(targetEncoding)) {
- return sourceStream;
- }
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- try {
- return ((FormatConversionProvider) (providers.next()))
- .getAudioInputStream(targetEncoding, sourceStream);
- } catch (ClassCastException e) {} catch (IllegalArgumentException e) {}
- }
- // sound.12=Could not get audio input stream from source stream
- throw new IllegalArgumentException(Messages.getString("sound.12")); //$NON-NLS-1$
- }
-
- public static AudioFormat[] getTargetFormats(
- AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
-
- List<AudioFormat> result = new ArrayList<AudioFormat>();
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- try {
- AudioFormat[] formats = ((FormatConversionProvider) (providers
- .next()))
- .getTargetFormats(targetEncoding, sourceFormat);
- for (AudioFormat format : formats) {
- result.add(format);
- }
- } catch (ClassCastException e) {}
- }
- AudioFormat[] temp = new AudioFormat[result.size()];
- return result.toArray(temp);
- }
-
- public static boolean isConversionSupported(AudioFormat targetFormat,
- AudioFormat sourceFormat) {
-
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- if (((FormatConversionProvider) (providers.next()))
- .isConversionSupported(targetFormat, sourceFormat)) {
- return true;
- }
- }
- return false;
- }
-
- public static AudioInputStream getAudioInputStream(
- AudioFormat targetFormat, AudioInputStream sourceStream) {
-
- if (sourceStream.getFormat().matches(targetFormat)) {
- return sourceStream;
- }
- for (Iterator providers = ProviderService.getProviders(
- formatConversionProviderPath).iterator(); providers.hasNext();) {
- try {
- return ((FormatConversionProvider) (providers.next()))
- .getAudioInputStream(targetFormat, sourceStream);
- } catch (ClassCastException e) {} catch (IllegalArgumentException e) {}
- }
- // sound.13=Could not get audio input stream from source stream
- throw new IllegalArgumentException(Messages.getString("sound.13")); //$NON-NLS-1$
- }
-
- public static AudioFileFormat getAudioFileFormat(InputStream stream)
- throws UnsupportedAudioFileException, IOException {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileReaderPath).iterator(); providers.hasNext();) {
- try {
- return ((AudioFileReader) (providers.next()))
- .getAudioFileFormat(stream);
- } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
- }
- // sound.14=File is not a supported file type
- throw new UnsupportedAudioFileException(Messages.getString("sound.14")); //$NON-NLS-1$
- }
-
- public static AudioFileFormat getAudioFileFormat(URL url)
- throws UnsupportedAudioFileException, IOException {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileReaderPath).iterator(); providers.hasNext();) {
- try {
- return ((AudioFileReader) (providers.next()))
- .getAudioFileFormat(url);
- } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
- }
- // sound.14=File is not a supported file type
- throw new UnsupportedAudioFileException(Messages.getString("sound.14")); //$NON-NLS-1$
- }
-
- public static AudioFileFormat getAudioFileFormat(File file)
- throws UnsupportedAudioFileException, IOException {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileReaderPath).iterator(); providers.hasNext();) {
- try {
- return ((AudioFileReader) (providers.next()))
- .getAudioFileFormat(file);
- } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
- }
- // sound.14=File is not a supported file type
- throw new UnsupportedAudioFileException(Messages.getString("sound.14")); //$NON-NLS-1$
- }
-
- public static AudioInputStream getAudioInputStream(InputStream stream)
- throws UnsupportedAudioFileException, IOException {
-
- if (stream instanceof AudioInputStream) {
- return (AudioInputStream) stream;
- }
- for (Iterator providers = ProviderService.getProviders(
- audioFileReaderPath).iterator(); providers.hasNext();) {
- try {
- return ((AudioFileReader) (providers.next()))
- .getAudioInputStream(stream);
- } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
- }
- // BEGIN android-added
- try {
- AudioFileReader reader = (AudioFileReader)(Class.forName("com.android.internal.sound.sampled.AndroidAudioFileReader").newInstance());
- return reader.getAudioInputStream(stream);
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- // sound.15=Could not get audio input stream from input stream
- throw new UnsupportedAudioFileException(Messages.getString("sound.15")); //$NON-NLS-1$
- }
-
- public static AudioInputStream getAudioInputStream(URL url)
- throws UnsupportedAudioFileException, IOException {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileReaderPath).iterator(); providers.hasNext();) {
- try {
- return ((AudioFileReader) (providers.next()))
- .getAudioInputStream(url);
- } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
- }
- // BEGIN android-added
- try {
- AudioFileReader reader = (AudioFileReader)(Class.forName("com.android.internal.sound.sampled.AndroidAudioFileReader").newInstance());
- return reader.getAudioInputStream(url);
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- // sound.16=Could not get audio input stream from input URL
- throw new UnsupportedAudioFileException(Messages.getString("sound.16")); //$NON-NLS-1$
- }
-
- public static AudioInputStream getAudioInputStream(File file)
- throws UnsupportedAudioFileException, IOException {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileReaderPath).iterator(); providers.hasNext();) {
- try {
- return ((AudioFileReader) (providers.next()))
- .getAudioInputStream(file);
- } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
- }
- // BEGIN android-added
- try {
- AudioFileReader reader = (AudioFileReader)(Class.forName("com.android.internal.sound.sampled.AndroidAudioFileReader").newInstance());
- return reader.getAudioInputStream(file);
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- // sound.17=Could not get audio input stream from input file
- throw new UnsupportedAudioFileException(Messages.getString("sound.17")); //$NON-NLS-1$
- }
-
- public static AudioFileFormat.Type[] getAudioFileTypes() {
- List<AudioFileFormat.Type> result = new ArrayList<AudioFileFormat.Type>();
- for (Iterator providers = ProviderService.getProviders(
- audioFileWriterPath).iterator(); providers.hasNext();) {
- try {
- AudioFileFormat.Type[] types = ((AudioFileWriter) (providers
- .next())).getAudioFileTypes();
- for (AudioFileFormat.Type type : types) {
- result.add(type);
- }
- } catch (ClassCastException e) {}
- }
- AudioFileFormat.Type[] temp = new AudioFileFormat.Type[result.size()];
- return result.toArray(temp);
- }
-
- public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileWriterPath).iterator(); providers.hasNext();) {
- if (((AudioFileWriter) (providers.next()))
- .isFileTypeSupported(fileType)) {
- return true;
- }
- }
- return false;
- }
-
- public static AudioFileFormat.Type[] getAudioFileTypes(
- AudioInputStream stream) {
- List<AudioFileFormat.Type> result = new ArrayList<AudioFileFormat.Type>();
- for (Iterator providers = ProviderService.getProviders(
- audioFileWriterPath).iterator(); providers.hasNext();) {
- try {
- AudioFileFormat.Type[] types = ((AudioFileWriter) (providers
- .next())).getAudioFileTypes(stream);
- for (AudioFileFormat.Type type : types) {
- result.add(type);
- }
- } catch (ClassCastException e) {}
- }
- AudioFileFormat.Type[] temp = new AudioFileFormat.Type[result.size()];
- return result.toArray(temp);
- }
-
- public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
- AudioInputStream stream) {
-
- for (Iterator providers = ProviderService.getProviders(
- audioFileWriterPath).iterator(); providers.hasNext();) {
- if (((AudioFileWriter) (providers.next())).isFileTypeSupported(
- fileType, stream)) {
- return true;
- }
- }
- return false;
- }
-
- public static int write(AudioInputStream stream,
- AudioFileFormat.Type fileType, OutputStream out) throws IOException {
- AudioFileWriter writer;
- for (Iterator providers = ProviderService.getProviders(
- audioFileWriterPath).iterator(); providers.hasNext();) {
- writer = (AudioFileWriter) (providers.next());
- if (writer.isFileTypeSupported(fileType, stream)) {
- return writer.write(stream, fileType, out);
- }
- }
- // sound.18=Type is not supported
- throw new IllegalArgumentException(Messages.getString("sound.18")); //$NON-NLS-1$
- }
-
- public static int write(AudioInputStream stream,
- AudioFileFormat.Type fileType, File out) throws IOException {
- AudioFileWriter writer;
- for (Iterator providers = ProviderService.getProviders(
- audioFileWriterPath).iterator(); providers.hasNext();) {
- writer = (AudioFileWriter) (providers.next());
- if (writer.isFileTypeSupported(fileType, stream)) {
- return writer.write(stream, fileType, out);
- }
- }
- // sound.18=Type is not supported
- throw new IllegalArgumentException(Messages.getString("sound.18")); //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/BooleanControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/BooleanControl.java
deleted file mode 100644
index 5ab87fb..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/BooleanControl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public abstract class BooleanControl extends Control {
-
- public static class Type extends Control.Type {
- public static final Type APPLY_REVERB = new Type("Apply Reverb"); //$NON-NLS-1$
-
- public static final Type MUTE = new Type("Mute"); //$NON-NLS-1$
-
- protected Type(String name) {
- super(name);
- }
- }
-
- private boolean value;
-
- private String trueStateLabel;
-
- private String falseStateLabel;
-
- protected BooleanControl(BooleanControl.Type type, boolean initialValue,
- String trueStateLabel, String falseStateLabel) {
- super(type);
- this.value = initialValue;
- this.trueStateLabel = trueStateLabel;
- this.falseStateLabel = falseStateLabel;
- }
-
- protected BooleanControl(BooleanControl.Type type, boolean initialValue) {
- this(type, initialValue, "true", "false"); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- public void setValue(boolean value) {
- this.value = value;
- }
-
- public boolean getValue() {
- return this.value;
- }
-
- public String getStateLabel(boolean state) {
- if (state) {
- return this.trueStateLabel;
- } else {
- return this.falseStateLabel;
- }
- }
-
- public String toString() {
- return getType() + " Control with current value: " + getStateLabel(value); //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Clip.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Clip.java
deleted file mode 100644
index 0e65b59..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Clip.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.io.IOException;
-
-public interface Clip extends DataLine {
- static final int LOOP_CONTINUOUSLY = -1;
-
- int getFrameLength();
-
- long getMicrosecondLength();
-
- void loop(int count);
-
- void open(AudioFormat format, byte[] data, int offset, int bufferSize)
- throws LineUnavailableException;
-
- void open(AudioInputStream stream) throws LineUnavailableException,
- IOException;
-
- void setFramePosition(int frames);
-
- void setLoopPoints(int start, int end);
-
- void setMicrosecondPosition(long microseconds);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/CompoundControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/CompoundControl.java
deleted file mode 100644
index 5862761..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/CompoundControl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public abstract class CompoundControl extends Control {
- public static class Type extends Control.Type {
- protected Type(String name) {
- super(name);
- }
- }
-
- private Control[] memberControls;
-
- protected CompoundControl(CompoundControl.Type type,
- Control[] memberControls) {
- super(type);
- this.memberControls = memberControls;
- }
-
- public Control[] getMemberControls() {
- return this.memberControls;
- }
-
- public String toString() {
- return getType() + "CompoundControl containing " //$NON-NLS-1$
- + String.valueOf(memberControls) + " Controls."; //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Control.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Control.java
deleted file mode 100644
index b6128e8..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Control.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public abstract class Control {
-
- public static class Type {
-
- private String name;
-
- public Type(String name) {
- this.name = name;
- }
-
- @Override
- public boolean equals(Object another) {
- if (this == another) {
- return true;
- }
-
- if (another == null || !(another instanceof Type)) {
- return false;
- }
-
- Type obj = (Type) another;
- return name == null ? obj.name == null : name.equals(obj.name);
- }
-
- @Override
- public final int hashCode() {
- return name == null ? 0 : name.hashCode();
- }
-
- @Override
- public final String toString() {
- return name;
- }
- }
-
- private Type type;
-
- protected Control(Type type) {
- this.type = type;
- }
-
- public Type getType() {
- return type;
- }
-
- public String toString() {
- return type + " Control"; //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/DataLine.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/DataLine.java
deleted file mode 100644
index e37ea3f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/DataLine.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface DataLine extends Line {
-
- class Info extends Line.Info {
- private AudioFormat[] formats;
- private int minBufferSize;
- private int maxBufferSize;
-
- public Info(Class <?> lineClass, AudioFormat format) {
- super(lineClass);
-
- this.formats = new AudioFormat[] { format };
- this.minBufferSize = AudioSystem.NOT_SPECIFIED;
- this.maxBufferSize = AudioSystem.NOT_SPECIFIED;
- }
-
- public Info(Class <?> lineClass, AudioFormat[] formats, int minBufferSize, int maxBufferSize) {
- super(lineClass);
-
- this.formats = formats;
- this.minBufferSize = minBufferSize;
- this.maxBufferSize = maxBufferSize;
- }
-
- public Info(Class <?> lineClass, AudioFormat format, int bufferSize) {
- super(lineClass);
-
- this.formats = new AudioFormat[] { format };
- this.minBufferSize = bufferSize;
- this.maxBufferSize = bufferSize;
- }
-
- public AudioFormat[] getFormats(){
- return formats;
- }
-
- public boolean isFormatSupported(AudioFormat format) {
- if (formats == null) {
- return false;
- }
- for (AudioFormat supported : formats) {
- if (format.matches(supported)) {
- return true;
- }
- }
- return false;
- }
-
- public int getMinBufferSize() {
- return minBufferSize;
- }
-
- public int getMaxBufferSize() {
- return maxBufferSize;
- }
-
- @Override
- public boolean matches(Line.Info info) {
-
- if (!super.matches(info)) {
- return false;
- }
-
- DataLine.Info inf = (DataLine.Info)info;
- if ((minBufferSize != AudioSystem.NOT_SPECIFIED
- && inf.getMinBufferSize() != AudioSystem.NOT_SPECIFIED
- && minBufferSize < inf.getMinBufferSize())
- || (maxBufferSize != AudioSystem.NOT_SPECIFIED
- && inf.getMaxBufferSize() != AudioSystem.NOT_SPECIFIED
- && maxBufferSize > inf.getMaxBufferSize())) {
- return false;
- }
-
- for (AudioFormat supported : formats) {
- if (!inf.isFormatSupported(supported)) {
- return false;
- }
- }
-
- return true;
- }
-
- @Override
- public String toString() {
- String formatStr = (formats.length == 1? "format " + formats[0].toString() //$NON-NLS-1$
- : formats.length + " audio formats"); //$NON-NLS-1$
- String bufStr = ""; //$NON-NLS-1$
- if (minBufferSize != AudioSystem.NOT_SPECIFIED) {
- bufStr = "and buffers of " + minBufferSize + //$NON-NLS-1$
- " to " + maxBufferSize + " bytes"; //$NON-NLS-1$ //$NON-NLS-2$
- }
- return getLineClass() + " supporting " + formatStr + ", " + bufStr; //$NON-NLS-1$
- }
- }
-
- int available();
-
- void drain();
-
- void flush();
-
- int getBufferSize();
-
- AudioFormat getFormat();
-
- int getFramePosition();
-
- float getLevel();
-
- long getLongFramePosition();
-
- long getMicrosecondPosition();
-
- boolean isActive();
-
- boolean isRunning();
-
- void start();
-
- void stop();
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/EnumControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/EnumControl.java
deleted file mode 100644
index a21a4cc..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/EnumControl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class EnumControl extends Control {
- public static class Type extends Control.Type {
- public static final Type REVERB = new Type("Reverb"); //$NON-NLS-1$
-
- protected Type(String name) {
- super(name);
- }
- }
-
- private Object[] values;
-
- private Object value;
-
- protected EnumControl(EnumControl.Type type, Object[] values, Object value) {
- super(type);
- this.value = value;
- this.values = values;
- }
-
- public void setValue(Object value) {
- for (Object val : values) {
- if (val.equals(value)) {
- this.value = value;
- return;
- }
- }
- // sound.0D=The value is not supported
- throw new IllegalArgumentException(Messages.getString("sound.0D")); //$NON-NLS-1$
- }
-
- public Object getValue() {
- return value;
- }
-
- public Object[] getValues() {
- return values;
- }
-
- public String toString() {
- return getType() + " with current value: " + value; //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/FloatControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/FloatControl.java
deleted file mode 100644
index 6bf92be..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/FloatControl.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class FloatControl extends Control {
-
- public static class Type extends Control.Type {
- public static final Type MASTER_GAIN = new Type("Master Gain"); //$NON-NLS-1$
-
- public static final Type AUX_SEND = new Type("AUX Send"); //$NON-NLS-1$
-
- public static final Type AUX_RETURN = new Type("AUX Return"); //$NON-NLS-1$
-
- public static final Type REVERB_SEND = new Type("Reverb Send"); //$NON-NLS-1$
-
- public static final Type REVERB_RETURN = new Type("Reverb Return"); //$NON-NLS-1$
-
- public static final Type VOLUME = new Type("Volume"); //$NON-NLS-1$
-
- public static final Type PAN = new Type("Pan"); //$NON-NLS-1$
-
- public static final Type BALANCE = new Type("Balance"); //$NON-NLS-1$
-
- public static final Type SAMPLE_RATE = new Type("Sample Rate"); //$NON-NLS-1$
-
- protected Type(String name) {
- super(name);
- }
- }
-
- private float value;
-
- private float maximum;
-
- private float minimum;
-
- private String units;
-
- private String minLabel;
-
- private String midLabel;
-
- private String maxLabel;
-
- private float precision;
-
- private int updatePeriod;
-
- protected FloatControl(FloatControl.Type type, float minimum,
- float maximum, float precision, int updatePeriod,
- float initialValue, String units, String minLabel, String midLabel,
- String maxLabel) {
- super(type);
- this.maximum = maximum;
- this.maxLabel = maxLabel;
- this.midLabel = midLabel;
- this.minLabel = minLabel;
- this.minimum = minimum;
- this.precision = precision;
- this.units = units;
- this.updatePeriod = updatePeriod;
- this.value = initialValue;
- }
-
- protected FloatControl(FloatControl.Type type, float minimum,
- float maximum, float precision, int updatePeriod,
- float initialValue, String units) {
- this(type, minimum, maximum, precision, updatePeriod, initialValue,
- units, "", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- public void setValue(float newValue) {
- if (newValue > maximum || newValue < minimum) {
- // sound.0F=value does not fall within the allowable range
- throw new IllegalArgumentException(Messages.getString("sound.0F")); //$NON-NLS-1$
- }
- this.value = newValue;
- }
-
- public float getValue() {
- return this.value;
- }
-
- public float getMaximum() {
- return this.maximum;
- }
-
- public float getMinimum() {
- return this.minimum;
- }
-
- public String getUnits() {
- return this.units;
- }
-
- public String getMinLabel() {
- return this.minLabel;
- }
-
- public String getMidLabel() {
- return this.midLabel;
- }
-
- public String getMaxLabel() {
- return this.maxLabel;
- }
-
- public float getPrecision() {
- return this.precision;
- }
-
- public int getUpdatePeriod() {
- return this.updatePeriod;
- }
-
- public void shift(float from, float to, int microseconds) {
- setValue(to);
- }
-
- public String toString() {
- return getType() + " with current value: "+ value + " " + units //$NON-NLS-1$ //$NON-NLS-2$
- + " (range: " + minimum + " - " + maximum + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Line.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Line.java
deleted file mode 100644
index decc68d..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Line.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface Line {
-
- class Info {
- private Class <?> lineClass;
-
- public Info(Class <?> lineClass) {
- this.lineClass = lineClass;
- }
-
- public Class <?> getLineClass( ){
- return lineClass;
- }
-
- public boolean matches(Line.Info info) {
- return lineClass.isAssignableFrom(info.getLineClass());
- }
-
- @Override
- public String toString() {
- return lineClass.toString();
- }
- }
-
- void addLineListener(LineListener listener);
-
- void close();
-
- Control getControl(Control.Type control);
-
- Control[] getControls();
-
- Line.Info getLineInfo();
-
- boolean isControlSupported(Control.Type control);
-
- boolean isOpen();
-
- void open() throws LineUnavailableException;
-
- void removeLineListener(LineListener listener);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineEvent.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineEvent.java
deleted file mode 100644
index 95a480a..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineEvent.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.EventObject;
-
-public class LineEvent extends EventObject {
-
- /**
- *
- */
- private static final long serialVersionUID = -1274246333383880410L;
-
- private LineEvent.Type type;
- private long position;
-
- public static class Type {
-
- public static final Type CLOSE = new Type("Close"); //$NON-NLS-1$
-
- public static final Type OPEN = new Type("Open"); //$NON-NLS-1$
-
- public static final Type START = new Type("Start"); //$NON-NLS-1$
-
- public static final Type STOP = new Type("Stop"); //$NON-NLS-1$
-
- private String name;
-
- public Type(String name) {
- this.name = name;
- }
-
- @Override
- public boolean equals(Object another) {
- if (this == another) {
- return true;
- }
-
- if (another == null || !(another instanceof Type)) {
- return false;
- }
-
- Type obj = (Type) another;
- return name == null ? obj.name == null : name.equals(obj.name);
- }
-
- @Override
- public final int hashCode() {
- return name == null ? 0 : name.hashCode();
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- public LineEvent(Line line, LineEvent.Type type, long position) {
- super(line);
- this.type = type;
- this.position = position;
- }
-
- public final Line getLine() {
- return (Line)getSource();
- }
-
- public final LineEvent.Type getType() {
- return type;
- }
-
- public final long getFramePosition() {
- return position;
- }
-
- public String toString() {
- return type + " event from line " + getLine(); //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineListener.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineListener.java
deleted file mode 100644
index a3a828f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.EventListener;
-
-public interface LineListener extends EventListener {
- void update(LineEvent event);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineUnavailableException.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineUnavailableException.java
deleted file mode 100644
index 5a687ed..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineUnavailableException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public class LineUnavailableException extends Exception {
- private static final long serialVersionUID = -2046718279487432130L;
-
- public LineUnavailableException() {
- super();
- }
-
- public LineUnavailableException(String message) {
- super(message);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Mixer.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Mixer.java
deleted file mode 100644
index f9fefda..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Mixer.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface Mixer extends Line {
-
- public static class Info {
- private String name;
- private String vendor;
- private String description;
- private String version;
-
- protected Info(String name, String vendor, String description, String version) {
- this.name = name;
- this.vendor = vendor;
- this.description = description;
- this.version = version;
- }
-
- @Override
- public final boolean equals(Object another) {
- return this == another;
- }
-
- public final String getDescription() {
- return description;
- }
-
- public final String getName() {
- return name;
- }
-
- public final String getVendor() {
- return vendor;
- }
-
- public final String getVersion() {
- return version;
- }
-
- @Override
- public final int hashCode() {
- return name.hashCode() + vendor.hashCode() + description.hashCode() + version.hashCode();
- }
-
- @Override
- public final String toString() {
- return name + ", version " + version; //$NON-NLS-1$
- }
- }
-
- Line getLine(Line.Info info) throws LineUnavailableException;
-
- int getMaxLines(Line.Info info);
-
- Mixer.Info getMixerInfo();
-
- Line.Info[] getSourceLineInfo();
-
- Line.Info[] getSourceLineInfo(Line.Info info);
-
- Line[] getSourceLines();
-
- Line.Info[] getTargetLineInfo();
-
- Line.Info[] getTargetLineInfo(Line.Info info);
-
- Line[] getTargetLines();
-
- boolean isLineSupported(Line.Info info);
-
- boolean isSynchronizationSupported(Line[] lines, boolean maintainSync);
-
- void synchronize(Line[] lines, boolean maintainSync);
-
- void unsynchronize(Line[] lines);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Port.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Port.java
deleted file mode 100644
index 68d0638..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Port.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface Port extends Line {
-
- public static class Info extends Line.Info {
-
- private String name;
-
- private boolean isSource;
-
- public static final Info MICROPHONE = new Info(Port.class,
- "MICROPHONE", true); //$NON-NLS-1$
-
- public static final Info LINE_IN = new Info(Port.class, "LINE_IN", true); //$NON-NLS-1$
-
- public static final Info COMPACT_DISC = new Info(Port.class,
- "COMPACT_DISC", true); //$NON-NLS-1$
-
- public static final Info SPEAKER = new Info(Port.class, "SPEAKER", //$NON-NLS-1$
- false);
-
- public static final Info HEADPHONE = new Info(Port.class, "HEADPHONES", //$NON-NLS-1$
- false);
-
- public static final Info LINE_OUT = new Info(Port.class, "LINE_OUT", //$NON-NLS-1$
- false);
-
- public Info(Class<?> lineClass, String name, boolean isSource) {
- super(lineClass);
- this.name = name;
- this.isSource = isSource;
- }
-
- public String getName() {
- return this.name;
- }
-
- public boolean isSource() {
- return this.isSource;
- }
-
- public boolean matches(Line.Info info) {
- if (super.matches(info) && Port.Info.class.equals(info.getClass())
- && name.equals(((Port.Info) info).getName())
- && isSource == ((Port.Info) info).isSource()) {
- return true;
- }
- return false;
- }
-
- public final boolean equals(Object obj) {
- return this == obj;
- }
-
- public final int hashCode() {
- return name.hashCode() ^ getLineClass().hashCode();
- }
-
- public final String toString() {
- return name + (isSource ? " source port" : " target port"); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/ReverbType.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/ReverbType.java
deleted file mode 100644
index 9645ba6..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/ReverbType.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public class ReverbType {
-
- protected ReverbType(String name, int earlyReflectionDelay,
- float earlyReflectionIntensity, int lateReflectionDelay,
- float lateReflectionIntensity, int decayTime) {
- this.name = name;
- this.earlyReflectionDelay = earlyReflectionDelay;
- this.earlyReflectionIntensity = earlyReflectionIntensity;
- this.lateReflectionDelay = lateReflectionDelay;
- this.lateReflectionIntensity = lateReflectionIntensity;
- this.decayTime = decayTime;
- }
-
- private String name;
-
- private int earlyReflectionDelay;
-
- private float earlyReflectionIntensity;
-
- private int lateReflectionDelay;
-
- private float lateReflectionIntensity;
-
- private int decayTime;
-
- public String getName() {
- return this.name;
- }
-
- public final int getEarlyReflectionDelay() {
- return this.earlyReflectionDelay;
- }
-
- public final float getEarlyReflectionIntensity() {
- return this.earlyReflectionIntensity;
- }
-
- public final int getLateReflectionDelay() {
- return this.lateReflectionDelay;
- }
-
- public final float getLateReflectionIntensity() {
- return this.lateReflectionIntensity;
- }
-
- public final int getDecayTime() {
- return this.decayTime;
- }
-
- public final boolean equals(Object obj) {
- return this == obj;
- }
-
- public final int hashCode() {
- return toString().hashCode();
- }
-
- public final String toString() {
- return name + ", early reflection delay " + earlyReflectionDelay //$NON-NLS-1$
- + " ns, early reflection intensity " + earlyReflectionIntensity //$NON-NLS-1$
- + " dB, late deflection delay " + lateReflectionDelay //$NON-NLS-1$
- + " ns, late reflection intensity " + lateReflectionIntensity //$NON-NLS-1$
- + " dB, decay time " + decayTime; //$NON-NLS-1$
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/SourceDataLine.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/SourceDataLine.java
deleted file mode 100644
index 4d68221..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/SourceDataLine.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface SourceDataLine extends DataLine {
-
- void open(AudioFormat format) throws LineUnavailableException;
-
- void open(AudioFormat format, int bufferSize)
- throws LineUnavailableException;
-
- int write(byte[] b, int off, int len);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/TargetDataLine.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/TargetDataLine.java
deleted file mode 100644
index f4c37c8..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/TargetDataLine.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface TargetDataLine extends DataLine {
-
- void open(AudioFormat format) throws LineUnavailableException;
-
- void open(AudioFormat format, int bufferSize)
- throws LineUnavailableException;
-
- int read(byte[] b, int off, int len);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/UnsupportedAudioFileException.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/UnsupportedAudioFileException.java
deleted file mode 100644
index 590266f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/UnsupportedAudioFileException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public class UnsupportedAudioFileException extends Exception {
- private static final long serialVersionUID = -139127412623160368L;
-
- public UnsupportedAudioFileException() {
- super();
- }
-
- public UnsupportedAudioFileException(String message) {
- super(message);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileReader.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileReader.java
deleted file mode 100644
index 5c01df5..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileReader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.UnsupportedAudioFileException;
-
-public abstract class AudioFileReader {
-
- public abstract AudioFileFormat getAudioFileFormat(File file)
- throws UnsupportedAudioFileException, IOException;
-
- public abstract AudioFileFormat getAudioFileFormat(InputStream stream)
- throws UnsupportedAudioFileException, IOException;
-
- public abstract AudioFileFormat getAudioFileFormat(URL url)
- throws UnsupportedAudioFileException, IOException;
-
- public abstract AudioInputStream getAudioInputStream(File file)
- throws UnsupportedAudioFileException, IOException;
-
- public abstract AudioInputStream getAudioInputStream(InputStream stream)
- throws UnsupportedAudioFileException, IOException;
-
- public abstract AudioInputStream getAudioInputStream(URL url)
- throws UnsupportedAudioFileException, IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileWriter.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileWriter.java
deleted file mode 100644
index 0bae3f3..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileWriter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioFileFormat.Type;
-
-public abstract class AudioFileWriter {
-
- public abstract AudioFileFormat.Type[] getAudioFileTypes();
-
- public abstract AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream);
-
- public boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
- AudioFileFormat.Type[] supported = getAudioFileTypes();
- for (Type element : supported) {
- if (fileType.equals(element)) {
- return true;
- }
- }
- return false;
- }
-
- public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream stream) {
- AudioFileFormat.Type[] supported = getAudioFileTypes(stream);
- for (Type element : supported) {
- if (fileType.equals(element)) {
- return true;
- }
- }
- return false;
- }
-
- public abstract int write(AudioInputStream stream,
- AudioFileFormat.Type fileType, File out) throws IOException;
-
- public abstract int write(AudioInputStream stream,
- AudioFileFormat.Type fileType, OutputStream out) throws IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/FormatConversionProvider.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/FormatConversionProvider.java
deleted file mode 100644
index ed0d69f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/FormatConversionProvider.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioFormat.Encoding;
-
-public abstract class FormatConversionProvider {
-
- public abstract AudioInputStream getAudioInputStream(
- AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream);
-
- public abstract AudioInputStream getAudioInputStream(
- AudioFormat targetFormat, AudioInputStream sourceStream);
-
- public abstract AudioFormat.Encoding[] getTargetEncodings(
- AudioFormat sourceFormat);
-
- public boolean isConversionSupported(AudioFormat.Encoding targetEncoding,
- AudioFormat sourceFormat) {
- AudioFormat.Encoding[] encodings = getTargetEncodings(sourceFormat);
- for (Encoding element : encodings) {
- if (targetEncoding.equals(element)) {
- return true;
- }
- }
- return false;
- }
-
- public abstract AudioFormat[] getTargetFormats(
- AudioFormat.Encoding targetFormat, AudioFormat sourceFormat);
-
- public boolean isConversionSupported(AudioFormat targetFormat,
- AudioFormat sourceFormat) {
- AudioFormat[] formats = getTargetFormats(targetFormat.getEncoding(),
- sourceFormat);
- for (AudioFormat element : formats) {
- if (targetFormat.equals(element)) {
- return true;
- }
- }
- return false;
- }
-
- public abstract AudioFormat.Encoding[] getSourceEncodings();
-
- public boolean isSourceEncodingSupported(AudioFormat.Encoding sourceEncoding) {
- AudioFormat.Encoding[] encodings = getSourceEncodings();
- for (Encoding element : encodings) {
- if (sourceEncoding.equals(element)) {
- return true;
- }
- }
- return false;
- }
-
- public abstract AudioFormat.Encoding[] getTargetEncodings();
-
- public boolean isTargetEncodingSupported(AudioFormat.Encoding targetEncoding) {
- AudioFormat.Encoding[] encodings = getTargetEncodings();
- for (Encoding element : encodings) {
- if (targetEncoding.equals(element)) {
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/MixerProvider.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/MixerProvider.java
deleted file mode 100644
index 86fdbb7..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/MixerProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import javax.sound.sampled.Mixer;
-import javax.sound.sampled.Mixer.Info;
-
-public abstract class MixerProvider {
-
- public abstract Mixer getMixer(Mixer.Info info);
-
- public abstract Mixer.Info[] getMixerInfo();
-
- public boolean isMixerSupported(Mixer.Info info) {
- Mixer.Info[] devices = getMixerInfo();
- for (Info element : devices) {
- if (info.equals(element)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/Messages.java b/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/Messages.java
deleted file mode 100644
index 65ecb83..0000000
--- a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/Messages.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
- * All changes made to this file manually will be overwritten
- * if this tool runs again. Better make changes in the template file.
- */
-
-package org.apache.harmony.sound.internal.nls;
-
-import org.apache.harmony.luni.util.MsgHelp;
-
-/**
- * This class retrieves strings from a resource bundle and returns them,
- * formatting them with MessageFormat when required.
- * <p>
- * It is used by the system classes to provide national language support, by
- * looking up messages in the <code>
- * org.apache.harmony.sound.internal.nls.messages
- * </code>
- * resource bundle. Note that if this file is not available, or an invalid key
- * is looked up, or resource bundle support is not available, the key itself
- * will be returned as the associated message. This means that the <em>KEY</em>
- * should a reasonable human-readable (english) string.
- *
- */
-public class Messages {
-
- private static final String sResource =
- "org.apache.harmony.sound.internal.nls.messages"; //$NON-NLS-1$
-
- /**
- * Retrieves a message which has no arguments.
- *
- * @param msg
- * String the key to look up.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg) {
- return MsgHelp.getString(sResource, msg);
- }
-
- /**
- * Retrieves a message which takes 1 argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * Object the object to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object arg) {
- return getString(msg, new Object[] { arg });
- }
-
- /**
- * Retrieves a message which takes 1 integer argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * int the integer to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, int arg) {
- return getString(msg, new Object[] { Integer.toString(arg) });
- }
-
- /**
- * Retrieves a message which takes 1 character argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * char the character to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, char arg) {
- return getString(msg, new Object[] { String.valueOf(arg) });
- }
-
- /**
- * Retrieves a message which takes 2 arguments.
- *
- * @param msg
- * String the key to look up.
- * @param arg1
- * Object an object to insert in the formatted output.
- * @param arg2
- * Object another object to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object arg1, Object arg2) {
- return getString(msg, new Object[] { arg1, arg2 });
- }
-
- /**
- * Retrieves a message which takes several arguments.
- *
- * @param msg
- * String the key to look up.
- * @param args
- * Object[] the objects to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object[] args) {
- return MsgHelp.getString(sResource, msg, args);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/messages.properties b/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/messages.properties
deleted file mode 100644
index efcf80b..0000000
--- a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/messages.properties
+++ /dev/null
@@ -1,39 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# messages for EN locale
-sound.01=-1
-sound.02=Index: {0}, Size: {1}
-sound.03=length out of bounds: {0}
-sound.04=Invalid status byte: {0}
-sound.05=command out of range: {0}
-sound.06=channel out of range: {0}
-sound.07=data1 out of range: {0}
-sound.08=data2 out of range: {0}
-sound.09=Invalid status byte for sysex message: {0}
-sound.0A=Invalid meta event with type {0}
-sound.0B=Unsupported division type: {0}
-sound.0C=Frame size must be one byte
-sound.0D=The value is not supported
-sound.0F=value does not fall within the allowable range
-sound.11=Could not get line
-sound.12=Could not get audio input stream from source stream
-sound.13=Could not get audio input stream from source stream
-sound.14=File is not a supported file type
-sound.15=Could not get audio input stream from input stream
-sound.16=Could not get audio input stream from input URL
-sound.17=Could not get audio input stream from input file
-sound.18=Type is not supported
diff --git a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/utils/ProviderService.java b/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/utils/ProviderService.java
deleted file mode 100644
index b1bbe2e..0000000
--- a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/utils/ProviderService.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.harmony.sound.utils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Properties;
-
-public class ProviderService {
-
- // Properties from sound.propertie file
- private static Properties devices;
-
- static {
- devices = new Properties();
-
- FileInputStream fstream = AccessController
- .doPrivileged(new PrivilegedAction<FileInputStream>() {
-
- public FileInputStream run() {
- // obtain the path to the file sound.properties
- String soundPropertiesPath = System
- .getProperty("java.home") //$NON-NLS-1$
- + File.separator + "lib" + File.separator //$NON-NLS-1$
- + "sound.properties"; //$NON-NLS-1$
- try {
- return new FileInputStream(soundPropertiesPath);
- } catch (FileNotFoundException e) {
- return null;
- }
- }
- });
-
- if (fstream != null) {
- // reading file sound.properties
- try {
- devices.load(fstream);
- } catch (IOException e) {}
- }
- }
-
- /**
- * this method return information about default device
- *
- * @param deviceName
- * @return
- */
- public static List<String> getDefaultDeviceDescription(String deviceName) {
-
- // variable that contain information about default device
- List<String> defaultDevice = new ArrayList<String>();
- String str;
- int index;
-
- /*
- * obtain the default device that describes by deviceName
- */
- str = devices.getProperty(deviceName);
- /*
- * if default device doesn't define, than return empty defaultDevice
- */
- if (str == null) {
- return defaultDevice;
- }
- /*
- * the separator between provider and name is '#'; find separator of
- * provider and name of device in the notation of default device
- */
- index = str.indexOf("#"); //$NON-NLS-1$
- /*
- * if separator doesn't find, so in the definition of default device
- * contain only name of provider, and so we add it
- */
- if (index == -1) {
- defaultDevice.add(str);
- defaultDevice.add(null);
- /*
- * if separator is the first symbol, so definition contain only name
- * of device
- */
- } else if (index == 0) {
- defaultDevice.add(null);
- defaultDevice.add(str.substring(index + 1));
- /*
- * if separator is not the first, so we find provider and name of
- * device
- */
- } else {
- defaultDevice.add(str.substring(0, index));
- defaultDevice.add(str.substring(index + 1));
- }
- return defaultDevice;
- }
-
- /**
- * this method return the list of providers
- *
- * @param providerName
- * @return
- */
- public static List<?> getProviders(String providerName) {
- final String name = providerName;
-
- return AccessController
- .doPrivileged(new PrivilegedAction<List<Object>>() {
-
- public List<Object> run() {
- List<Object> providers = new ArrayList<Object>();
- String className = null;
- byte[] bytes;
-
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- Enumeration<URL> urls = null;
- try {
- urls = cl.getResources(name);
- } catch (IOException e) {
- return providers;
- }
- for (; urls.hasMoreElements();) {
- try {
- InputStream in = urls.nextElement()
- .openStream();
- bytes = new byte[in.available()];
- in.read(bytes);
- in.close();
- } catch (IOException e) {
- continue;
- }
- String[] astr = new String(bytes).split("\r\n"); //$NON-NLS-1$
- for (String str : astr) {
- className = str.trim();
- if (!className.startsWith("#")) { // skip
- // comments
- // //$NON-NLS-1$
- try {
- providers.add(Class.forName(
- className.trim(), true, cl)
- .newInstance());
- } catch (IllegalAccessException e) {} catch (InstantiationException e) {} catch (ClassNotFoundException e) {}
- }
- }
- }
- return providers;
- }
- });
-
- }
-
- public static Properties getSoundProperties() {
- return devices;
- }
-
-}
diff --git a/libcore-disabled/sound/src/test/java/android/core/SoundTest.java b/libcore-disabled/sound/src/test/java/android/core/SoundTest.java
deleted file mode 100644
index 22a9261..0000000
--- a/libcore-disabled/sound/src/test/java/android/core/SoundTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import android.media.MediaPlayer;
-
-import com.android.internal.sound.midi.AndroidSequencer;
-import com.android.internal.sound.sampled.AndroidClip;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import java.io.File;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.Sequencer;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.Clip;
-import javax.sound.sampled.Line;
-
-public class SoundTest extends TestCase {
-
- public static String TAG = "SoundTest";
-
- // Regression test for #000000: Completion of MIDI file doesn't fire
- // corresponding event.
-// private boolean eventReceived = false;
-//
-// public void testMidiFileCompletion() {
-// try {
-// MediaPlayer player = new MediaPlayer();
-//
-// player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-// public void onCompletion(MediaPlayer player) {
-// eventReceived = true;
-// }
-// });
-//
-// player.setDataSource("/system/sounds/test.mid");
-// player.prepare();
-// player.start();
-// Thread.sleep(20000);
-// assertFalse("Player must be stopped", player.isPlaying());
-// assertTrue("Completion event must have been received", eventReceived);
-//
-// } catch (Exception ex) {
-// throw new RuntimeException(ex);
-// }
-// }
-
- // Regression test for #872614: General javax.sound weirdness.
- public void testMidiSupport() {
- try {
- Sequencer sequencer = MidiSystem.getSequencer();
- Assert.assertTrue("AndroidSequencer must exist", sequencer instanceof AndroidSequencer);
-
- MidiDevice.Info info = sequencer.getDeviceInfo();
- Assert.assertNotNull("Device info must exist", info);
-
- Sequence sequence = MidiSystem.getSequence(new File("/system/sounds/test.mid"));
- Assert.assertNotNull("Sequence must exist", sequence);
-
- Assert.assertFalse("Sequencer must not be open", sequencer.isOpen());
- sequencer.open();
- Assert.assertTrue("Sequencer must be open", sequencer.isOpen());
-
- Assert.assertNull("Sequencer must not have Sequence", sequencer.getSequence());
- sequencer.setSequence(sequence);
- Assert.assertNotNull("Sequencer must have Sequence", sequencer.getSequence());
-
- Assert.assertFalse("Sequencer must not be running", sequencer.isRunning());
- sequencer.start();
- Thread.sleep(1000);
- Assert.assertTrue("Sequencer must be running (after 1 second)", sequencer.isRunning());
-
- Thread.sleep(3000);
-
- Assert.assertTrue("Sequencer must be running", sequencer.isRunning());
- sequencer.stop();
- Thread.sleep(1000);
- Assert.assertFalse("Sequencer must not be running (after 1 second)", sequencer.isRunning());
-
- sequencer.close();
- Assert.assertFalse("Sequencer must not be open", sequencer.isOpen());
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- // Regression test for #872614: General javax.sound weirdness.
- public void testSampledSupport() {
- try {
- Clip clip = AudioSystem.getClip();
- Assert.assertTrue("AndroidClip must exist", clip instanceof AndroidClip);
-
- Line.Info info = clip.getLineInfo();
- Assert.assertNotNull("Line info must exist", info);
-
- AudioInputStream stream = AudioSystem.getAudioInputStream(new File("/system/media/audio/ringtones/ringer.ogg"));
- Assert.assertNotNull("AudioInputStream must exist", stream);
-
- Assert.assertFalse("Clip must not be open", clip.isOpen());
- clip.open(stream);
- Assert.assertTrue("Clip must be open", clip.isOpen());
-
- Assert.assertFalse("Clip must not be running", clip.isRunning());
- clip.start();
- Thread.sleep(1000);
- Assert.assertTrue("Clip must be running (after 1 second)", clip.isRunning());
-
- Thread.sleep(2000);
-
- Assert.assertTrue("Clip must be running", clip.isRunning());
- clip.stop();
- Thread.sleep(1000);
- Assert.assertFalse("Clip must not be running (after 1 second)", clip.isRunning());
-
- clip.close();
- Assert.assertFalse("Clip must not be open", clip.isOpen());
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
-}
diff --git a/libdex/Android.mk b/libdex/Android.mk
index df45f04..dfd9802 100644
--- a/libdex/Android.mk
+++ b/libdex/Android.mk
@@ -25,6 +25,7 @@
DexSwapVerify.c \
InstrUtils.c \
Leb128.c \
+ OpCodeNames.c \
OptInvocation.c \
sha1.c \
SysUtil.c \
diff --git a/libdex/CmdUtils.c b/libdex/CmdUtils.c
index 102664c..35696f9 100644
--- a/libdex/CmdUtils.c
+++ b/libdex/CmdUtils.c
@@ -70,7 +70,7 @@
goto bail;
}
- if (!dexZipExtractEntryToFile(&archive, entry, fd)) {
+ if (dexZipExtractEntryToFile(&archive, entry, fd) != 0) {
fprintf(stderr, "Extract of '%s' from '%s' failed\n",
kFileToExtract, zipFileName);
result = kUTFRBadZip;
@@ -89,12 +89,17 @@
/*
* Map the specified DEX file read-only (possibly after expanding it into a
* temp file from a Jar). Pass in a MemMapping struct to hold the info.
+ * If the file is an unoptimized DEX file, then byte-swapping and structural
+ * verification are performed on it before the memory is made read-only.
*
* The temp file is deleted after the map succeeds.
*
* This is intended for use by tools (e.g. dexdump) that need to get a
* read-only copy of a DEX file that could be in a number of different states.
*
+ * If "tempFileName" is NULL, a default value is used. The temp file is
+ * deleted after the map succeeds.
+ *
* If "quiet" is set, don't report common errors.
*
* Returns 0 (kUTFRSuccess) on success.
@@ -110,7 +115,7 @@
if (len < 5) {
if (!quiet) {
- fprintf(stderr,
+ fprintf(stderr,
"ERROR: filename must end in .dex, .zip, .jar, or .apk\n");
}
result = kUTFRBadArgs;
@@ -133,7 +138,7 @@
}
result = dexUnzipToFile(fileName, tempFileName, quiet);
-
+
if (result == kUTFRSuccess) {
//printf("+++ Good unzip to '%s'\n", tempFileName);
fileName = tempFileName;
@@ -150,6 +155,8 @@
}
}
+ result = kUTFRGenericFailure;
+
/*
* Pop open the (presumed) DEX file.
*/
@@ -162,13 +169,34 @@
goto bail;
}
- if (sysMapFileInShmemReadOnly(fd, pMap) != 0) {
- fprintf(stderr, "ERROR: Unable to map %s\n", fileName);
- close(fd);
+ if (sysMapFileInShmemWritableReadOnly(fd, pMap) != 0) {
+ fprintf(stderr, "ERROR: Unable to map '%s'\n", fileName);
goto bail;
}
/*
+ * This call will fail if the file exists on a filesystem that
+ * doesn't support mprotect(). If that's the case, then the file
+ * will have already been mapped private-writable by the previous
+ * call, so we don't need to do anything special if this call
+ * returns non-zero.
+ */
+ sysChangeMapAccess(pMap->addr, pMap->length, true, pMap);
+
+ if (dexSwapAndVerifyIfNecessary(pMap->addr, pMap->length)) {
+ fprintf(stderr, "ERROR: Failed structural verification of '%s'\n",
+ fileName);
+ goto bail;
+ }
+
+ /*
+ * Similar to above, this call will fail if the file wasn't ever
+ * read-only to begin with. This is innocuous, though it is
+ * undesirable from a memory hygiene perspective.
+ */
+ sysChangeMapAccess(pMap->addr, pMap->length, false, pMap);
+
+ /*
* Success! Close the file and return with the start/length in pMap.
*/
result = 0;
@@ -178,7 +206,7 @@
close(fd);
if (removeTemp) {
if (unlink(tempFileName) != 0) {
- fprintf(stderr, "Warning: unable to remove temp '%s'\n",
+ fprintf(stderr, "WARNING: unable to remove temp '%s'\n",
tempFileName);
}
}
diff --git a/libdex/CmdUtils.h b/libdex/CmdUtils.h
index e0b0105..7a85287 100644
--- a/libdex/CmdUtils.h
+++ b/libdex/CmdUtils.h
@@ -43,8 +43,12 @@
} UnzipToFileResult;
/*
- * Map the specified DEX file, possibly after expanding it into a temp file
- * from a Jar. Pass in a MemMapping struct to hold the info.
+ * Map the specified DEX file read-only (possibly after expanding it into a
+ * temp file from a Jar). Pass in a MemMapping struct to hold the info.
+ * If the file is an unoptimized DEX file, then byte-swapping and structural
+ * verification are performed on it before the memory is made read-only.
+ *
+ * The temp file is deleted after the map succeeds.
*
* This is intended for use by tools (e.g. dexdump) that need to get a
* read-only copy of a DEX file that could be in a number of different states.
@@ -52,7 +56,9 @@
* If "tempFileName" is NULL, a default value is used. The temp file is
* deleted after the map succeeds.
*
- * Returns 0 on success.
+ * If "quiet" is set, don't report common errors.
+ *
+ * Returns 0 (kUTFRSuccess) on success.
*/
UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName,
MemMapping* pMap, bool quiet);
diff --git a/libdex/DexCatch.c b/libdex/DexCatch.c
index 5eae17a..ed97e87 100644
--- a/libdex/DexCatch.c
+++ b/libdex/DexCatch.c
@@ -20,14 +20,14 @@
#include "DexCatch.h"
-/* Get the first handler offset for the given DexCode.
+/* Get the first handler offset for the given DexCode.
* It's not 0 because the handlers list is prefixed with its size
* (in entries) as a uleb128. */
u4 dexGetFirstHandlerOffset(const DexCode* pCode) {
if (pCode->triesSize == 0) {
return 0;
}
-
+
const u1* baseData = dexGetCatchHandlerData(pCode);
const u1* data = baseData;
diff --git a/libdex/DexCatch.h b/libdex/DexCatch.h
index f928144..c0eec7c 100644
--- a/libdex/DexCatch.h
+++ b/libdex/DexCatch.h
@@ -32,7 +32,7 @@
u4 address; /* handler address */
} DexCatchHandler;
-/* Get the first handler offset for the given DexCode.
+/* Get the first handler offset for the given DexCode.
* It's not 0 because the handlers list is prefixed with its size
* (in entries) as a uleb128. */
u4 dexGetFirstHandlerOffset(const DexCode* pCode);
@@ -84,7 +84,7 @@
{
dexCatchIteratorInitToPointer(pIterator,
dexGetCatchHandlerData(pCode) + offset);
-}
+}
/* Get the next item from a DexCatchIterator. Returns NULL if at end. */
DEX_INLINE DexCatchHandler* dexCatchIteratorNext(DexCatchIterator* pIterator) {
@@ -119,7 +119,7 @@
* found. Returns false if there is no applicable handler. */
DEX_INLINE bool dexFindCatchHandler(DexCatchIterator *pIterator,
const DexCode* pCode, u4 address) {
- u2 triesSize = pCode->triesSize;
+ u2 triesSize = pCode->triesSize;
int offset = -1;
// Short-circuit the overwhelmingly common cases.
@@ -134,13 +134,13 @@
if (address < start) {
break;
}
-
+
u4 end = start + tries[0].insnCount;
if (address >= end) {
break;
}
-
+
offset = tries[0].handlerOff;
break;
}
@@ -157,6 +157,6 @@
dexCatchIteratorInit(pIterator, pCode, offset);
return true;
}
-}
+}
#endif
diff --git a/libdex/DexClass.c b/libdex/DexClass.c
index 1268130..8a59e09 100644
--- a/libdex/DexClass.c
+++ b/libdex/DexClass.c
@@ -52,11 +52,11 @@
/* Read and verify an encoded_field. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure).
- *
+ *
* The lastIndex value should be set to 0 before the first field in
* a list is read. It is updated as fields are read and used in the
* decode process.
- *
+ *
* The verification done by this function is of the raw data format
* only; it does not verify that access flags or indices
* are valid. */
@@ -73,7 +73,7 @@
/* Read and verify an encoded_method. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure).
- *
+ *
* The lastIndex value should be set to 0 before the first method in
* a list is read. It is updated as fields are read and used in the
* decode process.
@@ -97,7 +97,7 @@
* must subsequently be free()d. This function returns NULL if there
* was trouble parsing the data. If this function is passed NULL, it
* returns an initialized empty DexClassData structure.
- *
+ *
* The verification done by this function is of the raw data format
* only; it does not verify that access flags, indices, or offsets
* are valid. */
@@ -110,7 +110,7 @@
memset(result, 0, sizeof(*result));
return result;
}
-
+
if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) {
return NULL;
}
@@ -138,21 +138,21 @@
} else {
result->staticFields = NULL;
}
-
+
if (header.instanceFieldsSize != 0) {
result->instanceFields = (DexField*) ptr;
ptr += header.instanceFieldsSize * sizeof(DexField);
} else {
result->instanceFields = NULL;
}
-
+
if (header.directMethodsSize != 0) {
result->directMethods = (DexMethod*) ptr;
ptr += header.directMethodsSize * sizeof(DexMethod);
} else {
result->directMethods = NULL;
}
-
+
if (header.virtualMethodsSize != 0) {
result->virtualMethods = (DexMethod*) ptr;
} else {
@@ -176,7 +176,7 @@
okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
&result->directMethods[i], &lastIndex);
}
-
+
lastIndex = 0;
for (i = 0; okay && (i < header.virtualMethodsSize); i++) {
okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
diff --git a/libdex/DexClass.h b/libdex/DexClass.h
index ce41e8b..3d1e11b 100644
--- a/libdex/DexClass.h
+++ b/libdex/DexClass.h
@@ -65,11 +65,11 @@
/* Read and verify an encoded_field. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure).
- *
+ *
* The lastIndex value should be set to 0 before the first field in
* a list is read. It is updated as fields are read and used in the
* decode process.
- *
+ *
* The verification done by this function is of the raw data format
* only; it does not verify that access flags or indices
* are valid. */
@@ -79,7 +79,7 @@
/* Read and verify an encoded_method. This updates the
* given data pointer to point past the end of the read data and
* returns an "okay" flag (that is, false == failure).
- *
+ *
* The lastIndex value should be set to 0 before the first method in
* a list is read. It is updated as fields are read and used in the
* decode process.
@@ -96,7 +96,7 @@
* must subsequently be free()d. This function returns NULL if there
* was trouble parsing the data. If this function is passed NULL, it
* returns an initialized empty DexClassData structure.
- *
+ *
* The verification done by this function is of the raw data format
* only; it does not verify that access flags, indices, or offsets
* are valid. */
@@ -127,8 +127,8 @@
}
/* Read an encoded_field without verification. This updates the
- * given data pointer to point past the end of the read data.
- *
+ * given data pointer to point past the end of the read data.
+ *
* The lastIndex value should be set to 0 before the first field in
* a list is read. It is updated as fields are read and used in the
* decode process.
@@ -143,8 +143,8 @@
}
/* Read an encoded_method without verification. This updates the
- * given data pointer to point past the end of the read data.
- *
+ * given data pointer to point past the end of the read data.
+ *
* The lastIndex value should be set to 0 before the first method in
* a list is read. It is updated as fields are read and used in the
* decode process.
diff --git a/libdex/DexFile.c b/libdex/DexFile.c
index b139746..0050e4a 100644
--- a/libdex/DexFile.c
+++ b/libdex/DexFile.c
@@ -90,7 +90,7 @@
* character (U+00a0, U+2000..U+200f, U+2028..U+202f,
* U+fff0..U+ffff).
*/
-
+
u2 utf16 = dexGetUtf16FromUtf8(pUtf8Ptr);
// Perform follow-up tests based on the high 8 bits.
@@ -139,7 +139,7 @@
/* Return whether the given string is a valid field or method name. */
bool dexIsValidMemberName(const char* s) {
bool angleName = false;
-
+
switch (*s) {
case '\0': {
// The empty string is not a valid name.
@@ -184,9 +184,9 @@
// Arrays may have no more than 255 dimensions.
return false;
}
-
+
switch (*(s++)) {
- case 'B':
+ case 'B':
case 'C':
case 'D':
case 'F':
@@ -443,7 +443,7 @@
pClassDef = dexGetClassDef(pDexFile, i);
pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
- classLookupAdd(pDexFile, pLookup,
+ classLookupAdd(pDexFile, pLookup,
(u1*)pString - pDexFile->baseAddr,
(u1*)pClassDef - pDexFile->baseAddr, &numProbes);
@@ -877,7 +877,7 @@
if (pLookup->table[idx].classDescriptorHash == hash) {
const char* str;
-
+
str = (const char*) (pDexFile->baseAddr + offset);
if (strcmp(str, descriptor) == 0) {
return (const DexClassDef*)
@@ -1017,7 +1017,7 @@
* Reads a string index as encoded for the debug info format,
* returning a string pointer or NULL as appropriate.
*/
-static const char* readStringIdx(const DexFile* pDexFile,
+static const char* readStringIdx(const DexFile* pDexFile,
const u1** pStream) {
u4 stringIdx = readUnsignedLeb128(pStream);
@@ -1033,7 +1033,7 @@
* Reads a type index as encoded for the debug info format, returning
* a string pointer for its descriptor or NULL as appropriate.
*/
-static const char* readTypeIdx(const DexFile* pDexFile,
+static const char* readTypeIdx(const DexFile* pDexFile,
const u1** pStream) {
u4 typeIdx = readUnsignedLeb128(pStream);
@@ -1056,14 +1056,14 @@
bool live;
} LocalInfo;
-static void emitLocalCbIfLive (void *cnxt, int reg, u4 endAddress,
+static void emitLocalCbIfLive (void *cnxt, int reg, u4 endAddress,
LocalInfo *localInReg, DexDebugNewLocalCb localCb)
{
if (localCb != NULL && localInReg[reg].live) {
localCb(cnxt, reg, localInReg[reg].startAddress, endAddress,
- localInReg[reg].name,
- localInReg[reg].descriptor,
- localInReg[reg].signature == NULL
+ localInReg[reg].name,
+ localInReg[reg].descriptor,
+ localInReg[reg].signature == NULL
? "" : localInReg[reg].signature );
}
}
@@ -1113,7 +1113,7 @@
} else {
assert(pCode->insSize == dexProtoComputeArgsSize(&proto));
}
-
+
DexParameterIterator iterator;
dexParameterIteratorInit(&iterator, &proto);
@@ -1121,7 +1121,7 @@
const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
const char *name;
int reg;
-
+
if ((argReg >= pCode->registersSize) || (descriptor == NULL)) {
goto invalid_stream;
}
@@ -1159,7 +1159,7 @@
case DBG_ADVANCE_PC:
address += readUnsignedLeb128(&stream);
break;
-
+
case DBG_ADVANCE_LINE:
line += readSignedLeb128(&stream);
break;
@@ -1170,13 +1170,13 @@
if (reg > pCode->registersSize) goto invalid_stream;
// Emit what was previously there, if anything
- emitLocalCbIfLive (cnxt, reg, address,
+ emitLocalCbIfLive (cnxt, reg, address,
localInReg, localCb);
localInReg[reg].name = readStringIdx(pDexFile, &stream);
localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream);
if (opcode == DBG_START_LOCAL_EXTENDED) {
- localInReg[reg].signature
+ localInReg[reg].signature
= readStringIdx(pDexFile, &stream);
} else {
localInReg[reg].signature = NULL;
@@ -1197,7 +1197,7 @@
reg = readUnsignedLeb128(&stream);
if (reg > pCode->registersSize) goto invalid_stream;
- if (localInReg[reg].name == NULL
+ if (localInReg[reg].name == NULL
|| localInReg[reg].descriptor == NULL) {
goto invalid_stream;
}
@@ -1224,7 +1224,7 @@
line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
if (posCb != NULL) {
- int done;
+ int done;
done = posCb(cnxt, address, line);
if (done) {
@@ -1254,4 +1254,3 @@
free(methodDescriptor);
}
}
-
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index a10aaf5..2ce7ebd 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -70,7 +70,7 @@
/*
* access flags and masks; the "standard" ones are all <= 0x4000
- *
+ *
* Note: There are related declarations in vm/oo/Object.h in the ClassFlags
* enum.
*/
@@ -96,7 +96,7 @@
ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only)
ACC_DECLARED_SYNCHRONIZED =
0x00020000, // method (Dalvik only)
- ACC_CLASS_MASK =
+ ACC_CLASS_MASK =
(ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
| ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
ACC_INNER_CLASS_MASK =
@@ -554,12 +554,23 @@
};
/*
- * Correct the byte ordering in a memory-mapped DEX file. This is only
- * required for code that opens "raw" DEX files, such as the DEX optimizer.
+ * Fix the byte ordering of all fields in the DEX file, and do
+ * structural verification. This is only required for code that opens
+ * "raw" DEX files, such as the DEX optimizer.
*
* Return 0 on success.
*/
-int dexFixByteOrdering(u1* addr, int len);
+int dexSwapAndVerify(u1* addr, int len);
+
+/*
+ * Detect the file type of the given memory buffer via magic number.
+ * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
+ * but return successfully on an optimized DEX file, and report an
+ * error for all other cases.
+ *
+ * Return 0 on success.
+ */
+int dexSwapAndVerifyIfNecessary(u1* addr, int len);
/*
* Compute DEX checksum.
@@ -747,7 +758,7 @@
if ((((u4) insnsEnd) & 3) != 0) {
insnsEnd++;
}
-
+
return (const DexTry*) insnsEnd;
}
@@ -784,7 +795,7 @@
/*
* Decode debug info for method.
- *
+ *
* posCb is called in ascending address order.
* localCb is called in order of ascending end address.
*/
diff --git a/libdex/DexInlines.c b/libdex/DexInlines.c
index ac0262f..6b3aed8 100644
--- a/libdex/DexInlines.c
+++ b/libdex/DexInlines.c
@@ -28,4 +28,3 @@
#include "InstrUtils.h"
#include "Leb128.h"
#include "ZipArchive.h"
-
diff --git a/libdex/DexProto.c b/libdex/DexProto.c
index c8f1b3e..b5574dc 100644
--- a/libdex/DexProto.c
+++ b/libdex/DexProto.c
@@ -112,7 +112,7 @@
* ===========================================================================
* Method Prototypes
* ===========================================================================
- */
+ */
/*
* Return the DexProtoId from the given DexProto. The DexProto must
@@ -150,7 +150,7 @@
}
length += strlen(dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
-
+
dexStringCacheAlloc(pCache, length);
char *at = (char*) pCache->value;
@@ -201,7 +201,7 @@
length += strlen(descriptor);
}
-
+
dexParameterIteratorInit(&iterator, pProto);
dexStringCacheAlloc(pCache, length);
@@ -299,7 +299,7 @@
// Compare return types.
if (compareReturnType) {
- int result =
+ int result =
strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx),
dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx));
@@ -309,14 +309,14 @@
}
// Compare parameters.
-
+
int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1;
int i;
for (i = 0; i < minParam; i++) {
u4 idx1 = dexTypeListGetIdx(typeList1, i);
u4 idx2 = dexTypeListGetIdx(typeList2, i);
- int result =
+ int result =
strcmp(dexStringByTypeIdx(dexFile1, idx1),
dexStringByTypeIdx(dexFile2, idx2));
@@ -368,7 +368,7 @@
if (result == NULL) {
return NULL;
}
-
+
// The return type is the character just past the ')'.
return result + 1;
}
@@ -385,7 +385,7 @@
while (*descriptor == '[') {
descriptor++;
}
-
+
switch (*descriptor) {
case 'B': case 'C': case 'D': case 'F':
case 'I': case 'J': case 'S': case 'Z': {
@@ -412,7 +412,7 @@
const char* descriptor) {
// First compare the return types.
- int result = strcmp(dexProtoGetReturnType(proto),
+ int result = strcmp(dexProtoGetReturnType(proto),
methodDescriptorReturnType(descriptor));
if (result != 0) {
@@ -427,7 +427,7 @@
// Skip the '('.
assert (*descriptor == '(');
descriptor++;
-
+
for (;;) {
const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator);
@@ -451,7 +451,7 @@
}
// Both prototype and descriptor have arguments. Compare them.
-
+
const char* nextDesc = methodDescriptorNextType(descriptor);
for (;;) {
@@ -469,7 +469,7 @@
break;
}
}
-
+
/*
* If we made it here, the two arguments matched, and
* descriptor == nextDesc.
@@ -482,7 +482,7 @@
* ===========================================================================
* Parameter Iterators
* ===========================================================================
- */
+ */
/*
* Initialize the given DexParameterIterator to be at the start of the
@@ -531,4 +531,3 @@
return dexStringByTypeIdx(pIterator->proto->dexFile, idx);
}
-
diff --git a/libdex/DexSwapVerify.c b/libdex/DexSwapVerify.c
index 400e766..a467fa7 100644
--- a/libdex/DexSwapVerify.c
+++ b/libdex/DexSwapVerify.c
@@ -1809,6 +1809,25 @@
SWAP_OFFSET4(item->debugInfoOff);
SWAP_FIELD4(item->insnsSize);
+ if (item->insSize > item->registersSize) {
+ LOGE("insSize (%u) > registersSize (%u)\n", item->insSize,
+ item->registersSize);
+ return NULL;
+ }
+
+ if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
+ /*
+ * It's okay for outsSize to be up to five, even if registersSize
+ * is smaller, since the short forms of method invocation allow
+ * repetition of a register multiple times within a single parameter
+ * list. Longer parameter lists, though, need to be represented
+ * in-order in the register file.
+ */
+ LOGE("outsSize (%u) > registersSize (%u)\n", item->outsSize,
+ item->registersSize);
+ return NULL;
+ }
+
count = item->insnsSize;
insns = item->insns;
CHECK_LIST_SIZE(insns, count, sizeof(u2));
@@ -2761,15 +2780,13 @@
}
/*
- * Fix the byte ordering of all fields in the DEX file, and do structural
- * verification.
- *
- * While we're at it, make sure that the file offsets all refer to locations
- * within the file.
+ * Fix the byte ordering of all fields in the DEX file, and do
+ * structural verification. This is only required for code that opens
+ * "raw" DEX files, such as the DEX optimizer.
*
* Returns 0 on success, nonzero on failure.
*/
-int dexFixByteOrdering(u1* addr, int len)
+int dexSwapAndVerify(u1* addr, int len)
{
DexHeader* pHeader;
CheckState state;
@@ -2899,3 +2916,29 @@
return !okay; // 0 == success
}
+
+/*
+ * Detect the file type of the given memory buffer via magic number.
+ * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
+ * but return successfully on an optimized DEX file, and report an
+ * error for all other cases.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+int dexSwapAndVerifyIfNecessary(u1* addr, int len)
+{
+ if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
+ // It is an optimized dex file.
+ return 0;
+ }
+
+ if (memcmp(addr, DEX_MAGIC, 4) == 0) {
+ // It is an unoptimized dex file.
+ return dexSwapAndVerify(addr, len);
+ }
+
+ LOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)\n",
+ addr[0], addr[1], addr[2], addr[3]);
+
+ return 1;
+}
diff --git a/libdex/InstrUtils.c b/libdex/InstrUtils.c
index d1ebeec..a3ee859 100644
--- a/libdex/InstrUtils.c
+++ b/libdex/InstrUtils.c
@@ -35,6 +35,9 @@
*
* (To save space in the binary we could generate a static table with a
* command-line utility.)
+ *
+ * TODO: it doesn't look like we're using the negative values anymore.
+ * Consider switching to only positive values.
*/
InstructionWidth* dexCreateInstrWidthTable(void)
{
@@ -294,6 +297,18 @@
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
+ case OP_IGET_VOLATILE:
+ case OP_IPUT_VOLATILE:
+ case OP_SGET_VOLATILE:
+ case OP_SPUT_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SPUT_OBJECT_VOLATILE:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
case OP_THROW_VERIFICATION_ERROR:
width = -2;
break;
@@ -317,20 +332,8 @@
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
- case OP_UNUSED_E3:
- case OP_UNUSED_E4:
- case OP_UNUSED_E5:
- case OP_UNUSED_E6:
- case OP_UNUSED_E7:
- case OP_UNUSED_E8:
- case OP_UNUSED_E9:
- case OP_UNUSED_EA:
- case OP_UNUSED_EB:
case OP_BREAKPOINT:
case OP_UNUSED_F1:
- case OP_UNUSED_FC:
- case OP_UNUSED_FD:
- case OP_UNUSED_FE:
case OP_UNUSED_FF:
assert(width == 0);
break;
@@ -625,6 +628,18 @@
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
+ case OP_IGET_VOLATILE:
+ case OP_IPUT_VOLATILE:
+ case OP_SGET_VOLATILE:
+ case OP_SPUT_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SPUT_OBJECT_VOLATILE:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
flags = kInstrCanContinue | kInstrCanThrow;
break;
@@ -646,20 +661,8 @@
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
- case OP_UNUSED_E3:
- case OP_UNUSED_E4:
- case OP_UNUSED_E5:
- case OP_UNUSED_E6:
- case OP_UNUSED_E7:
- case OP_UNUSED_E8:
- case OP_UNUSED_E9:
- case OP_UNUSED_EA:
- case OP_UNUSED_EB:
case OP_BREAKPOINT:
case OP_UNUSED_F1:
- case OP_UNUSED_FC:
- case OP_UNUSED_FD:
- case OP_UNUSED_FE:
case OP_UNUSED_FF:
break;
@@ -966,6 +969,20 @@
case OP_THROW_VERIFICATION_ERROR:
fmt = kFmt20bc;
break;
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
+ case OP_IGET_VOLATILE:
+ case OP_IPUT_VOLATILE:
+ case OP_SGET_VOLATILE:
+ case OP_SPUT_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SPUT_OBJECT_VOLATILE:
+ fmt = kFmt22c;
+ break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
@@ -1002,20 +1019,8 @@
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
- case OP_UNUSED_E3:
- case OP_UNUSED_E4:
- case OP_UNUSED_E5:
- case OP_UNUSED_E6:
- case OP_UNUSED_E7:
- case OP_UNUSED_E8:
- case OP_UNUSED_E9:
- case OP_UNUSED_EA:
- case OP_UNUSED_EB:
case OP_BREAKPOINT:
case OP_UNUSED_F1:
- case OP_UNUSED_FC:
- case OP_UNUSED_FD:
- case OP_UNUSED_FE:
case OP_UNUSED_FF:
fmt = kFmtUnknown;
break;
@@ -1064,7 +1069,7 @@
pDec->vB = INST_B(inst);
break;
case kFmt11n: // op vA, #+B
- pDec->vA = INST_A(inst);
+ pDec->vA = INST_A(inst);
pDec->vB = (s4) (INST_B(inst) << 28) >> 28; // sign extend 4-bit value
break;
case kFmt11x: // op vAA
@@ -1234,9 +1239,10 @@
* works for special OP_NOP entries, including switch statement data tables
* and array data.
*/
-int dexGetInstrOrTableWidthAbs(const InstructionWidth* widths, const u2* insns)
+size_t dexGetInstrOrTableWidthAbs(const InstructionWidth* widths,
+ const u2* insns)
{
- int width;
+ size_t width;
if (*insns == kPackedSwitchSignature) {
width = 4 + insns[1] * 2;
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
index 8449ae5..ad2bc34 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -29,7 +29,7 @@
* (This defines InstructionFormat as an unsigned char to reduce the size
* of the table. This isn't necessary with some compilers, which use an
* integer width appropriate for the number of enum values.)
- *
+ *
* If you add or delete a format, you have to change some or all of:
* - this enum
* - the switch inside dexDecodeInstruction() in InstrUtils.c
@@ -90,8 +90,8 @@
typedef signed char InstructionWidth;
/*
- * Instruction flags, used by the verifier to determine where control
- * can flow to next.
+ * Instruction flags, used by the verifier and JIT to determine where
+ * control can flow to next. Expected to fit in 8 bits.
*/
typedef unsigned char InstructionFlags;
enum InstructionFlags {
@@ -111,6 +111,7 @@
*/
InstructionWidth* dexCreateInstrWidthTable(void);
+#if 0 // no longer used
/*
* Returns the width of the specified instruction, or 0 if not defined.
* Optimized instructions use negative values.
@@ -120,15 +121,17 @@
// assert(/*opCode >= 0 &&*/ opCode < kNumDalvikInstructions);
return widths[opCode];
}
+#endif
/*
* Return the width of the specified instruction, or 0 if not defined.
*/
-DEX_INLINE int dexGetInstrWidthAbs(const InstructionWidth* widths,OpCode opCode)
+DEX_INLINE size_t dexGetInstrWidthAbs(const InstructionWidth* widths,
+ OpCode opCode)
{
//assert(/*opCode >= 0 &&*/ opCode < kNumDalvikInstructions);
- int val = dexGetInstrWidth(widths, opCode);
+ int val = widths[opCode];
if (val < 0)
val = -val;
/* XXX - the no-compare trick may be a cycle slower on ARM */
@@ -140,7 +143,8 @@
* works for special OP_NOP entries, including switch statement data tables
* and array data.
*/
-int dexGetInstrOrTableWidthAbs(const InstructionWidth* widths, const u2* insns);
+size_t dexGetInstrOrTableWidthAbs(const InstructionWidth* widths,
+ const u2* insns);
/*
diff --git a/libdex/OpCode.h b/libdex/OpCode.h
index 58d1702..312ff01 100644
--- a/libdex/OpCode.h
+++ b/libdex/OpCode.h
@@ -45,16 +45,16 @@
* and running int:fast as above
* - repeat for other platforms (x86, ...)
* (see notes in mterp/ReadMe.txt for rebuilding instructions)
- *
+ *
* Verifier / optimizer:
* - update some stuff in analysis/DexOptimize.c, analysis/DexVerify.c,
* and/or analysis/CodeVerify.c as needed
* - verify by running with verifier enabled (it's on by default)
- *
+ *
* Tools:
* - update the OpCodeNames table in dexdump/OpCodeNames.c
* - update dexdump/DexDump.c if an instruction format has changed
- *
+ *
* Note: The Dalvik VM tests (in the tests subdirectory) provide a convenient
* way to test most of the above without doing any rebuilds. In particular,
* test 003-omnibus-opcodes will exercise most of the opcodes.
@@ -108,18 +108,18 @@
OP_NEW_INSTANCE = 0x22,
OP_NEW_ARRAY = 0x23,
-
+
OP_FILLED_NEW_ARRAY = 0x24,
OP_FILLED_NEW_ARRAY_RANGE = 0x25,
OP_FILL_ARRAY_DATA = 0x26,
-
+
OP_THROW = 0x27,
OP_GOTO = 0x28,
OP_GOTO_16 = 0x29,
OP_GOTO_32 = 0x2a,
OP_PACKED_SWITCH = 0x2b,
OP_SPARSE_SWITCH = 0x2c,
-
+
OP_CMPL_FLOAT = 0x2d,
OP_CMPG_FLOAT = 0x2e,
OP_CMPL_DOUBLE = 0x2f,
@@ -145,7 +145,7 @@
OP_UNUSED_41 = 0x41,
OP_UNUSED_42 = 0x42,
OP_UNUSED_43 = 0x43,
-
+
OP_AGET = 0x44,
OP_AGET_WIDE = 0x45,
OP_AGET_OBJECT = 0x46,
@@ -198,7 +198,7 @@
OP_INVOKE_INTERFACE = 0x72,
OP_UNUSED_73 = 0x73,
-
+
OP_INVOKE_VIRTUAL_RANGE = 0x74,
OP_INVOKE_SUPER_RANGE = 0x75,
OP_INVOKE_DIRECT_RANGE = 0x76,
@@ -321,15 +321,17 @@
OP_SHR_INT_LIT8 = 0xe1,
OP_USHR_INT_LIT8 = 0xe2,
- OP_UNUSED_E3 = 0xe3,
- OP_UNUSED_E4 = 0xe4,
- OP_UNUSED_E5 = 0xe5,
- OP_UNUSED_E6 = 0xe6,
- OP_UNUSED_E7 = 0xe7,
- OP_UNUSED_E8 = 0xe8,
- OP_UNUSED_E9 = 0xe9,
- OP_UNUSED_EA = 0xea,
- OP_UNUSED_EB = 0xeb,
+ /* verifier/optimizer output -- nothing below here is generated by "dx" */
+ OP_IGET_VOLATILE = 0xe3,
+ OP_IPUT_VOLATILE = 0xe4,
+ OP_SGET_VOLATILE = 0xe5,
+ OP_SPUT_VOLATILE = 0xe6,
+ OP_IGET_OBJECT_VOLATILE = 0xe7,
+
+ OP_IGET_WIDE_VOLATILE = 0xe8,
+ OP_IPUT_WIDE_VOLATILE = 0xe9,
+ OP_SGET_WIDE_VOLATILE = 0xea,
+ OP_SPUT_WIDE_VOLATILE = 0xeb,
/*
* The "breakpoint" instruction is special, in that it should never
@@ -340,7 +342,6 @@
*/
OP_BREAKPOINT = 0xec,
- /* optimizer output -- these are never generated by "dx" */
OP_THROW_VERIFICATION_ERROR = 0xed,
OP_EXECUTE_INLINE = 0xee,
OP_EXECUTE_INLINE_RANGE = 0xef,
@@ -358,10 +359,11 @@
OP_INVOKE_VIRTUAL_QUICK_RANGE = 0xf9,
OP_INVOKE_SUPER_QUICK = 0xfa,
OP_INVOKE_SUPER_QUICK_RANGE = 0xfb,
- OP_UNUSED_FC = 0xfc, /* OP_INVOKE_DIRECT_QUICK? */
- OP_UNUSED_FD = 0xfd, /* OP_INVOKE_DIRECT_QUICK_RANGE? */
- OP_UNUSED_FE = 0xfe, /* OP_INVOKE_INTERFACE_QUICK? */
- OP_UNUSED_FF = 0xff, /* OP_INVOKE_INTERFACE_QUICK_RANGE*/
+ OP_IPUT_OBJECT_VOLATILE = 0xfc,
+ OP_SGET_OBJECT_VOLATILE = 0xfd,
+ OP_SPUT_OBJECT_VOLATILE = 0xfe,
+
+ OP_UNUSED_FF = 0xff, /* reserved for code expansion */
} OpCode;
#define kNumDalvikInstructions 256
@@ -627,15 +629,15 @@
H(OP_SHL_INT_LIT8), \
H(OP_SHR_INT_LIT8), \
H(OP_USHR_INT_LIT8), \
- H(OP_UNUSED_E3), \
- H(OP_UNUSED_E4), \
- H(OP_UNUSED_E5), \
- H(OP_UNUSED_E6), \
- H(OP_UNUSED_E7), \
- H(OP_UNUSED_E8), \
- H(OP_UNUSED_E9), \
- H(OP_UNUSED_EA), \
- H(OP_UNUSED_EB), \
+ H(OP_IGET_VOLATILE), \
+ H(OP_IPUT_VOLATILE), \
+ H(OP_SGET_VOLATILE), \
+ H(OP_SPUT_VOLATILE), \
+ H(OP_IGET_OBJECT_VOLATILE), \
+ H(OP_IGET_WIDE_VOLATILE), \
+ H(OP_IPUT_WIDE_VOLATILE), \
+ H(OP_SGET_WIDE_VOLATILE), \
+ H(OP_SPUT_WIDE_VOLATILE), \
H(OP_BREAKPOINT), \
H(OP_THROW_VERIFICATION_ERROR), \
H(OP_EXECUTE_INLINE), \
@@ -653,9 +655,9 @@
H(OP_INVOKE_VIRTUAL_QUICK_RANGE), \
H(OP_INVOKE_SUPER_QUICK), \
H(OP_INVOKE_SUPER_QUICK_RANGE), \
- H(OP_UNUSED_FC), \
- H(OP_UNUSED_FD), \
- H(OP_UNUSED_FE), \
+ H(OP_IPUT_OBJECT_VOLATILE), \
+ H(OP_SGET_OBJECT_VOLATILE), \
+ H(OP_SPUT_OBJECT_VOLATILE), \
H(OP_UNUSED_FF), \
};
diff --git a/dexdump/OpCodeNames.c b/libdex/OpCodeNames.c
similarity index 93%
rename from dexdump/OpCodeNames.c
rename to libdex/OpCodeNames.c
index 97b707e..c182d4e 100644
--- a/dexdump/OpCodeNames.c
+++ b/libdex/OpCodeNames.c
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Table of Dalvik opcode names.
*/
#include "OpCodeNames.h"
+#include <assert.h>
+
/*
* The following two lines work, but slashes and dashes both turn into
* underscores, and the strings are all upper case. The output is easier
@@ -287,15 +290,15 @@
"shl-int/lit8",
"shr-int/lit8",
"ushr-int/lit8",
- "UNUSED",
- "UNUSED",
- "UNUSED",
- "UNUSED",
- "UNUSED",
- "UNUSED",
- "UNUSED",
- "UNUSED",
- "UNUSED",
+ "+iget-volatile",
+ "+iput-volatile",
+ "+sget-volatile",
+ "+sput-volatile",
+ "+iget-object-volatile",
+ "+iget-wide-volatile",
+ "+iput-wide-volatile",
+ "+sget-wide-volatile",
+ "+sput-wide-volatile",
"^breakpoint", // does not appear in DEX files
"^throw-verification-error", // does not appear in DEX files
"+execute-inline",
@@ -314,17 +317,17 @@
"+invoke-virtual-quick/range",
"+invoke-super-quick",
"+invoke-super-quick/range",
- "UNUSED",
- "UNUSED",
- "UNUSED",
+ "+iput-object-volatile",
+ "+sget-object-volatile",
+ "+sput-object-volatile",
"UNUSED",
};
/*
* Return the name of an opcode.
*/
-const char* getOpcodeName(OpCode op)
+const char* dexGetOpcodeName(OpCode op)
{
+ assert(op >= 0 && op < kNumDalvikInstructions);
return gOpNames[op];
}
-
diff --git a/dexdump/OpCodeNames.h b/libdex/OpCodeNames.h
similarity index 79%
rename from dexdump/OpCodeNames.h
rename to libdex/OpCodeNames.h
index 1aec0d1..f81368d 100644
--- a/dexdump/OpCodeNames.h
+++ b/libdex/OpCodeNames.h
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Dalvik opcode names.
- */
-#ifndef _DEXDUMP_OPCODENAMES
-#define _DEXDUMP_OPCODENAMES
+ */
+#ifndef _LIBDEX_OPCODENAMES
+#define _LIBDEX_OPCODENAMES
-#include "libdex/OpCode.h"
+#include "OpCode.h"
-const char* getOpcodeName(OpCode op);
+const char* dexGetOpcodeName(OpCode op);
-#endif /*_DEXDUMP_OPCODENAMES*/
+#endif /*_LIBDEX_OPCODENAMES*/
diff --git a/libdex/OptInvocation.c b/libdex/OptInvocation.c
index 8ce918b..df5f8d9 100644
--- a/libdex/OptInvocation.c
+++ b/libdex/OptInvocation.c
@@ -140,4 +140,3 @@
return 0;
}
-
diff --git a/libdex/SysUtil.c b/libdex/SysUtil.c
index 7c6aaef..e2b1fff 100644
--- a/libdex/SysUtil.c
+++ b/libdex/SysUtil.c
@@ -24,20 +24,13 @@
#include <stdio.h>
#include <unistd.h>
#include <string.h>
-
#ifdef HAVE_POSIX_FILEMAP
-#include <sys/mman.h>
+# include <sys/mman.h>
#endif
-
#include <limits.h>
#include <errno.h>
-/*
- * Having trouble finding a portable way to get this. sysconf(_SC_PAGE_SIZE)
- * seems appropriate, but we don't have that on the device. Some systems
- * have getpagesize(2), though the linux man page has some odd cautions.
- */
-#define DEFAULT_PAGE_SIZE 4096
+#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
/*
@@ -266,35 +259,25 @@
}
/*
- * Map part of a file (from fd's current offset) into a shared, read-only
- * memory segment.
+ * Map part of a file into a shared, read-only memory segment. The "start"
+ * offset is absolute, not relative.
*
* On success, returns 0 and fills out "pMap". On failure, returns a nonzero
* value and does not disturb "pMap".
*/
-int sysMapFileSegmentInShmem(int fd, off_t start, long length,
+int sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
MemMapping* pMap)
{
#ifdef HAVE_POSIX_FILEMAP
- off_t dummy;
- size_t fileLength, actualLength;
+ size_t actualLength;
off_t actualStart;
int adjust;
void* memPtr;
assert(pMap != NULL);
- if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
- return -1;
-
- if (start + length > (long)fileLength) {
- LOGW("bad segment: st=%d len=%ld flen=%d\n",
- (int) start, length, (int) fileLength);
- return -1;
- }
-
/* adjust to be page-aligned */
- adjust = start % DEFAULT_PAGE_SIZE;
+ adjust = start % SYSTEM_PAGE_SIZE;
actualStart = start - adjust;
actualLength = length + adjust;
@@ -400,3 +383,26 @@
memcpy(dst, src, sizeof(MemMapping));
}
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg)
+{
+ while (count != 0) {
+ ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count));
+ if (actual < 0) {
+ int err = errno;
+ LOGE("%s: write failed: %s\n", logMsg, strerror(err));
+ return err;
+ } else if (actual != (ssize_t) count) {
+ LOGD("%s: partial write (will retry): (%d of %zd)\n",
+ logMsg, (int) actual, count);
+ buf = (const void*) (((const u1*) buf) + actual);
+ }
+ count -= actual;
+ }
+
+ return 0;
+}
diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h
index b300a7b..01b4e1a 100644
--- a/libdex/SysUtil.h
+++ b/libdex/SysUtil.h
@@ -80,7 +80,7 @@
/*
* Like sysMapFileInShmemReadOnly, but on only part of a file.
*/
-int sysMapFileSegmentInShmem(int fd, off_t start, long length,
+int sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
MemMapping* pMap);
/*
@@ -106,4 +106,11 @@
*/
void sysReleaseShmem(MemMapping* pMap);
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg);
+
#endif /*_DALVIK_SYSUTIL*/
diff --git a/libdex/ZipArchive.c b/libdex/ZipArchive.c
index 7c7e18e..756f488 100644
--- a/libdex/ZipArchive.c
+++ b/libdex/ZipArchive.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Read-only access to Zip archives, with minimal heap allocation.
*/
@@ -21,10 +22,13 @@
#include <zlib.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
+#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
+
/*
* Zip file constants.
@@ -32,6 +36,7 @@
#define kEOCDSignature 0x06054b50
#define kEOCDLen 22
#define kEOCDNumEntries 8 // offset to #of entries in file
+#define kEOCDSize 12 // size of the central directory
#define kEOCDFileOffset 16 // offset to central directory
#define kMaxCommentLen 65535 // longest possible in ushort
@@ -72,7 +77,7 @@
if (ent < 0 || ent >= pArchive->mHashTableSize ||
pArchive->mHashTable[ent].name == NULL)
{
- LOGW("Invalid ZipEntry %p (%ld)\n", entry, ent);
+ LOGW("Zip: invalid ZipEntry %p (%ld)\n", entry, ent);
return -1;
}
return ent;
@@ -115,7 +120,7 @@
*/
static u2 get2LE(unsigned char const* pSrc)
{
- return pSrc[0] | (pSrc[1] << 8);
+ return pSrc[0] | (pSrc[1] << 8);
}
/*
@@ -134,156 +139,205 @@
}
/*
- * Parse the Zip archive, verifying its contents and initializing internal
- * data structures.
+ * Find the zip Central Directory and memory-map it.
+ *
+ * On success, returns 0 after populating fields from the EOCD area:
+ * mDirectoryOffset
+ * mDirectoryMap
+ * mNumEntries
*/
-static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap)
+static int mapCentralDirectory(int fd, const char* debugFileName,
+ ZipArchive* pArchive)
{
-#define CHECK_OFFSET(_off) { \
- if ((unsigned int) (_off) >= maxOffset) { \
- LOGE("ERROR: bad offset %u (max %d): %s\n", \
- (unsigned int) (_off), maxOffset, #_off); \
- goto bail; \
- } \
- }
- bool result = false;
- const unsigned char* basePtr = (const unsigned char*)pMap->addr;
- const unsigned char* ptr;
- size_t length = pMap->length;
- unsigned int i, numEntries, cdOffset;
- unsigned int val;
+ u1* scanBuf = NULL;
+ int result = -1;
/*
- * The first 4 bytes of the file will either be the local header
- * signature for the first file (kLFHSignature) or, if the archive doesn't
- * have any files in it, the end-of-central-directory signature
- * (kEOCDSignature).
+ * Get and test file length.
*/
- val = get4LE(basePtr);
- if (val == kEOCDSignature) {
- LOGI("Found Zip archive, but it looks empty\n");
- goto bail;
- } else if (val != kLFHSignature) {
- LOGV("Not a Zip archive (found 0x%08x)\n", val);
+ off_t fileLength = lseek(fd, 0, SEEK_END);
+ if (fileLength < kEOCDLen) {
+ LOGV("Zip: length %ld is too small to be zip\n", (long) fileLength);
goto bail;
}
/*
- * Find the EOCD. We'll find it immediately unless they have a file
- * comment.
- */
- ptr = basePtr + length - kEOCDLen;
-
- while (ptr >= basePtr) {
- if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
- break;
- ptr--;
- }
- if (ptr < basePtr) {
- LOGI("Could not find end-of-central-directory in Zip\n");
- goto bail;
- }
-
- /*
- * There are two interesting items in the EOCD block: the number of
- * entries in the file, and the file offset of the start of the
- * central directory.
+ * Perform the traditional EOCD snipe hunt.
*
- * (There's actually a count of the #of entries in this file, and for
- * all files which comprise a spanned archive, but for our purposes
- * we're only interested in the current file. Besides, we expect the
- * two to be equivalent for our stuff.)
+ * We're searching for the End of Central Directory magic number,
+ * which appears at the start of the EOCD block. It's followed by
+ * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
+ * need to read the last part of the file into a buffer, dig through
+ * it to find the magic number, parse some values out, and use those
+ * to determine the extent of the CD.
+ *
+ * We start by pulling in the last part of the file.
*/
- numEntries = get2LE(ptr + kEOCDNumEntries);
- cdOffset = get4LE(ptr + kEOCDFileOffset);
+ size_t readAmount = kMaxEOCDSearch;
+ if (readAmount > (size_t) fileLength)
+ readAmount = fileLength;
+ off_t searchStart = fileLength - readAmount;
- /* valid offsets are [0,EOCD] */
- unsigned int maxOffset;
- maxOffset = (ptr - basePtr) +1;
-
- LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
- if (numEntries == 0 || cdOffset >= length) {
- LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
- numEntries, cdOffset, length);
+ scanBuf = (u1*) malloc(readAmount);
+ if (lseek(fd, searchStart, SEEK_SET) != searchStart) {
+ LOGW("Zip: seek %ld failed: %s\n", (long) searchStart, strerror(errno));
goto bail;
}
+ ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, readAmount));
+ if (actual != (ssize_t) readAmount) {
+ LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Scan backward for the EOCD magic. In an archive without a trailing
+ * comment, we'll find it on the first try. (We may want to consider
+ * doing an initial minimal read; if we don't find it, retry with a
+ * second read as above.)
+ */
+ int i;
+ for (i = readAmount - kEOCDLen; i >= 0; i--) {
+ if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
+ LOGV("+++ Found EOCD at buf+%d\n", i);
+ break;
+ }
+ }
+ if (i < 0) {
+ LOGD("Zip: EOCD not found, %s is not zip\n", debugFileName);
+ goto bail;
+ }
+
+ off_t eocdOffset = searchStart + i;
+ const u1* eocdPtr = scanBuf + i;
+
+ assert(eocdOffset < fileLength);
+
+ /*
+ * Grab the CD offset and size, and the number of entries in the
+ * archive. Verify that they look reasonable.
+ */
+ u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries);
+ u4 dirSize = get4LE(eocdPtr + kEOCDSize);
+ u4 dirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+
+ if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
+ LOGW("Zip: bad offsets (dir %ld, size %u, eocd %ld)\n",
+ (long) dirOffset, dirSize, (long) eocdOffset);
+ goto bail;
+ }
+ if (numEntries == 0) {
+ LOGW("Zip: empty archive?\n");
+ goto bail;
+ }
+
+ LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
+ numEntries, dirSize, dirOffset);
+
+ /*
+ * It all looks good. Create a mapping for the CD, and set the fields
+ * in pArchive.
+ */
+ if (sysMapFileSegmentInShmem(fd, dirOffset, dirSize,
+ &pArchive->mDirectoryMap) != 0)
+ {
+ LOGW("Zip: cd map failed\n");
+ goto bail;
+ }
+
+ pArchive->mNumEntries = numEntries;
+ pArchive->mDirectoryOffset = dirOffset;
+
+ result = 0;
+
+bail:
+ free(scanBuf);
+ return result;
+}
+
+/*
+ * Parses the Zip archive's Central Directory. Allocates and populates the
+ * hash table.
+ *
+ * Returns 0 on success.
+ */
+static int parseZipArchive(ZipArchive* pArchive)
+{
+ int result = -1;
+ const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr;
+ size_t cdLength = pArchive->mDirectoryMap.length;
+ int numEntries = pArchive->mNumEntries;
/*
* Create hash table. We have a minimum 75% load factor, possibly as
* low as 50% after we round off to a power of 2. There must be at
* least one unused entry to avoid an infinite loop during creation.
*/
- pArchive->mNumEntries = numEntries;
pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3);
pArchive->mHashTable = (ZipHashEntry*)
calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry));
/*
* Walk through the central directory, adding entries to the hash
- * table.
+ * table and verifying values.
*/
- ptr = basePtr + cdOffset;
+ const u1* ptr = cdPtr;
+ int i;
for (i = 0; i < numEntries; i++) {
- unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
- const unsigned char* localHdr;
- unsigned int hash;
-
if (get4LE(ptr) != kCDESignature) {
- LOGW("Missed a central dir sig (at %d)\n", i);
+ LOGW("Zip: missed a central dir sig (at %d)\n", i);
goto bail;
}
- if (ptr + kCDELen > basePtr + length) {
- LOGW("Ran off the end (at %d)\n", i);
+ if (ptr + kCDELen > cdPtr + cdLength) {
+ LOGW("Zip: ran off the end (at %d)\n", i);
goto bail;
}
- localHdrOffset = get4LE(ptr + kCDELocalOffset);
- CHECK_OFFSET(localHdrOffset);
+ long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+ if (localHdrOffset >= pArchive->mDirectoryOffset) {
+ LOGW("Zip: bad LFH offset %ld at entry %d\n", localHdrOffset, i);
+ goto bail;
+ }
+
+ unsigned int fileNameLen, extraLen, commentLen, hash;
fileNameLen = get2LE(ptr + kCDENameLen);
extraLen = get2LE(ptr + kCDEExtraLen);
commentLen = get2LE(ptr + kCDECommentLen);
- //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
- // i, localHdrOffset, fileNameLen, extraLen, commentLen);
- //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);
-
/* add the CDE filename to the hash table */
hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
addToHash(pArchive, (const char*)ptr + kCDELen, fileNameLen, hash);
- localHdr = basePtr + localHdrOffset;
- if (get4LE(localHdr) != kLFHSignature) {
- LOGW("Bad offset to local header: %d (at %d)\n",
- localHdrOffset, i);
+ ptr += kCDELen + fileNameLen + extraLen + commentLen;
+ if ((size_t)(ptr - cdPtr) > cdLength) {
+ LOGW("Zip: bad CD advance (%d vs %zd) at entry %d\n",
+ (int) (ptr - cdPtr), cdLength, i);
goto bail;
}
-
- ptr += kCDELen + fileNameLen + extraLen + commentLen;
- CHECK_OFFSET(ptr - basePtr);
}
+ LOGV("+++ zip good scan %d entries\n", numEntries);
- result = true;
+ result = 0;
bail:
return result;
-#undef CHECK_OFFSET
}
/*
- * Open the specified file read-only. We memory-map the entire thing and
- * parse the contents.
+ * Open the specified file read-only. We examine the contents and verify
+ * that it appears to be a valid zip file.
*
* This will be called on non-Zip files, especially during VM startup, so
* we don't want to be too noisy about certain types of failure. (Do
* we want a "quiet" flag?)
*
- * On success, we fill out the contents of "pArchive" and return 0.
+ * On success, we fill out the contents of "pArchive" and return 0. On
+ * failure we return the errno value.
*/
int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive)
{
int fd, err;
- LOGV("Opening archive '%s' %p\n", fileName, pArchive);
+ LOGV("Opening as zip '%s' %p\n", fileName, pArchive);
memset(pArchive, 0, sizeof(ZipArchive));
@@ -298,47 +352,32 @@
}
/*
- * Prepare to access a ZipArchive in an open file descriptor.
+ * Prepare to access a ZipArchive through an open file descriptor.
+ *
+ * On success, we fill out the contents of "pArchive" and return 0.
*/
int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive)
{
- MemMapping map;
- int err;
+ int result = -1;
- map.addr = NULL;
memset(pArchive, 0, sizeof(*pArchive));
-
pArchive->mFd = fd;
- if (sysMapFileInShmemReadOnly(pArchive->mFd, &map) != 0) {
- err = -1;
- LOGW("Map of '%s' failed\n", debugFileName);
+ if (mapCentralDirectory(fd, debugFileName, pArchive) != 0)
goto bail;
- }
- if (map.length < kEOCDLen) {
- err = -1;
- LOGV("File '%s' too small to be zip (%zd)\n", debugFileName,map.length);
- goto bail;
- }
-
- if (!parseZipArchive(pArchive, &map)) {
- err = -1;
- LOGV("Parsing '%s' failed\n", debugFileName);
+ if (parseZipArchive(pArchive) != 0) {
+ LOGV("Zip: parsing '%s' failed\n", debugFileName);
goto bail;
}
/* success */
- err = 0;
- sysCopyMap(&pArchive->mMap, &map);
- map.addr = NULL;
+ result = 0;
bail:
- if (err != 0)
+ if (result != 0)
dexZipCloseArchive(pArchive);
- if (map.addr != NULL)
- sysReleaseShmem(&map);
- return err;
+ return result;
}
@@ -354,10 +393,12 @@
if (pArchive->mFd >= 0)
close(pArchive->mFd);
- sysReleaseShmem(&pArchive->mMap);
+ sysReleaseShmem(&pArchive->mDirectoryMap);
free(pArchive->mHashTable);
+ /* ensure nobody tries to use the ZipArchive after it's closed */
+ pArchive->mDirectoryOffset = -1;
pArchive->mFd = -1;
pArchive->mNumEntries = -1;
pArchive->mHashTableSize = -1;
@@ -382,7 +423,7 @@
memcmp(pArchive->mHashTable[ent].name, entryName, nameLen) == 0)
{
/* match */
- return (ZipEntry) (ent + kZipEntryAdj);
+ return (ZipEntry)(long)(ent + kZipEntryAdj);
}
ent = (ent + 1) & (hashTableSize-1);
@@ -421,27 +462,27 @@
/*
* Get the useful fields from the zip entry.
*
- * Returns "false" if the offsets to the fields or the contents of the fields
- * appear to be bogus.
+ * Returns non-zero if the contents of the fields (particularly the data
+ * offset) appear to be bogus.
*/
-bool dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
- int* pMethod, long* pUncompLen, long* pCompLen, off_t* pOffset,
+int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
+ int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
long* pModWhen, long* pCrc32)
{
int ent = entryToIndex(pArchive, entry);
if (ent < 0)
- return false;
+ return -1;
/*
* Recover the start of the central directory entry from the filename
- * pointer.
+ * pointer. The filename is the first entry past the fixed-size data,
+ * so we can just subtract back from that.
*/
const unsigned char* basePtr = (const unsigned char*)
- pArchive->mMap.addr;
+ pArchive->mDirectoryMap.addr;
const unsigned char* ptr = (const unsigned char*)
pArchive->mHashTable[ent].name;
- size_t zipLength =
- pArchive->mMap.length;
+ off_t cdOffset = pArchive->mDirectoryOffset;
ptr -= kCDELen;
@@ -454,87 +495,120 @@
if (pCrc32 != NULL)
*pCrc32 = get4LE(ptr + kCDECRC);
+ size_t compLen = get4LE(ptr + kCDECompLen);
+ if (pCompLen != NULL)
+ *pCompLen = compLen;
+ size_t uncompLen = get4LE(ptr + kCDEUncompLen);
+ if (pUncompLen != NULL)
+ *pUncompLen = uncompLen;
+
/*
- * We need to make sure that the lengths are not so large that somebody
- * trying to map the compressed or uncompressed data runs off the end
- * of the mapped region.
+ * If requested, determine the offset of the start of the data. All we
+ * have is the offset to the Local File Header, which is variable size,
+ * so we have to read the contents of the struct to figure out where
+ * the actual data starts.
+ *
+ * We also need to make sure that the lengths are not so large that
+ * somebody trying to map the compressed or uncompressed data runs
+ * off the end of the mapped region.
+ *
+ * Note we don't verify compLen/uncompLen if they don't request the
+ * dataOffset, because dataOffset is expensive to determine. However,
+ * if they don't have the file offset, they're not likely to be doing
+ * anything with the contents.
*/
- unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset);
- if (localHdrOffset + kLFHLen >= zipLength) {
- LOGE("ERROR: bad local hdr offset in zip\n");
- return false;
- }
- const unsigned char* localHdr = basePtr + localHdrOffset;
- off_t dataOffset = localHdrOffset + kLFHLen
- + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen);
- if ((unsigned long) dataOffset >= zipLength) {
- LOGE("ERROR: bad data offset in zip\n");
- return false;
- }
-
- if (pCompLen != NULL) {
- *pCompLen = get4LE(ptr + kCDECompLen);
- if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) {
- LOGE("ERROR: bad compressed length in zip\n");
- return false;
- }
- }
- if (pUncompLen != NULL) {
- *pUncompLen = get4LE(ptr + kCDEUncompLen);
- if (*pUncompLen < 0) {
- LOGE("ERROR: negative uncompressed length in zip\n");
- return false;
- }
- if (method == kCompressStored &&
- (size_t)(dataOffset + *pUncompLen) >= zipLength)
- {
- LOGE("ERROR: bad uncompressed length in zip\n");
- return false;
- }
- }
-
if (pOffset != NULL) {
+ long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+ if (localHdrOffset + kLFHLen >= cdOffset) {
+ LOGW("Zip: bad local hdr offset in zip\n");
+ return -1;
+ }
+
+ u1 lfhBuf[kLFHLen];
+ if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
+ LOGW("Zip: failed seeking to lfh at offset %ld\n", localHdrOffset);
+ return -1;
+ }
+ ssize_t actual =
+ TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf)));
+ if (actual != sizeof(lfhBuf)) {
+ LOGW("Zip: failed reading lfh from offset %ld\n", localHdrOffset);
+ return -1;
+ }
+
+ if (get4LE(lfhBuf) != kLFHSignature) {
+ LOGW("Zip: didn't find signature at start of lfh, offset=%ld\n",
+ localHdrOffset);
+ return -1;
+ }
+
+ off_t dataOffset = localHdrOffset + kLFHLen
+ + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
+ if (dataOffset >= cdOffset) {
+ LOGW("Zip: bad data offset %ld in zip\n", (long) dataOffset);
+ return -1;
+ }
+
+ /* check lengths */
+ if ((off_t)(dataOffset + compLen) > cdOffset) {
+ LOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)\n",
+ (long) dataOffset, compLen, (long) cdOffset);
+ return -1;
+ }
+
+ if (method == kCompressStored &&
+ (off_t)(dataOffset + uncompLen) > cdOffset)
+ {
+ LOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)\n",
+ (long) dataOffset, uncompLen, (long) cdOffset);
+ return -1;
+ }
+
*pOffset = dataOffset;
}
- return true;
+ return 0;
}
/*
- * Uncompress "deflate" data from one buffer to an open file descriptor.
+ * Uncompress "deflate" data from the archive's file to an open file
+ * descriptor.
*/
-static bool inflateToFile(int fd, const void* inBuf, long uncompLen,
- long compLen)
+static int inflateToFile(int inFd, int outFd, size_t uncompLen, size_t compLen)
{
- bool result = false;
- const int kWriteBufSize = 32768;
- unsigned char writeBuf[kWriteBufSize];
+ int result = -1;
+ const size_t kBufSize = 32768;
+ unsigned char* readBuf = (unsigned char*) malloc(kBufSize);
+ unsigned char* writeBuf = (unsigned char*) malloc(kBufSize);
z_stream zstream;
int zerr;
+ if (readBuf == NULL || writeBuf == NULL)
+ goto bail;
+
/*
* Initialize the zlib stream struct.
*/
- memset(&zstream, 0, sizeof(zstream));
+ memset(&zstream, 0, sizeof(zstream));
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zstream.opaque = Z_NULL;
- zstream.next_in = (Bytef*)inBuf;
- zstream.avail_in = compLen;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
zstream.next_out = (Bytef*) writeBuf;
- zstream.avail_out = sizeof(writeBuf);
+ zstream.avail_out = kBufSize;
zstream.data_type = Z_UNKNOWN;
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
+ /*
+ * Use the undocumented "negative window bits" feature to tell zlib
+ * that there's no zlib header waiting for it.
+ */
zerr = inflateInit2(&zstream, -MAX_WBITS);
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
LOGE("Installed zlib is not compatible with linked version (%s)\n",
ZLIB_VERSION);
} else {
- LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+ LOGW("Call to inflateInit2 failed (zerr=%d)\n", zerr);
}
goto bail;
}
@@ -543,12 +617,27 @@
* Loop while we have more to do.
*/
do {
- /*
- * Expand data.
- */
+ /* read as much as we can */
+ if (zstream.avail_in == 0) {
+ size_t getSize = (compLen > kBufSize) ? kBufSize : compLen;
+
+ ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, readBuf, getSize));
+ if (actual != (ssize_t) getSize) {
+ LOGW("Zip: inflate read failed (%d vs %zd)\n",
+ (int)actual, getSize);
+ goto z_bail;
+ }
+
+ compLen -= getSize;
+
+ zstream.next_in = readBuf;
+ zstream.avail_in = getSize;
+ }
+
+ /* uncompress the data */
zerr = inflate(&zstream, Z_NO_FLUSH);
if (zerr != Z_OK && zerr != Z_STREAM_END) {
- LOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+ LOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
zerr, zstream.next_in, zstream.avail_in,
zstream.next_out, zstream.avail_out);
goto z_bail;
@@ -556,90 +645,103 @@
/* write when we're full or when we're done */
if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
+ (zerr == Z_STREAM_END && zstream.avail_out != kBufSize))
{
- long writeSize = zstream.next_out - writeBuf;
- int cc = write(fd, writeBuf, writeSize);
- if (cc != (int) writeSize) {
- if (cc < 0) {
- LOGW("write failed in inflate: %s\n", strerror(errno));
- } else {
- LOGW("partial write in inflate (%d vs %ld)\n",
- cc, writeSize);
- }
+ size_t writeSize = zstream.next_out - writeBuf;
+ if (sysWriteFully(outFd, writeBuf, writeSize, "Zip inflate") != 0)
goto z_bail;
- }
zstream.next_out = writeBuf;
- zstream.avail_out = sizeof(writeBuf);
+ zstream.avail_out = kBufSize;
}
} while (zerr == Z_OK);
assert(zerr == Z_STREAM_END); /* other errors should've been caught */
/* paranoia */
- if ((long) zstream.total_out != uncompLen) {
- LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+ if (zstream.total_out != uncompLen) {
+ LOGW("Zip: size mismatch on inflated file (%ld vs %zd)\n",
zstream.total_out, uncompLen);
goto z_bail;
}
- result = true;
+ result = 0;
z_bail:
inflateEnd(&zstream); /* free up any allocated structures */
bail:
+ free(readBuf);
+ free(writeBuf);
return result;
}
/*
+ * Copy bytes from input to output.
+ */
+static int copyFileToFile(int inFd, int outFd, size_t uncompLen)
+{
+ const size_t kBufSize = 32768;
+ unsigned char buf[kBufSize];
+
+ while (uncompLen != 0) {
+ size_t getSize = (uncompLen > kBufSize) ? kBufSize : uncompLen;
+
+ ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, buf, getSize));
+ if (actual != (ssize_t) getSize) {
+ LOGW("Zip: copy read failed (%d vs %zd)\n", (int)actual, getSize);
+ return -1;
+ }
+
+ if (sysWriteFully(outFd, buf, getSize, "Zip copy") != 0)
+ return -1;
+
+ uncompLen -= getSize;
+ }
+
+ return 0;
+}
+
+/*
* Uncompress an entry, in its entirety, to an open file descriptor.
*
* TODO: this doesn't verify the data's CRC, but probably should (especially
* for uncompressed data).
*/
-bool dexZipExtractEntryToFile(const ZipArchive* pArchive,
+int dexZipExtractEntryToFile(const ZipArchive* pArchive,
const ZipEntry entry, int fd)
{
- bool result = false;
+ int result = -1;
int ent = entryToIndex(pArchive, entry);
- if (ent < 0)
- return -1;
+ if (ent < 0) {
+ LOGW("Zip: extract can't find entry %p\n", entry);
+ goto bail;
+ }
- const unsigned char* basePtr = (const unsigned char*)pArchive->mMap.addr;
int method;
- long uncompLen, compLen;
- off_t offset;
+ size_t uncompLen, compLen;
+ off_t dataOffset;
- if (!dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen,
- &offset, NULL, NULL))
+ if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen,
+ &dataOffset, NULL, NULL) != 0)
{
goto bail;
}
+ if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) {
+ LOGW("Zip: lseek to data at %ld failed\n", (long) dataOffset);
+ goto bail;
+ }
if (method == kCompressStored) {
- ssize_t actual;
-
- actual = write(fd, basePtr + offset, uncompLen);
- if (actual < 0) {
- LOGE("Write failed: %s\n", strerror(errno));
+ if (copyFileToFile(pArchive->mFd, fd, uncompLen) != 0)
goto bail;
- } else if (actual != uncompLen) {
- LOGE("Partial write during uncompress (%d of %ld)\n",
- (int) actual, uncompLen);
- goto bail;
- } else {
- LOGI("+++ successful write\n");
- }
} else {
- if (!inflateToFile(fd, basePtr+offset, uncompLen, compLen))
+ if (inflateToFile(pArchive->mFd, fd, uncompLen, compLen) != 0)
goto bail;
}
- result = true;
+ result = 0;
bail:
return result;
}
-
diff --git a/libdex/ZipArchive.h b/libdex/ZipArchive.h
index 0cd98b2..bf4edf9 100644
--- a/libdex/ZipArchive.h
+++ b/libdex/ZipArchive.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Read-only access to Zip archives, with minimal heap allocation.
*/
@@ -41,12 +42,15 @@
/*
* Read-only Zip archive.
*
- * We want "open" and "find entry by name" to be fast operations, and we
- * want to use as little memory as possible. We memory-map the file,
- * and load a hash table with pointers to the filenames (which aren't
- * null-terminated). The other fields are at a fixed offset from the
- * filename, so we don't need to extract those (but we do need to byte-read
- * and endian-swap them every time we want them).
+ * We want "open" and "find entry by name" to be fast operations, and
+ * we want to use as little memory as possible. We memory-map the zip
+ * central directory, and load a hash table with pointers to the filenames
+ * (which aren't null-terminated). The other fields are at a fixed offset
+ * from the filename, so we don't need to extract those (but we do need
+ * to byte-read and endian-swap them every time we want them).
+ *
+ * It's possible that somebody has handed us a massive (~1GB) zip archive,
+ * so we can't expect to mmap the entire file.
*
* To speed comparisons when doing a lookup by name, we could make the mapping
* "private" (copy-on-write) and null-terminate the filenames after verifying
@@ -58,8 +62,9 @@
/* open Zip archive */
int mFd;
- /* mapped file */
- MemMapping mMap;
+ /* mapped central directory area */
+ off_t mDirectoryOffset;
+ MemMapping mDirectoryMap;
/* number of entries in the Zip archive */
int mNumEntries;
@@ -121,9 +126,11 @@
/*
* Retrieve one or more of the "interesting" fields. Non-NULL pointers
* are filled in.
+ *
+ * Returns 0 on success.
*/
-bool dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
- int* pMethod, long* pUncompLen, long* pCompLen, off_t* pOffset,
+int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
+ int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
long* pModWhen, long* pCrc32);
/*
@@ -136,10 +143,10 @@
dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, &val, NULL, NULL);
return (long) val;
}
-DEX_INLINE long dexGetZipEntryUncompLen(const ZipArchive* pArchive,
+DEX_INLINE size_t dexGetZipEntryUncompLen(const ZipArchive* pArchive,
const ZipEntry entry)
{
- long val = 0;
+ size_t val = 0;
dexZipGetEntryInfo(pArchive, entry, NULL, &val, NULL, NULL, NULL, NULL);
return val;
}
@@ -160,8 +167,10 @@
/*
* Uncompress and write an entry to a file descriptor.
+ *
+ * Returns 0 on success.
*/
-bool dexZipExtractEntryToFile(const ZipArchive* pArchive,
+int dexZipExtractEntryToFile(const ZipArchive* pArchive,
const ZipEntry entry, int fd);
/*
diff --git a/libdex/sha1.c b/libdex/sha1.c
index 6289248..dc7e30a 100644
--- a/libdex/sha1.c
+++ b/libdex/sha1.c
@@ -16,7 +16,7 @@
100% Public Domain
-----------------
-Modified 7/98
+Modified 7/98
By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain
diff --git a/libnativehelper/Android.mk b/libnativehelper/Android.mk
index 552f139..2acc869 100644
--- a/libnativehelper/Android.mk
+++ b/libnativehelper/Android.mk
@@ -36,7 +36,6 @@
libutils \
libz \
libcrypto \
- libicudata \
libicuuc \
libicui18n \
libsqlite
diff --git a/libnativehelper/JNIHelp.c b/libnativehelper/JNIHelp.c
index a75b837..59d457b 100644
--- a/libnativehelper/JNIHelp.c
+++ b/libnativehelper/JNIHelp.c
@@ -40,11 +40,15 @@
LOGE("Native registration unable to find class '%s'\n", className);
return -1;
}
+
+ int result = 0;
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
LOGE("RegisterNatives failed for '%s'\n", className);
- return -1;
+ result = -1;
}
- return 0;
+
+ (*env)->DeleteLocalRef(env, clazz);
+ return result;
}
/*
@@ -52,45 +56,113 @@
* be populated with the "binary" class name and, if present, the
* exception message.
*/
-static void getExceptionSummary(JNIEnv* env, jthrowable excep, char* buf,
- size_t bufLen)
+static void getExceptionSummary(JNIEnv* env, jthrowable exception, char* buf, size_t bufLen)
{
- if (excep == NULL)
- return;
+ int success = 0;
- /* get the name of the exception's class; none of these should fail */
- jclass clazz = (*env)->GetObjectClass(env, excep); // exception's class
- jclass jlc = (*env)->GetObjectClass(env, clazz); // java.lang.Class
- jmethodID getNameMethod =
- (*env)->GetMethodID(env, jlc, "getName", "()Ljava/lang/String;");
- jstring className = (*env)->CallObjectMethod(env, clazz, getNameMethod);
+ /* get the name of the exception's class */
+ jclass exceptionClazz = (*env)->GetObjectClass(env, exception); // can't fail
+ jclass classClazz = (*env)->GetObjectClass(env, exceptionClazz); // java.lang.Class, can't fail
+ jmethodID classGetNameMethod = (*env)->GetMethodID(
+ env, classClazz, "getName", "()Ljava/lang/String;");
+ jstring classNameStr = (*env)->CallObjectMethod(env, exceptionClazz, classGetNameMethod);
+ if (classNameStr != NULL) {
+ /* get printable string */
+ const char* classNameChars = (*env)->GetStringUTFChars(env, classNameStr, NULL);
+ if (classNameChars != NULL) {
+ /* if the exception has a message string, get that */
+ jmethodID throwableGetMessageMethod = (*env)->GetMethodID(
+ env, exceptionClazz, "getMessage", "()Ljava/lang/String;");
+ jstring messageStr = (*env)->CallObjectMethod(
+ env, exception, throwableGetMessageMethod);
- /* get printable string */
- const char* nameStr = (*env)->GetStringUTFChars(env, className, NULL);
- if (nameStr == NULL) {
- snprintf(buf, bufLen, "%s", "out of memory generating summary");
- (*env)->ExceptionClear(env); // clear OOM
- return;
+ if (messageStr != NULL) {
+ const char* messageChars = (*env)->GetStringUTFChars(env, messageStr, NULL);
+ if (messageChars != NULL) {
+ snprintf(buf, bufLen, "%s: %s", classNameChars, messageChars);
+ (*env)->ReleaseStringUTFChars(env, messageStr, messageChars);
+ } else {
+ (*env)->ExceptionClear(env); // clear OOM
+ snprintf(buf, bufLen, "%s: <error getting message>", classNameChars);
+ }
+ (*env)->DeleteLocalRef(env, messageStr);
+ } else {
+ strncpy(buf, classNameChars, bufLen);
+ buf[bufLen - 1] = '\0';
+ }
+
+ (*env)->ReleaseStringUTFChars(env, classNameStr, classNameChars);
+ success = 1;
+ }
+ (*env)->DeleteLocalRef(env, classNameStr);
+ }
+ (*env)->DeleteLocalRef(env, classClazz);
+ (*env)->DeleteLocalRef(env, exceptionClazz);
+
+ if (! success) {
+ (*env)->ExceptionClear(env);
+ snprintf(buf, bufLen, "%s", "<error getting class name>");
+ }
+}
+
+/*
+ * Formats an exception as a string with its stack trace.
+ */
+static void printStackTrace(JNIEnv* env, jthrowable exception, char* buf, size_t bufLen)
+{
+ int success = 0;
+
+ jclass stringWriterClazz = (*env)->FindClass(env, "java/io/StringWriter");
+ if (stringWriterClazz != NULL) {
+ jmethodID stringWriterCtor = (*env)->GetMethodID(env, stringWriterClazz,
+ "<init>", "()V");
+ jmethodID stringWriterToStringMethod = (*env)->GetMethodID(env, stringWriterClazz,
+ "toString", "()Ljava/lang/String;");
+
+ jclass printWriterClazz = (*env)->FindClass(env, "java/io/PrintWriter");
+ if (printWriterClazz != NULL) {
+ jmethodID printWriterCtor = (*env)->GetMethodID(env, printWriterClazz,
+ "<init>", "(Ljava/io/Writer;)V");
+
+ jobject stringWriterObj = (*env)->NewObject(env, stringWriterClazz, stringWriterCtor);
+ if (stringWriterObj != NULL) {
+ jobject printWriterObj = (*env)->NewObject(env, printWriterClazz, printWriterCtor,
+ stringWriterObj);
+ if (printWriterObj != NULL) {
+ jclass exceptionClazz = (*env)->GetObjectClass(env, exception); // can't fail
+ jmethodID printStackTraceMethod = (*env)->GetMethodID(
+ env, exceptionClazz, "printStackTrace", "(Ljava/io/PrintWriter;)V");
+
+ (*env)->CallVoidMethod(
+ env, exception, printStackTraceMethod, printWriterObj);
+ if (! (*env)->ExceptionCheck(env)) {
+ jstring messageStr = (*env)->CallObjectMethod(
+ env, stringWriterObj, stringWriterToStringMethod);
+ if (messageStr != NULL) {
+ jsize messageStrLength = (*env)->GetStringLength(env, messageStr);
+ if (messageStrLength >= (jsize) bufLen) {
+ messageStrLength = bufLen - 1;
+ }
+ (*env)->GetStringUTFRegion(env, messageStr, 0, messageStrLength, buf);
+ (*env)->DeleteLocalRef(env, messageStr);
+ buf[messageStrLength] = '\0';
+ success = 1;
+ }
+ }
+ (*env)->DeleteLocalRef(env, exceptionClazz);
+ (*env)->DeleteLocalRef(env, printWriterObj);
+ }
+ (*env)->DeleteLocalRef(env, stringWriterObj);
+ }
+ (*env)->DeleteLocalRef(env, printWriterClazz);
+ }
+ (*env)->DeleteLocalRef(env, stringWriterClazz);
}
- /* if the exception has a message string, get that */
- jmethodID getThrowableMessage =
- (*env)->GetMethodID(env, clazz, "getMessage", "()Ljava/lang/String;");
- jstring message = (*env)->CallObjectMethod(env, excep, getThrowableMessage);
-
- if (message != NULL) {
- const char* messageStr = (*env)->GetStringUTFChars(env, message, NULL);
- snprintf(buf, bufLen, "%s: %s", nameStr, messageStr);
- if (messageStr != NULL)
- (*env)->ReleaseStringUTFChars(env, message, messageStr);
- else
- (*env)->ExceptionClear(env); // clear OOM
- } else {
- strncpy(buf, nameStr, bufLen);
- buf[bufLen-1] = '\0';
+ if (! success) {
+ (*env)->ExceptionClear(env);
+ getExceptionSummary(env, exception, buf, bufLen);
}
-
- (*env)->ReleaseStringUTFChars(env, className, nameStr);
}
/*
@@ -110,11 +182,14 @@
/* TODO: consider creating the new exception with this as "cause" */
char buf[256];
- jthrowable excep = (*env)->ExceptionOccurred(env);
+ jthrowable exception = (*env)->ExceptionOccurred(env);
(*env)->ExceptionClear(env);
- getExceptionSummary(env, excep, buf, sizeof(buf));
- LOGW("Discarding pending exception (%s) to throw %s\n",
- buf, className);
+
+ if (exception != NULL) {
+ getExceptionSummary(env, exception, buf, sizeof(buf));
+ LOGW("Discarding pending exception (%s) to throw %s\n", buf, className);
+ (*env)->DeleteLocalRef(env, exception);
+ }
}
exceptionClass = (*env)->FindClass(env, className);
@@ -124,12 +199,15 @@
return -1;
}
+ int result = 0;
if ((*env)->ThrowNew(env, exceptionClass, msg) != JNI_OK) {
LOGE("Failed throwing '%s' '%s'\n", className, msg);
/* an exception, most likely OOM, will now be pending */
- return -1;
+ result = -1;
}
- return 0;
+
+ (*env)->DeleteLocalRef(env, exceptionClass);
+ return result;
}
/*
@@ -158,6 +236,33 @@
return jniThrowException(env, "java/io/IOException", message);
}
+/*
+ * Log an exception.
+ * If exception is NULL, logs the current exception in the JNI environment, if any.
+ */
+void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable exception)
+{
+ int currentException = 0;
+ if (exception == NULL) {
+ exception = (*env)->ExceptionOccurred(env);
+ if (exception == NULL) {
+ return;
+ }
+
+ (*env)->ExceptionClear(env);
+ currentException = 1;
+ }
+
+ char buffer[1024];
+ printStackTrace(env, exception, buffer, sizeof(buffer));
+ __android_log_write(priority, tag, buffer);
+
+ if (currentException) {
+ (*env)->Throw(env, exception); // rethrow
+ (*env)->DeleteLocalRef(env, exception);
+ }
+}
+
const char* jniStrError(int errnum, char* buf, size_t buflen)
{
// note: glibc has a nonstandard strerror_r that returns char* rather
@@ -180,3 +285,55 @@
return ret;
}
}
+
+static struct CachedFields {
+ jclass fileDescriptorClass;
+ jmethodID fileDescriptorCtor;
+ jfieldID descriptorField;
+} gCachedFields;
+
+int registerJniHelp(JNIEnv* env) {
+ gCachedFields.fileDescriptorClass =
+ (*env)->NewGlobalRef(env, (*env)->FindClass(env, "java/io/FileDescriptor"));
+ if (gCachedFields.fileDescriptorClass == NULL) {
+ return -1;
+ }
+
+ gCachedFields.fileDescriptorCtor =
+ (*env)->GetMethodID(env, gCachedFields.fileDescriptorClass, "<init>", "()V");
+ if (gCachedFields.fileDescriptorCtor == NULL) {
+ return -1;
+ }
+
+ gCachedFields.descriptorField =
+ (*env)->GetFieldID(env, gCachedFields.fileDescriptorClass, "descriptor", "I");
+ if (gCachedFields.descriptorField == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Create a java.io.FileDescriptor given an integer fd
+ */
+jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
+ jobject fileDescriptor = (*env)->NewObject(env,
+ gCachedFields.fileDescriptorClass, gCachedFields.fileDescriptorCtor);
+ jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
+ return fileDescriptor;
+}
+
+/*
+ * Get an int file descriptor from a java.io.FileDescriptor
+ */
+int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
+ return (*env)->GetIntField(env, fileDescriptor, gCachedFields.descriptorField);
+}
+
+/*
+ * Set the descriptor of a java.io.FileDescriptor
+ */
+void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
+ (*env)->SetIntField(env, fileDescriptor, gCachedFields.descriptorField, value);
+}
diff --git a/libnativehelper/README b/libnativehelper/README
index fa757c0..5a5f5d4 100644
--- a/libnativehelper/README
+++ b/libnativehelper/README
@@ -9,4 +9,3 @@
- SHOULD be written in C rather than C++ where possible.
Some helper functions are defined in include/nativehelper/JNIHelp.h.
-
diff --git a/libnativehelper/Register.c b/libnativehelper/Register.c
index 4e98c33..87017ac 100644
--- a/libnativehelper/Register.c
+++ b/libnativehelper/Register.c
@@ -1,127 +1,33 @@
/*
- * Copyright 2006 The Android Open Source Project
+ * Copyright (C) 2006 The Android Open Source Project
*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
* JNI helper functions.
*/
-#include "jni.h"
-#include "AndroidSystemNatives.h"
-#include <stdio.h>
+#include "jni.h"
+
+extern int registerCoreLibrariesJni(JNIEnv* env);
+extern int registerJniHelp(JNIEnv* env);
/*
* Register all methods for system classes.
- *
- * Remember to add the declarations to include/nativehelper/JavaSystemNatives.h.
*/
int jniRegisterSystemMethods(JNIEnv* env)
{
- int result = -1;
-
- (*env)->PushLocalFrame(env, 128);
-
- if (register_org_apache_harmony_dalvik_NativeTestTarget(env) != 0)
- goto bail;
-
- if (register_java_io_File(env) != 0)
- goto bail;
- if (register_java_io_FileDescriptor(env) != 0)
- goto bail;
- if (register_java_io_ObjectOutputStream(env) != 0)
- goto bail;
- if (register_java_io_ObjectInputStream(env) != 0)
- goto bail;
- if (register_java_io_ObjectStreamClass(env) != 0)
- goto bail;
-
- if (register_java_lang_Float(env) != 0)
- goto bail;
- if (register_java_lang_Double(env) != 0)
- goto bail;
- if (register_java_lang_Math(env) != 0)
- goto bail;
- if (register_java_lang_ProcessManager(env) != 0)
- goto bail;
- if (register_java_lang_StrictMath(env) != 0)
- goto bail;
- if (register_java_lang_System(env) != 0)
- goto bail;
-
- if (register_org_apache_harmony_luni_platform_OSFileSystem(env) != 0)
- goto bail;
- if (register_org_apache_harmony_luni_platform_OSMemory(env) != 0)
- goto bail;
- if (register_org_apache_harmony_luni_platform_OSNetworkSystem(env) != 0)
- goto bail;
- if (register_org_apache_harmony_luni_util_fltparse(env) != 0)
- goto bail;
- if (register_org_apache_harmony_luni_util_NumberConvert(env) != 0)
- goto bail;
- if (register_org_apache_harmony_text_BidiWrapper(env) != 0)
- goto bail;
-
- if (register_org_openssl_NativeBN(env) != 0)
- goto bail;
- if (register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(env) != 0)
- goto bail;
-
- if (register_java_util_zip_Adler32(env) != 0)
- goto bail;
- if (register_java_util_zip_CRC32(env) != 0)
- goto bail;
- if (register_java_util_zip_Deflater(env) != 0)
- goto bail;
- if (register_java_util_zip_Inflater(env) != 0)
- goto bail;
-
- if (register_java_net_InetAddress(env) != 0)
- goto bail;
- if (register_java_net_NetworkInterface(env) != 0)
- goto bail;
-
- if (register_com_ibm_icu4jni_text_NativeNormalizer(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_text_NativeBreakIterator(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_text_NativeDecimalFormat(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_text_NativeCollator(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_converters_NativeConverter(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_regex_NativeRegEx(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_lang_UCharacter(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_util_Resources(env) != 0)
- goto bail;
- if (register_com_ibm_icu4jni_text_NativeRBNF(env) != 0)
- goto bail;
-
- if (register_SQLite_Database(env) != 0)
- goto bail;
- if (register_SQLite_Vm(env) != 0)
- goto bail;
- if (register_SQLite_FunctionContext(env) != 0)
- goto bail;
- if (register_SQLite_Stmt(env) != 0)
- goto bail;
- if (register_SQLite_Blob(env) != 0)
- goto bail;
-
- /*
- * Initialize the Android classes last, as they have dependencies
- * on the "corer" core classes.
- */
-
- if (register_dalvik_system_TouchDex(env) != 0)
- goto bail;
-
- if (register_org_apache_harmony_xml_ExpatParser(env) != 0)
- goto bail;
-
- result = 0;
-
-bail:
- (*env)->PopLocalFrame(env, NULL);
- return result;
+ // We initialize JNIHelp.c first so that the core libraries can safely rely on it.
+ return registerJniHelp(env) != -1 && registerCoreLibrariesJni(env) != -1;
}
diff --git a/libnativehelper/include/nativehelper/AndroidSystemNatives.h b/libnativehelper/include/nativehelper/AndroidSystemNatives.h
deleted file mode 100644
index 800c015..0000000
--- a/libnativehelper/include/nativehelper/AndroidSystemNatives.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Registration functions for native methods in system classes.
- */
-#ifndef _NATIVEHELPER_ANDROIDSYSTEMNATIVES
-#define _NATIVEHELPER_ANDROIDSYSTEMNATIVES
-
-#include "jni.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Call this to register the methods below. Ideally, this is the only
- * symbol that needs to be exported from the library.
- */
-int jniRegisterSystemJavaMethods(JNIEnv* env);
-
-
-/*
- * Registration functions for native methods in libcore.
- */
-int register_org_apache_harmony_dalvik_NativeTestTarget(JNIEnv* env);
-
-int register_dalvik_system_TouchDex(JNIEnv* env);
-
-int register_org_apache_harmony_xml_ExpatParser(JNIEnv *env);
-
-int register_java_io_File(JNIEnv* env);
-int register_java_io_FileDescriptor(JNIEnv* env);
-int register_java_io_ObjectOutputStream(JNIEnv* env);
-int register_java_io_ObjectInputStream(JNIEnv* env);
-int register_java_io_ObjectStreamClass(JNIEnv* env);
-
-int register_java_lang_Character(JNIEnv* env);
-int register_java_lang_Double(JNIEnv* env);
-int register_java_lang_Float(JNIEnv* env);
-int register_java_lang_Math(JNIEnv* env);
-int register_java_lang_ProcessManager(JNIEnv* env);
-int register_java_lang_StrictMath(JNIEnv* env);
-int register_java_lang_System(JNIEnv* env);
-
-int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv* env);
-int register_org_apache_harmony_luni_platform_OSMemory(JNIEnv* env);
-int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env);
-int register_org_apache_harmony_text_BidiWrapper(JNIEnv *env);
-
-int register_org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl(JNIEnv *env);
-int register_org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl(JNIEnv *env);
-int register_org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl(JNIEnv *env);
-int register_org_openssl_NativeBN(JNIEnv *env);
-int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv *env);
-
-int register_java_util_jar_JarFile(JNIEnv* env);
-int register_java_util_zip_Adler32(JNIEnv* env);
-int register_java_util_zip_CRC32(JNIEnv* env);
-int register_java_util_zip_Deflater(JNIEnv* env);
-int register_java_util_zip_Inflater(JNIEnv* env);
-int register_java_util_zip_ZipFile(JNIEnv* env);
-int register_java_net_InetAddress(JNIEnv* env);
-int register_java_net_NetworkInterface(JNIEnv* env);
-
-int register_org_apache_harmony_luni_util_fltparse(JNIEnv *env);
-int register_org_apache_harmony_luni_util_NumberConvert(JNIEnv *env);
-
-int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv* env);
-int register_com_ibm_icu4jni_lang_UCharacter(JNIEnv* env);
-int register_com_ibm_icu4jni_text_NativeCollator(JNIEnv* env);
-int register_com_ibm_icu4jni_text_NativeBreakIterator(JNIEnv* env);
-int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env);
-int register_com_ibm_icu4jni_regex_NativeRegEx(JNIEnv* env);
-int register_com_ibm_icu4jni_util_Resources(JNIEnv* env);
-int register_com_ibm_icu4jni_text_NativeRBNF(JNIEnv* env);
-
-int register_sun_misc_Unsafe(JNIEnv* env);
-
-int register_SQLite_Database(JNIEnv* env);
-int register_SQLite_Vm(JNIEnv* env);
-int register_SQLite_FunctionContext(JNIEnv* env);
-int register_SQLite_Stmt(JNIEnv* env);
-int register_SQLite_Blob(JNIEnv* env);
-
-int register_org_openssl_NativeBN(JNIEnv* env);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*_NATIVEHELPER_ANDROIDSYSTEMNATIVES*/
diff --git a/libnativehelper/include/nativehelper/JNIHelp.h b/libnativehelper/include/nativehelper/JNIHelp.h
index 59c2620..1c9f933 100644
--- a/libnativehelper/include/nativehelper/JNIHelp.h
+++ b/libnativehelper/include/nativehelper/JNIHelp.h
@@ -81,7 +81,7 @@
*/
jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd);
-/*
+/*
* Get an int file descriptor from a java.io.FileDescriptor
*/
int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor);
@@ -91,6 +91,12 @@
*/
void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value);
+/*
+ * Log a message and an exception.
+ * If exception is NULL, logs the current exception in the JNI environment.
+ */
+void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception);
+
#ifdef __cplusplus
}
#endif
@@ -135,10 +141,28 @@
inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor,
int value)
{
- return jniSetFileDescriptorOfFD(&env->functions, fileDescriptor, value);
+ jniSetFileDescriptorOfFD(&env->functions, fileDescriptor, value);
+}
+inline void jniLogException(JNIEnv* env, int priority, const char* tag,
+ jthrowable exception = NULL)
+{
+ jniLogException(&env->functions, priority, tag, exception);
}
#endif
+/* Logging macros.
+ *
+ * Logs an exception. If the exception is omitted or NULL, logs the current exception
+ * from the JNI environment, if any.
+ */
+#define LOG_EX(env, priority, tag, ...) \
+ IF_LOG(priority, tag) jniLogException(env, ANDROID_##priority, tag, ##__VA_ARGS__)
+#define LOGV_EX(env, ...) LOG_EX(env, LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define LOGD_EX(env, ...) LOG_EX(env, LOG_DEBUG, LOG_TAG, ##__VA_ARGS__)
+#define LOGI_EX(env, ...) LOG_EX(env, LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define LOGW_EX(env, ...) LOG_EX(env, LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define LOGE_EX(env, ...) LOG_EX(env, LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
* <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
diff --git a/libnativehelper/include/nativehelper/jni.h b/libnativehelper/include/nativehelper/jni.h
index ad954c8..22b1d88 100644
--- a/libnativehelper/include/nativehelper/jni.h
+++ b/libnativehelper/include/nativehelper/jni.h
@@ -1,11 +1,26 @@
/*
- * Copyright 2006 The Android Open Source Project
+ * Copyright (C) 2006 The Android Open Source Project
*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
* JNI specification, as defined by Sun:
* http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html
*
* Everything here is expected to be VM-neutral.
*/
+
#ifndef _JNI_H
#define _JNI_H
@@ -124,10 +139,10 @@
JNIWeakGlobalRefType = 3
} jobjectRefType;
-typedef struct {
- const char* name;
- const char* signature;
- void* fnPtr;
+typedef struct {
+ const char* name;
+ const char* signature;
+ void* fnPtr;
} JNINativeMethod;
struct _JNIEnv;
@@ -1037,7 +1052,7 @@
void* reserved0;
void* reserved1;
void* reserved2;
-
+
jint (*DestroyJavaVM)(JavaVM*);
jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);
jint (*DetachCurrentThread)(JavaVM*);
diff --git a/run-core-tests.sh b/run-core-tests.sh
deleted file mode 100755
index fc86c41..0000000
--- a/run-core-tests.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh
-#
-# Run the core library tests.
-#
-# You can build and run the unit tests as follows (assuming sh/bash;
-# csh users should modify to suit):
-#
-# $ cd <client>/device
-# $ . envsetup.sh
-# $ lunch 2
-# $ make
-# $ make CtsCoreTests
-# $ ./dalvik/run-core-tests.sh
-#
-# Note: You may also specify a specific test as an argument.
-
-datadir=/tmp/${USER}
-base=$OUT
-framework=$base/system/framework
-apps=$base/data/app
-
-export ANDROID_PRINTF_LOG=tag
-export ANDROID_LOG_TAGS='*:w' # was: jdwp:i dalvikvm:i dalvikvmi:i'
-export ANDROID_DATA=$datadir
-export ANDROID_ROOT=$base/system
-
-debug_opts=-Xcheck:jni
-
-OPTS=`getopt -o dl: --long debug,log:,help -n $0 -- "$@"`
-
-if [ $? != 0 ]; then echo "Terminating..." >&2; exit 1; fi
-
-eval set -- "$OPTS"
-
-while true; do
- case "$1" in
- -d|--debug) debug_opts="$debug_opts -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y"; shift ;;
- -l) export ANDROID_LOG_TAGS='*:'$2; shift 2 ;;
- --log) export ANDROID_LOG_TAGS="$2"; shift 2 ;;
- --help)
- echo usage: $0 [-d\|--debug] [-l\|--log] test.class.name;
- printf "\t%-15s%s\n" "-d|--debug" "wait for the debugger";
- printf "\t%-15s%s\n" "-l" "set the global logging level";
- printf "\t%-15s%s\n" "--log" "set the logging TAG";
- printf "\t%-15s%s\n" "--help" "this message";
- exit 1;
- ;;
- --) shift; break ;;
- *) echo "Internal Error!" >&2; exit 1 ;;
- esac
-done
-
-export LD_LIBRARY_PATH=$base/system/lib
-export DYLD_LIBRARY_PATH=$base/system/lib
-
-exe=$base/system/bin/dalvikvm
-bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar
-cpath=$framework/core-tests.jar
-
-# Notes:
-# (1) The IO tests create lots of files in the current directory, so we change
-# to /tmp first.
-# (2) Some of the core tests need a hell of a lot of memory, so we use a
-# large value for both heap and stack.
-
-rm -rf ${datadir}/xml_source
-mkdir -p ${datadir}/xml_source
-mkdir -p ${datadir}/dalvik-cache
-cd $ANDROID_BUILD_TOP/libcore
-cp -R xml/src/test/resources/* ${datadir}/xml_source
-
-cd $datadir
-exec $valgrind $exe \
- -Duser.language=en -Duser.region=US -Djava.io.tmpdir=$datadir \
- -Djavax.net.ssl.trustStore=$base/system/etc/security/cacerts.bks \
- -Xmx512M -Xss32K \
- -Xbootclasspath:$bpath -classpath $cpath $debug_opts \
- com.google.coretests.Main "$@"
diff --git a/tests/002-sleep/src/Main.java b/tests/002-sleep/src/Main.java
index 450be2f..c1a2d83 100644
--- a/tests/002-sleep/src/Main.java
+++ b/tests/002-sleep/src/Main.java
@@ -5,7 +5,7 @@
if (args.length != 0) {
millis = Integer.parseInt(args[0]);
}
-
+
System.out.println("Sleeping " + millis + " msec...");
long start = System.currentTimeMillis();
diff --git a/tests/003-omnibus-opcodes/build b/tests/003-omnibus-opcodes/build
index 0259995..9eb5ed3 100644
--- a/tests/003-omnibus-opcodes/build
+++ b/tests/003-omnibus-opcodes/build
@@ -24,4 +24,3 @@
dx -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
zip test.jar classes.dex
-
diff --git a/tests/003-omnibus-opcodes/src/Array.java b/tests/003-omnibus-opcodes/src/Array.java
index 6f1aa47..f385dd8 100644
--- a/tests/003-omnibus-opcodes/src/Array.java
+++ b/tests/003-omnibus-opcodes/src/Array.java
@@ -222,4 +222,3 @@
checkNegAlloc(-1);
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/Compare.java b/tests/003-omnibus-opcodes/src/Compare.java
index 27d6862..43a708a 100644
--- a/tests/003-omnibus-opcodes/src/Compare.java
+++ b/tests/003-omnibus-opcodes/src/Compare.java
@@ -169,4 +169,3 @@
testDoubleCompare(-5.0, 4.0, 4.0, (1.0/0.0) / (1.0/0.0));
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/FloatMath.java b/tests/003-omnibus-opcodes/src/FloatMath.java
index cf4869c..3c49402 100644
--- a/tests/003-omnibus-opcodes/src/FloatMath.java
+++ b/tests/003-omnibus-opcodes/src/FloatMath.java
@@ -335,4 +335,3 @@
jlmTests(3.14159f, 123456.78987654321);
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/Goto.java b/tests/003-omnibus-opcodes/src/Goto.java
index 5b467fd..d56ceae 100644
--- a/tests/003-omnibus-opcodes/src/Goto.java
+++ b/tests/003-omnibus-opcodes/src/Goto.java
@@ -2406,4 +2406,3 @@
bigGoto(true);
}
};
-
diff --git a/tests/003-omnibus-opcodes/src/InstField.java b/tests/003-omnibus-opcodes/src/InstField.java
index d1fdbfc..80b95ab 100644
--- a/tests/003-omnibus-opcodes/src/InstField.java
+++ b/tests/003-omnibus-opcodes/src/InstField.java
@@ -15,6 +15,16 @@
*/
public class InstField {
+ public boolean mBoolean1, mBoolean2;
+ public byte mByte1, mByte2;
+ public char mChar1, mChar2;
+ public short mShort1, mShort2;
+ public int mInt1, mInt2;
+ public float mFloat1, mFloat2;
+ public long mLong1, mLong2;
+ public double mDouble1, mDouble2;
+ public volatile long mVolatileLong1, mVolatileLong2;
+
public void run() {
assignFields();
checkFields();
@@ -70,6 +80,8 @@
mLong2 = -1234605616436508552L;
mDouble1 = 3.1415926535;
mDouble2 = 1.0 / 0.0; // +inf
+ mVolatileLong1 = mLong1 - 1;
+ mVolatileLong2 = mLong2 + 1;
}
public void checkFields() {
@@ -90,15 +102,7 @@
assert(mLong2 == -1234605616436508552L);
assert(mDouble1 > 3.141592653 && mDouble1 < 3.141592654);
assert(mDouble2 > mDouble1);
+ assert(mVolatileLong1 == 1234605616436508551L);
+ assert(mVolatileLong2 == -1234605616436508551L);
}
-
- public boolean mBoolean1, mBoolean2;
- public byte mByte1, mByte2;
- public char mChar1, mChar2;
- public short mShort1, mShort2;
- public int mInt1, mInt2;
- public float mFloat1, mFloat2;
- public long mLong1, mLong2;
- public double mDouble1, mDouble2;
}
-
diff --git a/tests/003-omnibus-opcodes/src/IntMath.java b/tests/003-omnibus-opcodes/src/IntMath.java
index d5ac744..89194de 100644
--- a/tests/003-omnibus-opcodes/src/IntMath.java
+++ b/tests/003-omnibus-opcodes/src/IntMath.java
@@ -490,4 +490,3 @@
jlmTests(12345, 0x1122334455667788L);
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/Main.java b/tests/003-omnibus-opcodes/src/Main.java
index 271d795..fb39d76 100644
--- a/tests/003-omnibus-opcodes/src/Main.java
+++ b/tests/003-omnibus-opcodes/src/Main.java
@@ -68,7 +68,7 @@
} catch (VerifyError ve) {
System.out.println("Caught (retry): " + ve);
}
-
+
try {
UnresTest2.run();
} catch (VerifyError ve) {
diff --git a/tests/003-omnibus-opcodes/src/MethodCall.java b/tests/003-omnibus-opcodes/src/MethodCall.java
index 2a365f2..f89194b 100644
--- a/tests/003-omnibus-opcodes/src/MethodCall.java
+++ b/tests/003-omnibus-opcodes/src/MethodCall.java
@@ -80,4 +80,3 @@
return 7;
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/Monitor.java b/tests/003-omnibus-opcodes/src/Monitor.java
index 0518ad9..66d7c65 100644
--- a/tests/003-omnibus-opcodes/src/Monitor.java
+++ b/tests/003-omnibus-opcodes/src/Monitor.java
@@ -42,4 +42,3 @@
assert(mVal == 2);
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/StaticField.java b/tests/003-omnibus-opcodes/src/StaticField.java
index 2ccec62..7ccdd7e 100644
--- a/tests/003-omnibus-opcodes/src/StaticField.java
+++ b/tests/003-omnibus-opcodes/src/StaticField.java
@@ -15,6 +15,16 @@
*/
public class StaticField {
+ public static boolean mBoolean1, mBoolean2;
+ public static byte mByte1, mByte2;
+ public static char mChar1, mChar2;
+ public static short mShort1, mShort2;
+ public static int mInt1, mInt2;
+ public static float mFloat1, mFloat2;
+ public static long mLong1, mLong2;
+ public static double mDouble1, mDouble2;
+ public static volatile long mVolatileLong1, mVolatileLong2;
+
public static void run() {
assignFields();
checkFields();
@@ -38,6 +48,8 @@
mLong2 = -1234605616436508552L;
mDouble1 = 3.1415926535;
mDouble2 = 1.0 / 0.0; // +inf
+ mVolatileLong1 = mLong1 - 1;
+ mVolatileLong2 = mLong2 + 1;
}
public static void checkFields() {
@@ -58,15 +70,7 @@
assert(mLong2 == -1234605616436508552L);
assert(mDouble1 > 3.141592653 && mDouble1 < 3.141592654);
assert(mDouble2 > mDouble1);
+ assert(mVolatileLong1 == 1234605616436508551L);
+ assert(mVolatileLong2 == -1234605616436508551L);
}
-
- public static boolean mBoolean1, mBoolean2;
- public static byte mByte1, mByte2;
- public static char mChar1, mChar2;
- public static short mShort1, mShort2;
- public static int mInt1, mInt2;
- public static float mFloat1, mFloat2;
- public static long mLong1, mLong2;
- public static double mDouble1, mDouble2;
}
-
diff --git a/tests/003-omnibus-opcodes/src/Switch.java b/tests/003-omnibus-opcodes/src/Switch.java
index de1b7e1..67c82b0 100644
--- a/tests/003-omnibus-opcodes/src/Switch.java
+++ b/tests/003-omnibus-opcodes/src/Switch.java
@@ -60,4 +60,3 @@
testSwitch();
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/Throw.java b/tests/003-omnibus-opcodes/src/Throw.java
index 2d4e130..91ee6dd 100644
--- a/tests/003-omnibus-opcodes/src/Throw.java
+++ b/tests/003-omnibus-opcodes/src/Throw.java
@@ -122,4 +122,3 @@
th.rethrow();
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/UnresClass.java b/tests/003-omnibus-opcodes/src/UnresClass.java
index 10dd79a..52b3d4f 100644
--- a/tests/003-omnibus-opcodes/src/UnresClass.java
+++ b/tests/003-omnibus-opcodes/src/UnresClass.java
@@ -7,4 +7,3 @@
public class UnresClass {
int foo;
}
-
diff --git a/tests/003-omnibus-opcodes/src/UnresStuff.java b/tests/003-omnibus-opcodes/src/UnresStuff.java
index 5c925af..1d2a556 100644
--- a/tests/003-omnibus-opcodes/src/UnresStuff.java
+++ b/tests/003-omnibus-opcodes/src/UnresStuff.java
@@ -20,4 +20,3 @@
System.out.println("unres!");
}
}
-
diff --git a/tests/003-omnibus-opcodes/src/UnresTest2.java b/tests/003-omnibus-opcodes/src/UnresTest2.java
index b458bfe..768be8f 100644
--- a/tests/003-omnibus-opcodes/src/UnresTest2.java
+++ b/tests/003-omnibus-opcodes/src/UnresTest2.java
@@ -47,4 +47,3 @@
System.out.println("UnresTest2 done");
}
}
-
diff --git a/tests/003-omnibus-opcodes/src2/UnresStuff.java b/tests/003-omnibus-opcodes/src2/UnresStuff.java
index 8b4b884..56f43af 100644
--- a/tests/003-omnibus-opcodes/src2/UnresStuff.java
+++ b/tests/003-omnibus-opcodes/src2/UnresStuff.java
@@ -7,4 +7,3 @@
public class UnresStuff {
public int x;
}
-
diff --git a/tests/004-annotations/expected.txt b/tests/004-annotations/expected.txt
index 6caef04..063b3ed 100644
--- a/tests/004-annotations/expected.txt
+++ b/tests/004-annotations/expected.txt
@@ -4,6 +4,8 @@
mapping is class [Landroid.test.anno.IntToString;
0='@android.test.anno.IntToString(from=0, to=NORMAL_FOCUS)'
1='@android.test.anno.IntToString(from=2, to=WEAK_FOCUS)'
+present(getFocusType, ExportedProperty): true
+present(getFocusType, AnnoSimpleType): false
AnnoSimpleField true, SimplyNoted false
annotations on TYPE class android.test.anno.SimplyNoted(2):
diff --git a/tests/004-annotations/src/android/test/anno/AnnoArrayField.java b/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
index d929aac..681045c 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
@@ -17,4 +17,3 @@
double[] dd() default {0.987654321};
String[] str() default {};
}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java b/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java
index e807a32..19dadec 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java
@@ -8,4 +8,3 @@
public @interface AnnoFancyConstructor {
public int numArgs() default 0;
}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyField.java b/tests/004-annotations/src/android/test/anno/AnnoFancyField.java
index 3637976..855ba56 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoFancyField.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyField.java
@@ -10,4 +10,3 @@
public @interface AnnoFancyField {
public String nombre() default "no se";
}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java b/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java
index 0958f34..3088866 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java
@@ -12,4 +12,3 @@
AnnoFancyMethodEnum enumerated() default AnnoFancyMethodEnum.FOO;
Class someClass() default SomeClass.class;
}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java b/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java
index 2bda6ee..bc2ba7c 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java
@@ -8,4 +8,3 @@
public @interface AnnoFancyParameter {
double factor();
}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyType.java b/tests/004-annotations/src/android/test/anno/AnnoFancyType.java
index 34ba009..745f838 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoFancyType.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyType.java
@@ -9,4 +9,3 @@
public int num();
public String name() default "unknown";
}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java
index c0c127b..d66b9ae 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSimpleConstructor {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java
index 6428f1a..04193d2 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSimpleField {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
index 9a5e062..a839fa2 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSimpleLocalVariable {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java
index 78e46aa..fcd9c0f 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSimpleMethod {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java b/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java
index 8d37376..4aadfe7 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSimplePackage {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java
index 305f6d5..6e26ca3 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSimpleParameter {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java
index 7c3c718..3bba3db 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java
@@ -7,4 +7,3 @@
@Inherited
@Documented
public @interface AnnoSimpleType {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java
index 8bae110..f74b291 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface AnnoSimpleType2 {}
-
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
index e6ae9ce..541d82e 100644
--- a/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
@@ -6,4 +6,3 @@
@Retention(RetentionPolicy.CLASS)
public @interface AnnoSimpleTypeInvis {}
-
diff --git a/tests/004-annotations/src/android/test/anno/ExportedProperty.java b/tests/004-annotations/src/android/test/anno/ExportedProperty.java
index 380b93d..810d28f 100644
--- a/tests/004-annotations/src/android/test/anno/ExportedProperty.java
+++ b/tests/004-annotations/src/android/test/anno/ExportedProperty.java
@@ -10,4 +10,3 @@
boolean resolveId() default false;
IntToString[] mapping() default { @IntToString(from = -1, to = "-1") };
}
-
diff --git a/tests/004-annotations/src/android/test/anno/FullyNoted.java b/tests/004-annotations/src/android/test/anno/FullyNoted.java
index d24a6d8..76a7b04 100644
--- a/tests/004-annotations/src/android/test/anno/FullyNoted.java
+++ b/tests/004-annotations/src/android/test/anno/FullyNoted.java
@@ -37,4 +37,3 @@
return 0;
}
}
-
diff --git a/tests/004-annotations/src/android/test/anno/INoted.java b/tests/004-annotations/src/android/test/anno/INoted.java
index 7a7198c..b2cd007 100644
--- a/tests/004-annotations/src/android/test/anno/INoted.java
+++ b/tests/004-annotations/src/android/test/anno/INoted.java
@@ -5,4 +5,3 @@
@AnnoSimpleMethod
public int bar();
}
-
diff --git a/tests/004-annotations/src/android/test/anno/IntToString.java b/tests/004-annotations/src/android/test/anno/IntToString.java
index 5363c83..e84fcfa 100644
--- a/tests/004-annotations/src/android/test/anno/IntToString.java
+++ b/tests/004-annotations/src/android/test/anno/IntToString.java
@@ -10,4 +10,3 @@
int from();
String to();
}
-
diff --git a/tests/004-annotations/src/android/test/anno/SimplyNoted.java b/tests/004-annotations/src/android/test/anno/SimplyNoted.java
index 7dce77e..95a3d24 100644
--- a/tests/004-annotations/src/android/test/anno/SimplyNoted.java
+++ b/tests/004-annotations/src/android/test/anno/SimplyNoted.java
@@ -28,4 +28,3 @@
return bar;
}
}
-
diff --git a/tests/004-annotations/src/android/test/anno/SomeClass.java b/tests/004-annotations/src/android/test/anno/SomeClass.java
index 5bb05c9..c21d68d 100644
--- a/tests/004-annotations/src/android/test/anno/SomeClass.java
+++ b/tests/004-annotations/src/android/test/anno/SomeClass.java
@@ -2,4 +2,3 @@
public class SomeClass {
}
-
diff --git a/tests/004-annotations/src/android/test/anno/SubNoted.java b/tests/004-annotations/src/android/test/anno/SubNoted.java
index 089e5e6..2530346 100644
--- a/tests/004-annotations/src/android/test/anno/SubNoted.java
+++ b/tests/004-annotations/src/android/test/anno/SubNoted.java
@@ -10,4 +10,3 @@
return 0;
}
}
-
diff --git a/tests/004-annotations/src/android/test/anno/TestAnnotations.java b/tests/004-annotations/src/android/test/anno/TestAnnotations.java
index d7b0b14..4ad32d5 100644
--- a/tests/004-annotations/src/android/test/anno/TestAnnotations.java
+++ b/tests/004-annotations/src/android/test/anno/TestAnnotations.java
@@ -14,7 +14,7 @@
static private void printAnnotationArray(String prefix, Annotation[] arr) {
TreeMap<String, Annotation> sorted =
new TreeMap<String, Annotation>();
-
+
for (Annotation a : arr) {
sorted.put(a.annotationType().getName(), a);
}
@@ -24,7 +24,7 @@
System.out.println(prefix + " " + a.annotationType());
}
}
-
+
static void printAnnotations(Class clazz) {
Annotation[] annos;
Annotation[][] parAnnos;
@@ -120,7 +120,7 @@
Method meth;
ExportedProperty property;
final IntToString[] mapping;
-
+
try {
meth = TestAnnotations.class.getMethod("getFocusType",
(Class[])null);
@@ -132,6 +132,13 @@
System.out.println("mapping is " + mapping.getClass() +
"\n 0='" + mapping[0] + "'\n 1='" + mapping[1] + "'");
+
+ /* while we're here, check isAnnotationPresent on Method */
+ System.out.println("present(getFocusType, ExportedProperty): " +
+ meth.isAnnotationPresent(ExportedProperty.class));
+ System.out.println("present(getFocusType, AnnoSimpleType): " +
+ meth.isAnnotationPresent(AnnoSimpleType.class));
+
System.out.println("");
}
@@ -168,4 +175,3 @@
System.out.println("SubNoted.get(AnnoSimpleType) = " + anno);
}
}
-
diff --git a/tests/004-annotations/src/android/test/anno/package-info.java b/tests/004-annotations/src/android/test/anno/package-info.java
index f434024..74b11f9 100644
--- a/tests/004-annotations/src/android/test/anno/package-info.java
+++ b/tests/004-annotations/src/android/test/anno/package-info.java
@@ -1,3 +1,2 @@
@AnnoSimplePackage
package android.test.anno;
-
diff --git a/tests/008-instanceof/src/Iface1.java b/tests/008-instanceof/src/Iface1.java
index 12dcfe7..ba17d45 100644
--- a/tests/008-instanceof/src/Iface1.java
+++ b/tests/008-instanceof/src/Iface1.java
@@ -11,4 +11,3 @@
public String mWahoo = new String("wahoo");
}
-
diff --git a/tests/008-instanceof/src/Iface2.java b/tests/008-instanceof/src/Iface2.java
index 6f8c262..83fe650 100644
--- a/tests/008-instanceof/src/Iface2.java
+++ b/tests/008-instanceof/src/Iface2.java
@@ -7,4 +7,3 @@
public int iFunc2(int ii);
}
-
diff --git a/tests/008-instanceof/src/Iface2Sub1.java b/tests/008-instanceof/src/Iface2Sub1.java
index 83c8791..db3e905 100644
--- a/tests/008-instanceof/src/Iface2Sub1.java
+++ b/tests/008-instanceof/src/Iface2Sub1.java
@@ -7,4 +7,3 @@
//public int iFunc2(int ii);
}
-
diff --git a/tests/008-instanceof/src/ImplA.java b/tests/008-instanceof/src/ImplA.java
index 9949d01..9007001 100644
--- a/tests/008-instanceof/src/ImplA.java
+++ b/tests/008-instanceof/src/ImplA.java
@@ -12,4 +12,3 @@
return ii+2;
}
}
-
diff --git a/tests/008-instanceof/src/ImplB.java b/tests/008-instanceof/src/ImplB.java
index b3a0c89..619fa00 100644
--- a/tests/008-instanceof/src/ImplB.java
+++ b/tests/008-instanceof/src/ImplB.java
@@ -14,4 +14,3 @@
public static String mWhoami = new String("ImplB!");
}
-
diff --git a/tests/009-instanceof2/src/Iface1.java b/tests/009-instanceof2/src/Iface1.java
index 12dcfe7..ba17d45 100644
--- a/tests/009-instanceof2/src/Iface1.java
+++ b/tests/009-instanceof2/src/Iface1.java
@@ -11,4 +11,3 @@
public String mWahoo = new String("wahoo");
}
-
diff --git a/tests/009-instanceof2/src/Iface2.java b/tests/009-instanceof2/src/Iface2.java
index 6f8c262..83fe650 100644
--- a/tests/009-instanceof2/src/Iface2.java
+++ b/tests/009-instanceof2/src/Iface2.java
@@ -7,4 +7,3 @@
public int iFunc2(int ii);
}
-
diff --git a/tests/009-instanceof2/src/Iface2Sub1.java b/tests/009-instanceof2/src/Iface2Sub1.java
index 83c8791..db3e905 100644
--- a/tests/009-instanceof2/src/Iface2Sub1.java
+++ b/tests/009-instanceof2/src/Iface2Sub1.java
@@ -7,4 +7,3 @@
//public int iFunc2(int ii);
}
-
diff --git a/tests/009-instanceof2/src/ImplA.java b/tests/009-instanceof2/src/ImplA.java
index 9949d01..9007001 100644
--- a/tests/009-instanceof2/src/ImplA.java
+++ b/tests/009-instanceof2/src/ImplA.java
@@ -12,4 +12,3 @@
return ii+2;
}
}
-
diff --git a/tests/009-instanceof2/src/ImplB.java b/tests/009-instanceof2/src/ImplB.java
index b3a0c89..619fa00 100644
--- a/tests/009-instanceof2/src/ImplB.java
+++ b/tests/009-instanceof2/src/ImplB.java
@@ -14,4 +14,3 @@
public static String mWhoami = new String("ImplB!");
}
-
diff --git a/tests/010-instance/src/Y.java b/tests/010-instance/src/Y.java
index 6585ee7..2b2c371 100644
--- a/tests/010-instance/src/Y.java
+++ b/tests/010-instance/src/Y.java
@@ -6,4 +6,3 @@
return 1;
}
}
-
diff --git a/tests/011-array-copy/src/Iface1.java b/tests/011-array-copy/src/Iface1.java
index 12dcfe7..ba17d45 100644
--- a/tests/011-array-copy/src/Iface1.java
+++ b/tests/011-array-copy/src/Iface1.java
@@ -11,4 +11,3 @@
public String mWahoo = new String("wahoo");
}
-
diff --git a/tests/011-array-copy/src/Iface2.java b/tests/011-array-copy/src/Iface2.java
index 6f8c262..83fe650 100644
--- a/tests/011-array-copy/src/Iface2.java
+++ b/tests/011-array-copy/src/Iface2.java
@@ -7,4 +7,3 @@
public int iFunc2(int ii);
}
-
diff --git a/tests/011-array-copy/src/ImplA.java b/tests/011-array-copy/src/ImplA.java
index 9949d01..9007001 100644
--- a/tests/011-array-copy/src/ImplA.java
+++ b/tests/011-array-copy/src/ImplA.java
@@ -12,4 +12,3 @@
return ii+2;
}
}
-
diff --git a/tests/015-switch/src/Main.java b/tests/015-switch/src/Main.java
index 678a564..7198e2b 100644
--- a/tests/015-switch/src/Main.java
+++ b/tests/015-switch/src/Main.java
@@ -103,4 +103,3 @@
}
}
}
-
diff --git a/tests/021-string2/src/junit/framework/Assert.java b/tests/021-string2/src/junit/framework/Assert.java
index c1bc7b2..364e646 100644
--- a/tests/021-string2/src/junit/framework/Assert.java
+++ b/tests/021-string2/src/junit/framework/Assert.java
@@ -71,7 +71,7 @@
assertEquals(null, expected, actual);
}
/**
- * Asserts that two Strings are equal.
+ * Asserts that two Strings are equal.
*/
static public void assertEquals(String message, String expected, String actual) {
if (expected == null && actual == null)
@@ -81,7 +81,7 @@
throw new ComparisonFailure(message, expected, actual);
}
/**
- * Asserts that two Strings are equal.
+ * Asserts that two Strings are equal.
*/
static public void assertEquals(String expected, String actual) {
assertEquals(null, expected, actual);
diff --git a/tests/021-string2/src/junit/framework/ComparisonFailure.java b/tests/021-string2/src/junit/framework/ComparisonFailure.java
index a0ad176..0cb2cee 100644
--- a/tests/021-string2/src/junit/framework/ComparisonFailure.java
+++ b/tests/021-string2/src/junit/framework/ComparisonFailure.java
@@ -2,7 +2,7 @@
/**
* Thrown when an assert equals for Strings failed.
- *
+ *
* Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
*/
public class ComparisonFailure extends AssertionFailedError {
@@ -20,19 +20,19 @@
fExpected= expected;
fActual= actual;
}
-
+
/**
* Returns "..." in place of common prefix and "..." in
* place of common suffix between expected and actual.
- *
+ *
* @see java.lang.Throwable#getMessage()
*/
public String getMessage() {
if (fExpected == null || fActual == null)
return Assert.format(super.getMessage(), fExpected, fActual);
-
+
int end= Math.min(fExpected.length(), fActual.length());
-
+
int i= 0;
for(; i < end; i++) {
if (fExpected.charAt(i) != fActual.charAt(i))
@@ -45,7 +45,7 @@
break;
}
String actual, expected;
-
+
// equal strings
if (j < i && k < i) {
expected= fExpected;
@@ -57,12 +57,12 @@
expected= "..."+expected;
actual= "..."+actual;
}
-
+
if (j < fExpected.length()-1)
expected= expected+"...";
if (k < fActual.length()-1)
actual= actual+"...";
- }
+ }
return Assert.format(super.getMessage(), expected, actual);
}
}
diff --git a/tests/022-interface/src/Iface1.java b/tests/022-interface/src/Iface1.java
index 12dcfe7..ba17d45 100644
--- a/tests/022-interface/src/Iface1.java
+++ b/tests/022-interface/src/Iface1.java
@@ -11,4 +11,3 @@
public String mWahoo = new String("wahoo");
}
-
diff --git a/tests/022-interface/src/Iface2.java b/tests/022-interface/src/Iface2.java
index 6f8c262..83fe650 100644
--- a/tests/022-interface/src/Iface2.java
+++ b/tests/022-interface/src/Iface2.java
@@ -7,4 +7,3 @@
public int iFunc2(int ii);
}
-
diff --git a/tests/022-interface/src/Iface2Sub1.java b/tests/022-interface/src/Iface2Sub1.java
index 83c8791..db3e905 100644
--- a/tests/022-interface/src/Iface2Sub1.java
+++ b/tests/022-interface/src/Iface2Sub1.java
@@ -7,4 +7,3 @@
//public int iFunc2(int ii);
}
-
diff --git a/tests/022-interface/src/ImplA.java b/tests/022-interface/src/ImplA.java
index 9949d01..9007001 100644
--- a/tests/022-interface/src/ImplA.java
+++ b/tests/022-interface/src/ImplA.java
@@ -12,4 +12,3 @@
return ii+2;
}
}
-
diff --git a/tests/022-interface/src/ImplB.java b/tests/022-interface/src/ImplB.java
index b3a0c89..619fa00 100644
--- a/tests/022-interface/src/ImplB.java
+++ b/tests/022-interface/src/ImplB.java
@@ -14,4 +14,3 @@
public static String mWhoami = new String("ImplB!");
}
-
diff --git a/tests/023-many-interfaces/iface-gen.c b/tests/023-many-interfaces/iface-gen.c
index 313de69..1e3284a 100644
--- a/tests/023-many-interfaces/iface-gen.c
+++ b/tests/023-many-interfaces/iface-gen.c
@@ -52,4 +52,3 @@
return (result != 0);
}
-
diff --git a/tests/023-many-interfaces/src/ManyInterfaces.java b/tests/023-many-interfaces/src/ManyInterfaces.java
index 3c67f1f..375938a 100644
--- a/tests/023-many-interfaces/src/ManyInterfaces.java
+++ b/tests/023-many-interfaces/src/ManyInterfaces.java
@@ -152,7 +152,7 @@
{
/** whether to report timing information */
private static boolean timing = false;
-
+
/**
* Report on a section.
*/
@@ -168,7 +168,7 @@
/**
* Run tests.
- *
+ *
* @param timing whether to print out timing info
*/
public static void run(boolean timing) {
@@ -233,7 +233,7 @@
end = System.nanoTime();
report("testInst099", start, end, iter, rept);
}
-
+
public int func001() { return 1; }
public int func003() { return 3; }
public int func005() { return 5; }
@@ -411,4 +411,3 @@
}
}
}
-
diff --git a/tests/024-illegal-access/src/SemiPrivate.java b/tests/024-illegal-access/src/SemiPrivate.java
index cc7f2d8..17b2ac0 100644
--- a/tests/024-illegal-access/src/SemiPrivate.java
+++ b/tests/024-illegal-access/src/SemiPrivate.java
@@ -6,4 +6,3 @@
public class SemiPrivate {
/* not private */ static String mPrivvy = "stuff";
}
-
diff --git a/tests/024-illegal-access/src/otherpkg/Package.java b/tests/024-illegal-access/src/otherpkg/Package.java
index a82b321..bc295b5 100644
--- a/tests/024-illegal-access/src/otherpkg/Package.java
+++ b/tests/024-illegal-access/src/otherpkg/Package.java
@@ -21,4 +21,3 @@
*/
public class Package {
}
-
diff --git a/tests/024-illegal-access/src2/SemiPrivate.java b/tests/024-illegal-access/src2/SemiPrivate.java
index 6bdf610..cf6f8e6 100644
--- a/tests/024-illegal-access/src2/SemiPrivate.java
+++ b/tests/024-illegal-access/src2/SemiPrivate.java
@@ -6,4 +6,3 @@
public class SemiPrivate {
private static String mPrivvy = "stuff";
}
-
diff --git a/tests/024-illegal-access/src2/otherpkg/Package.java b/tests/024-illegal-access/src2/otherpkg/Package.java
index 7f740d4..54d8341 100644
--- a/tests/024-illegal-access/src2/otherpkg/Package.java
+++ b/tests/024-illegal-access/src2/otherpkg/Package.java
@@ -21,4 +21,3 @@
*/
class Package {
}
-
diff --git a/tests/025-access-controller/src/Privvy.java b/tests/025-access-controller/src/Privvy.java
index d8027a1..07a0678 100644
--- a/tests/025-access-controller/src/Privvy.java
+++ b/tests/025-access-controller/src/Privvy.java
@@ -16,4 +16,3 @@
return mValue;
}
}
-
diff --git a/tests/027-arithmetic/src/Main.java b/tests/027-arithmetic/src/Main.java
index 6299eed..4d0f74e 100644
--- a/tests/027-arithmetic/src/Main.java
+++ b/tests/027-arithmetic/src/Main.java
@@ -139,4 +139,3 @@
unsignedShiftTest();
}
}
-
diff --git a/tests/028-array-write/src/Main.java b/tests/028-array-write/src/Main.java
index c9181f1..6f36f84 100644
--- a/tests/028-array-write/src/Main.java
+++ b/tests/028-array-write/src/Main.java
@@ -6,7 +6,7 @@
public class Main {
/** whether to report times */
static boolean timing = false;
-
+
static final int STORAGE_SIZE = 128*1024;
static int[] mStorage = new int[STORAGE_SIZE];
@@ -60,10 +60,9 @@
if ((args.length >= 1) && args[0].equals("--timing")) {
timing = true;
}
-
+
writeTest();
copyTest();
System.out.println("Done!");
}
}
-
diff --git a/tests/029-assert/src/Main.java b/tests/029-assert/src/Main.java
index efa10f7..1e5cc7c 100644
--- a/tests/029-assert/src/Main.java
+++ b/tests/029-assert/src/Main.java
@@ -14,4 +14,3 @@
}
}
}
-
diff --git a/tests/030-bad-finalizer/run b/tests/030-bad-finalizer/run
index 6e02946..8e03cd3 100644
--- a/tests/030-bad-finalizer/run
+++ b/tests/030-bad-finalizer/run
@@ -17,11 +17,11 @@
${RUN} "$@" > original-output.txt
cat original-output.txt | awk '
-/Segmentation fault/ {
+/Segmentation fault/ {
# ignore the details of the line
print "(segfault)"
next;
}
-{
+{
print;
}'
diff --git a/tests/030-bad-finalizer/src/BadFinalizer.java b/tests/030-bad-finalizer/src/BadFinalizer.java
index 25aee3f..3ff422b 100644
--- a/tests/030-bad-finalizer/src/BadFinalizer.java
+++ b/tests/030-bad-finalizer/src/BadFinalizer.java
@@ -30,4 +30,3 @@
}
}
}
-
diff --git a/tests/030-bad-finalizer/src/Main.java b/tests/030-bad-finalizer/src/Main.java
index 542020e..c063476 100644
--- a/tests/030-bad-finalizer/src/Main.java
+++ b/tests/030-bad-finalizer/src/Main.java
@@ -18,9 +18,8 @@
System.out.println("Requesting another GC.");
System.gc();
}
-
+
System.out.println("Done waiting.");
System.exit(0);
}
}
-
diff --git a/tests/031-class-attributes/src/ClassAttrs.java b/tests/031-class-attributes/src/ClassAttrs.java
index 35bd550..c1407bd 100644
--- a/tests/031-class-attributes/src/ClassAttrs.java
+++ b/tests/031-class-attributes/src/ClassAttrs.java
@@ -53,7 +53,7 @@
meth = MemberClass.class.getMethod("foo", (Class[]) null);
System.out.println("method signature: "
+ getSignatureAttribute(meth));
-
+
Field field;
field = MemberClass.class.getField("mWha");
System.out.println("field signature: "
diff --git a/tests/032-concrete-sub/src/AbstractBase.java b/tests/032-concrete-sub/src/AbstractBase.java
index 875303e..6281189 100644
--- a/tests/032-concrete-sub/src/AbstractBase.java
+++ b/tests/032-concrete-sub/src/AbstractBase.java
@@ -24,4 +24,3 @@
public void abstractOrNot() {}
}
-
diff --git a/tests/032-concrete-sub/src/ConcreteSub.java b/tests/032-concrete-sub/src/ConcreteSub.java
index fbaeb1b..083f25d 100644
--- a/tests/032-concrete-sub/src/ConcreteSub.java
+++ b/tests/032-concrete-sub/src/ConcreteSub.java
@@ -24,7 +24,7 @@
System.out.println("calling abs.doStuff()");
abs.doStuff();
}
-
+
public static void main() {
ConcreteSub sub = new ConcreteSub();
@@ -51,4 +51,3 @@
System.out.println("meth modifiers=" + meth.getModifiers());
}
}
-
diff --git a/tests/032-concrete-sub/src/ConcreteSub2.java b/tests/032-concrete-sub/src/ConcreteSub2.java
index 0b8fbf5..0a9e67e 100644
--- a/tests/032-concrete-sub/src/ConcreteSub2.java
+++ b/tests/032-concrete-sub/src/ConcreteSub2.java
@@ -24,4 +24,3 @@
abstractOrNot();
}
}
-
diff --git a/tests/032-concrete-sub/src/Main.java b/tests/032-concrete-sub/src/Main.java
index a3aa2b8..4a5193d 100644
--- a/tests/032-concrete-sub/src/Main.java
+++ b/tests/032-concrete-sub/src/Main.java
@@ -34,4 +34,3 @@
}
}
}
-
diff --git a/tests/032-concrete-sub/src2/AbstractBase.java b/tests/032-concrete-sub/src2/AbstractBase.java
index 78ec4b1..534f738 100644
--- a/tests/032-concrete-sub/src2/AbstractBase.java
+++ b/tests/032-concrete-sub/src2/AbstractBase.java
@@ -27,4 +27,3 @@
public abstract void abstractOrNot();
}
-
diff --git a/tests/033-class-init-deadlock/src/Main.java b/tests/033-class-init-deadlock/src/Main.java
index df13c26..27c4922 100644
--- a/tests/033-class-init-deadlock/src/Main.java
+++ b/tests/033-class-init-deadlock/src/Main.java
@@ -11,15 +11,15 @@
static public void main(String[] args) {
Thread thread1, thread2;
-
+
System.out.println("Deadlock test starting.");
thread1 = new Thread() { public void run() { new A(); } };
thread2 = new Thread() { public void run() { new B(); } };
thread1.start();
thread2.start();
-
+
try { Thread.sleep(6000); } catch (InterruptedException ie) { }
-
+
System.out.println("Deadlock test interupting threads.");
thread1.interrupt();
thread2.interrupt();
@@ -49,4 +49,3 @@
Main.bInitialized = true;
}
}
-
diff --git a/tests/034-call-null/src/Main.java b/tests/034-call-null/src/Main.java
index 6b5c28c..a0a129e 100644
--- a/tests/034-call-null/src/Main.java
+++ b/tests/034-call-null/src/Main.java
@@ -12,4 +12,3 @@
instance.doStuff();
}
}
-
diff --git a/tests/035-enum/src/Main.java b/tests/035-enum/src/Main.java
index c0915d4..09fcc98 100644
--- a/tests/035-enum/src/Main.java
+++ b/tests/035-enum/src/Main.java
@@ -21,4 +21,3 @@
System.out.println(" enum? " + field.isEnumConstant());
}
}
-
diff --git a/tests/036-finalizer/src/FinalizerTest.java b/tests/036-finalizer/src/FinalizerTest.java
index 7bf289e..420ec34 100644
--- a/tests/036-finalizer/src/FinalizerTest.java
+++ b/tests/036-finalizer/src/FinalizerTest.java
@@ -21,4 +21,3 @@
mReborn = this;
}
}
-
diff --git a/tests/036-finalizer/src/Main.java b/tests/036-finalizer/src/Main.java
index a8623f8..c29cc11 100644
--- a/tests/036-finalizer/src/Main.java
+++ b/tests/036-finalizer/src/Main.java
@@ -40,7 +40,7 @@
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
-
+
return wimp[0];
}
@@ -80,7 +80,7 @@
/* this will try to collect and finalize ft */
System.out.println("gc");
System.gc();
-
+
System.out.println("wimp: " + wimpString(wimp));
System.out.println("finalize");
System.runFinalization();
@@ -105,4 +105,3 @@
System.out.println("wimp: " + wimpString(wimp));
}
}
-
diff --git a/tests/037-inherit/src/Main.java b/tests/037-inherit/src/Main.java
index e0b36c7..55b782e 100644
--- a/tests/037-inherit/src/Main.java
+++ b/tests/037-inherit/src/Main.java
@@ -35,4 +35,3 @@
return this.MAGIC_INT;
}
}
-
diff --git a/tests/039-join-main/src/Main.java b/tests/039-join-main/src/Main.java
index 8d66b58..0644f1c 100644
--- a/tests/039-join-main/src/Main.java
+++ b/tests/039-join-main/src/Main.java
@@ -6,7 +6,7 @@
public class Main {
public static void main(String[] args) {
Thread t;
-
+
t = new Thread(new JoinMainSub(Thread.currentThread()), "Joiner");
System.out.print("Starting thread '" + t.getName() + "'\n");
t.start();
@@ -39,4 +39,3 @@
}
}
}
-
diff --git a/tests/040-miranda/src/MirandaAbstract.java b/tests/040-miranda/src/MirandaAbstract.java
index 1ce97c3..b603ce6 100644
--- a/tests/040-miranda/src/MirandaAbstract.java
+++ b/tests/040-miranda/src/MirandaAbstract.java
@@ -14,4 +14,3 @@
return true;
}
}
-
diff --git a/tests/040-miranda/src/MirandaClass.java b/tests/040-miranda/src/MirandaClass.java
index 835752d..3bf6704 100644
--- a/tests/040-miranda/src/MirandaClass.java
+++ b/tests/040-miranda/src/MirandaClass.java
@@ -22,4 +22,3 @@
return false;
}
}
-
diff --git a/tests/040-miranda/src/MirandaClass2.java b/tests/040-miranda/src/MirandaClass2.java
index 4c07bd9..e9bdf2b 100644
--- a/tests/040-miranda/src/MirandaClass2.java
+++ b/tests/040-miranda/src/MirandaClass2.java
@@ -7,4 +7,3 @@
return 28;
}
}
-
diff --git a/tests/040-miranda/src/MirandaInterface.java b/tests/040-miranda/src/MirandaInterface.java
index a7c89fd..2c0a59a 100644
--- a/tests/040-miranda/src/MirandaInterface.java
+++ b/tests/040-miranda/src/MirandaInterface.java
@@ -8,4 +8,3 @@
public boolean inInterface();
}
-
diff --git a/tests/040-miranda/src/MirandaInterface2.java b/tests/040-miranda/src/MirandaInterface2.java
index f0187c6..83b6af8 100644
--- a/tests/040-miranda/src/MirandaInterface2.java
+++ b/tests/040-miranda/src/MirandaInterface2.java
@@ -10,4 +10,3 @@
public int inInterface2();
}
-
diff --git a/tests/042-new-instance/src/Main.java b/tests/042-new-instance/src/Main.java
index 037aa2a..8faef13 100644
--- a/tests/042-new-instance/src/Main.java
+++ b/tests/042-new-instance/src/Main.java
@@ -154,4 +154,3 @@
}
}
}
-
diff --git a/tests/042-new-instance/src/MaybeAbstract.java b/tests/042-new-instance/src/MaybeAbstract.java
index 43c002b..6d3b05b 100644
--- a/tests/042-new-instance/src/MaybeAbstract.java
+++ b/tests/042-new-instance/src/MaybeAbstract.java
@@ -18,4 +18,3 @@
public MaybeAbstract() {}
int foo() { return 0; }
}
-
diff --git a/tests/042-new-instance/src2/MaybeAbstract.java b/tests/042-new-instance/src2/MaybeAbstract.java
index bfbfd45..8b70a07 100644
--- a/tests/042-new-instance/src2/MaybeAbstract.java
+++ b/tests/042-new-instance/src2/MaybeAbstract.java
@@ -18,4 +18,3 @@
public MaybeAbstract() {}
int foo() { return 0; }
}
-
diff --git a/tests/043-privates/src/Main.java b/tests/043-privates/src/Main.java
index 9c4d357..73b4d79 100644
--- a/tests/043-privates/src/Main.java
+++ b/tests/043-privates/src/Main.java
@@ -43,4 +43,3 @@
return "PrivatePackageSub!";
}
}
-
diff --git a/tests/044-proxy/src/BasicTest.java b/tests/044-proxy/src/BasicTest.java
index 1633812..2a453c4 100644
--- a/tests/044-proxy/src/BasicTest.java
+++ b/tests/044-proxy/src/BasicTest.java
@@ -261,4 +261,3 @@
return result;
}
}
-
diff --git a/tests/044-proxy/src/Clash.java b/tests/044-proxy/src/Clash.java
index 31a9d2f..adeffdc 100644
--- a/tests/044-proxy/src/Clash.java
+++ b/tests/044-proxy/src/Clash.java
@@ -68,4 +68,3 @@
return null;
}
}
-
diff --git a/tests/044-proxy/src/Clash2.java b/tests/044-proxy/src/Clash2.java
index 44ffe47..2a384f4 100644
--- a/tests/044-proxy/src/Clash2.java
+++ b/tests/044-proxy/src/Clash2.java
@@ -58,4 +58,3 @@
return null;
}
}
-
diff --git a/tests/044-proxy/src/Clash3.java b/tests/044-proxy/src/Clash3.java
index ce323da..6d6f2f2 100644
--- a/tests/044-proxy/src/Clash3.java
+++ b/tests/044-proxy/src/Clash3.java
@@ -73,4 +73,3 @@
return null;
}
}
-
diff --git a/tests/044-proxy/src/Clash4.java b/tests/044-proxy/src/Clash4.java
index f200573..1bfb37f 100644
--- a/tests/044-proxy/src/Clash4.java
+++ b/tests/044-proxy/src/Clash4.java
@@ -75,4 +75,3 @@
return null;
}
}
-
diff --git a/tests/044-proxy/src/Main.java b/tests/044-proxy/src/Main.java
index 64ba9b8..01926af 100644
--- a/tests/044-proxy/src/Main.java
+++ b/tests/044-proxy/src/Main.java
@@ -27,4 +27,3 @@
WrappedThrow.main(null);
}
}
-
diff --git a/tests/044-proxy/src/WrappedThrow.java b/tests/044-proxy/src/WrappedThrow.java
index ea4af24..27ae84e 100644
--- a/tests/044-proxy/src/WrappedThrow.java
+++ b/tests/044-proxy/src/WrappedThrow.java
@@ -242,4 +242,3 @@
return result;
}
}
-
diff --git a/tests/045-reflect-array/src/Main.java b/tests/045-reflect-array/src/Main.java
index 1be05dd..c70e291 100644
--- a/tests/045-reflect-array/src/Main.java
+++ b/tests/045-reflect-array/src/Main.java
@@ -145,4 +145,3 @@
System.out.println("ReflectArrayTest.testMulti passed");
}
}
-
diff --git a/tests/046-reflect/src/Main.java b/tests/046-reflect/src/Main.java
index 99b1c4e..399a417 100644
--- a/tests/046-reflect/src/Main.java
+++ b/tests/046-reflect/src/Main.java
@@ -433,4 +433,3 @@
}
public void createNoisyInit(NoisyInit ni) {}
}
-
diff --git a/tests/047-returns/src/Main.java b/tests/047-returns/src/Main.java
index dc8ed76..d53c4a7 100644
--- a/tests/047-returns/src/Main.java
+++ b/tests/047-returns/src/Main.java
@@ -63,4 +63,3 @@
interface CommonInterface {
int doStuff();
}
-
diff --git a/tests/048-server-socket/src/Main.java b/tests/048-server-socket/src/Main.java
index b21210a..55dbf9a 100644
--- a/tests/048-server-socket/src/Main.java
+++ b/tests/048-server-socket/src/Main.java
@@ -50,4 +50,3 @@
System.out.println("done");
}
}
-
diff --git a/tests/049-show-object/src/Main.java b/tests/049-show-object/src/Main.java
index 60a4cef..d31eeda 100644
--- a/tests/049-show-object/src/Main.java
+++ b/tests/049-show-object/src/Main.java
@@ -32,4 +32,3 @@
showObject(array);
}
}
-
diff --git a/tests/050-sync-test/src/Main.java b/tests/050-sync-test/src/Main.java
index 620e899..c2ea192 100644
--- a/tests/050-sync-test/src/Main.java
+++ b/tests/050-sync-test/src/Main.java
@@ -42,7 +42,7 @@
try {
Thread.sleep(100);
- }
+ }
catch (InterruptedException ie) {
System.out.println("INTERRUPT!");
ie.printStackTrace();
@@ -153,7 +153,7 @@
}
catch (InterruptedException ie) {
// Expecting this; interrupted should be false.
- System.out.println(Thread.currentThread().getName() +
+ System.out.println(Thread.currentThread().getName() +
" interrupted, flag=" + Thread.interrupted());
intr = true;
}
@@ -177,4 +177,3 @@
}
}
}
-
diff --git a/tests/050-sync-test/src/ThreadDeathHandler.java b/tests/050-sync-test/src/ThreadDeathHandler.java
index 3f42f4d..5ea61a5 100644
--- a/tests/050-sync-test/src/ThreadDeathHandler.java
+++ b/tests/050-sync-test/src/ThreadDeathHandler.java
@@ -17,4 +17,3 @@
e.printStackTrace();
}
}
-
diff --git a/tests/051-thread/src/Main.java b/tests/051-thread/src/Main.java
index ff1b181..9acc89e 100644
--- a/tests/051-thread/src/Main.java
+++ b/tests/051-thread/src/Main.java
@@ -32,7 +32,7 @@
} catch (InterruptedException ex) {
ex.printStackTrace();
}
-
+
System.out.print("Thread starter returning\n");
}
@@ -71,4 +71,3 @@
}
}
}
-
diff --git a/tests/052-verifier-fun/src/Main.java b/tests/052-verifier-fun/src/Main.java
index 81ff654..ca960cf 100644
--- a/tests/052-verifier-fun/src/Main.java
+++ b/tests/052-verifier-fun/src/Main.java
@@ -107,4 +107,3 @@
feature.doStuff();
}
}
-
diff --git a/tests/053-wait-some/src/Main.java b/tests/053-wait-some/src/Main.java
index 468f9f0..51e6c52 100644
--- a/tests/053-wait-some/src/Main.java
+++ b/tests/053-wait-some/src/Main.java
@@ -13,7 +13,7 @@
boolean timing = (args.length >= 1) && args[0].equals("--timing");
doit(timing);
}
-
+
public static void doit(boolean timing) {
Object sleepy = new Object();
long start, end;
@@ -47,10 +47,10 @@
if (epsilon > 50) {
epsilon = 50;
}
-
+
long min = delay - epsilon;
long max = delay + epsilon;
-
+
if (elapsed < min) {
System.out.println(" Elapsed time was too short");
showTime = true;
@@ -60,7 +60,7 @@
showTime = true;
}
}
-
+
if (showTime) {
System.out.println(" Wall clock elapsed "
+ elapsed + "ms");
@@ -69,4 +69,3 @@
}
}
}
-
diff --git a/tests/054-uncaught/src/Main.java b/tests/054-uncaught/src/Main.java
index 68e9b42..4ee6b05 100644
--- a/tests/054-uncaught/src/Main.java
+++ b/tests/054-uncaught/src/Main.java
@@ -8,7 +8,7 @@
testThread(1);
testThread(2);
testThread(3);
-
+
catchTheUncaught(1);
}
@@ -22,7 +22,7 @@
ex.printStackTrace();
}
}
-
+
static void catchTheUncaught(int which) {
ThreadDeathHandler defHandler = new ThreadDeathHandler("DEFAULT");
ThreadDeathHandler threadHandler = new ThreadDeathHandler("THREAD");
@@ -55,7 +55,7 @@
public Helper(int which) {
this.which = which;
}
-
+
public void run() {
catchTheUncaught(which);
}
diff --git a/tests/054-uncaught/src/ThreadDeathHandler.java b/tests/054-uncaught/src/ThreadDeathHandler.java
index 3f42f4d..5ea61a5 100644
--- a/tests/054-uncaught/src/ThreadDeathHandler.java
+++ b/tests/054-uncaught/src/ThreadDeathHandler.java
@@ -17,4 +17,3 @@
e.printStackTrace();
}
}
-
diff --git a/tests/055-enum-performance/src/Main.java b/tests/055-enum-performance/src/Main.java
index a576d3a..64d03eb 100644
--- a/tests/055-enum-performance/src/Main.java
+++ b/tests/055-enum-performance/src/Main.java
@@ -3,7 +3,7 @@
public class Main {
/** used by {@link #basisCall} */
static private int basisTestValue = 12;
-
+
static public void main(String[] args) throws Exception {
boolean timing = (args.length >= 1) && args[0].equals("--timing");
run(timing);
@@ -11,7 +11,7 @@
static public void run(boolean timing) {
preTest();
-
+
long time0 = System.nanoTime();
int count1 = test1(500);
long time1 = System.nanoTime();
@@ -105,7 +105,7 @@
static public int basisCall(int i, String name) {
int compare = name.compareTo("fuzzbot");
-
+
if (i < (basisTestValue * compare)) {
return basisTestValue;
} else {
diff --git a/tests/057-iteration-performance/src/Main.java b/tests/057-iteration-performance/src/Main.java
index defbd75..d562802 100644
--- a/tests/057-iteration-performance/src/Main.java
+++ b/tests/057-iteration-performance/src/Main.java
@@ -19,7 +19,7 @@
/**
* The matrix of tests includes the A-E axis for loop body contents and
* the 0-5 axis for iterator style.
- *
+ *
* <ul>
* <li>A: empty body</li>
* <li>B: array element access and update</li>
@@ -30,7 +30,7 @@
* <li>G: one small object allocation (empty constructor)</li>
* <li>H: copy 8k of bytes from one array to another</li>
* </ul>
- *
+ *
* <ul>
* <li>0: for() loop backward to 0</li>
* <li>1: for() loop forward to local variable</li>
@@ -44,7 +44,7 @@
public class Main {
static public final int BODIES = 8;
static public final int LOOPS = 7;
-
+
static public void main(String[] args) throws Exception {
boolean timing = (args.length >= 1) && args[0].equals("--timing");
@@ -70,14 +70,14 @@
if (timing) {
System.out.println("iters = " + iters);
}
-
+
run(timing, iters);
}
static private enum Normalization {
NONE, PER_COLUMN, TOP_LEFT;
}
-
+
static public void printTimings(double[][] timings, Normalization norm) {
System.out.println();
System.out.printf("%-7s A B C D E" +
@@ -124,7 +124,7 @@
} else {
combineTimings(timings, newTimings, i);
}
-
+
if (checkTimes(timings, timing)) {
break;
}
@@ -137,7 +137,7 @@
if (! goodTimes) {
timing = true;
}
-
+
if (timing) {
printTimings(timings, Normalization.NONE);
printTimings(timings, Normalization.TOP_LEFT);
@@ -151,13 +151,13 @@
int oldWeight) {
for (int i = 0; i < target.length; i++) {
for (int j = 0; j < target[i].length; j++) {
- target[i][j] =
+ target[i][j] =
((target[i][j] * oldWeight) + newTimes[i][j])
/ (oldWeight + 1);
}
}
}
-
+
static public boolean checkTimes(double[][] timings, boolean print) {
// expected increase over A1
double[][] expected = {
@@ -167,11 +167,11 @@
{ 1.6, 2.8, 2.9, 3.6, 6.8, 12.6, 63.5, 97.0 },
{ 1.7, 3.0, 2.9, 3.7, 6.9, 12.8, 64.0, 98.0 },
{ 6.0, 6.0, 6.0, 7.0, 10.0, 15.0, 64.5, 105.0 },
- { 31.0, 31.2, 31.5, 34.0, 41.0, 43.0, 91.0, 135.0 },
+ { 31.0, 31.2, 31.5, 34.0, 41.0, 43.0, 91.0, 135.0 },
};
boolean good = true;
-
+
for (int x = 0; x < BODIES; x++) {
for (int y = 0; y < LOOPS; y++) {
double ratio = timings[x][y] / timings[0][0];
@@ -187,7 +187,7 @@
return good;
}
-
+
static public double[][] runAllTests(int iters, boolean print) {
// diters is used to get usec, not nanosec; hence the extra 1000.
double diters = (double) iters * INNER_COUNT * 1000;
@@ -200,7 +200,7 @@
if (print) {
System.out.println("Running A...");
}
-
+
t0 = System.nanoTime();
testA0(iters);
t1 = System.nanoTime();
@@ -226,11 +226,11 @@
timings[0][6] = (t7 - t6) / diters;
// Column B
-
+
if (print) {
System.out.println("Running B...");
}
-
+
t0 = System.nanoTime();
testB0(iters);
t1 = System.nanoTime();
@@ -256,11 +256,11 @@
timings[1][6] = (t7 - t6) / diters;
// Column C
-
+
if (print) {
System.out.println("Running C...");
}
-
+
t0 = System.nanoTime();
testC0(iters);
t1 = System.nanoTime();
@@ -284,9 +284,9 @@
timings[2][4] = (t5 - t4) / diters;
timings[2][5] = (t6 - t5) / diters;
timings[2][6] = (t7 - t6) / diters;
-
+
// Column D
-
+
if (print) {
System.out.println("Running D...");
}
@@ -314,9 +314,9 @@
timings[3][4] = (t5 - t4) / diters;
timings[3][5] = (t6 - t5) / diters;
timings[3][6] = (t7 - t6) / diters;
-
+
// Column E
-
+
if (print) {
System.out.println("Running E...");
}
@@ -344,9 +344,9 @@
timings[4][4] = (t5 - t4) / diters;
timings[4][5] = (t6 - t5) / diters;
timings[4][6] = (t7 - t6) / diters;
-
+
// Column F
-
+
if (print) {
System.out.println("Running F...");
}
@@ -379,9 +379,9 @@
iters /= 5;
diters /= 5;
-
+
// Column G
-
+
if (print) {
System.out.println("Running G...");
}
@@ -409,9 +409,9 @@
timings[6][4] = (t5 - t4) / diters;
timings[6][5] = (t6 - t5) / diters;
timings[6][6] = (t7 - t6) / diters;
-
+
// Column H
-
+
if (print) {
System.out.println("Running H...");
}
@@ -472,9 +472,9 @@
return size;
}
}
-
+
// The tests themselves
-
+
static public void testA0(int iters) {
for (int outer = iters; outer > 0; outer--) {
for (int i = INNER_COUNT; i > 0; i--) {
@@ -495,7 +495,7 @@
static public void testA2(int iters) {
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
// empty
@@ -505,7 +505,7 @@
static public void testA3(int iters) {
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
// empty
@@ -515,7 +515,7 @@
static public void testA4(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
// empty
@@ -525,7 +525,7 @@
static public void testA5(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
// empty
@@ -535,7 +535,7 @@
static public void testA6(int iters) {
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
// empty
@@ -545,7 +545,7 @@
static public void testB0(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = INNER_COUNT; i > 0; i--) {
target.value++;
@@ -567,7 +567,7 @@
static public void testB2(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
target.value++;
@@ -578,7 +578,7 @@
static public void testB3(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
target.value++;
@@ -588,7 +588,7 @@
static public void testB4(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
target.value++;
@@ -598,7 +598,7 @@
static public void testB5(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
target.value++;
@@ -609,7 +609,7 @@
static public void testB6(int iters) {
Target target = TARGET;
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
target.value++;
@@ -640,7 +640,7 @@
static public void testC2(int iters) {
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
array[i]++;
@@ -650,7 +650,7 @@
static public void testC3(int iters) {
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
array[0] = i + 1;
@@ -661,7 +661,7 @@
static public void testC4(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
array[i]++;
@@ -672,7 +672,7 @@
static public void testC5(int iters) {
int[] array = INNER_ARRAY;
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
array[i]++;
@@ -683,7 +683,7 @@
static public void testC6(int iters) {
int[] array = INNER_ARRAY;
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
array[0]++;
@@ -715,7 +715,7 @@
static public void testD2(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
target.simple();
@@ -726,7 +726,7 @@
static public void testD3(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
target.simple();
@@ -736,7 +736,7 @@
static public void testD4(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
target.simple();
@@ -746,7 +746,7 @@
static public void testD5(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
target.simple();
@@ -757,13 +757,13 @@
static public void testD6(int iters) {
Target target = TARGET;
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
target.simple();
}
}
- }
+ }
static public void testE0(int iters) {
Target target = TARGET;
@@ -793,7 +793,7 @@
static public void testE2(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
synchronized (target) {
@@ -806,7 +806,7 @@
static public void testE3(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
synchronized (target) {
@@ -818,7 +818,7 @@
static public void testE4(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
synchronized (target) {
@@ -830,7 +830,7 @@
static public void testE5(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
synchronized (target) {
@@ -843,7 +843,7 @@
static public void testE6(int iters) {
Target target = TARGET;
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
synchronized (target) {
@@ -851,7 +851,7 @@
}
}
}
- }
+ }
static public void testF0(int iters) {
Target target = TARGET;
@@ -885,7 +885,7 @@
static public void testF2(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
target.simple();
@@ -900,7 +900,7 @@
static public void testF3(int iters) {
Target target = TARGET;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
target.simple();
@@ -914,7 +914,7 @@
static public void testF4(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
target.simple();
@@ -928,7 +928,7 @@
static public void testF5(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
target.simple();
@@ -943,7 +943,7 @@
static public void testF6(int iters) {
Target target = TARGET;
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
target.simple();
@@ -975,7 +975,7 @@
static public void testG2(int iters) {
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
new Target();
@@ -985,7 +985,7 @@
static public void testG3(int iters) {
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
new Target();
@@ -995,7 +995,7 @@
static public void testG4(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
new Target();
@@ -1005,7 +1005,7 @@
static public void testG5(int iters) {
Target target = TARGET;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
new Target();
@@ -1015,7 +1015,7 @@
static public void testG6(int iters) {
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
new Target();
@@ -1026,7 +1026,7 @@
static public void testH0(int iters) {
byte[] b1 = BYTES_1;
byte[] b2 = BYTES_2;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = INNER_COUNT; i > 0; i--) {
System.arraycopy(b1, 0, b2, 0, ARRAY_BYTES);
@@ -1050,7 +1050,7 @@
byte[] b1 = BYTES_1;
byte[] b2 = BYTES_2;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < array.length; i++) {
System.arraycopy(b1, 0, b2, 0, ARRAY_BYTES);
@@ -1062,7 +1062,7 @@
byte[] b1 = BYTES_1;
byte[] b2 = BYTES_2;
int[] array = INNER_ARRAY;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i : array) {
System.arraycopy(b1, 0, b2, 0, ARRAY_BYTES);
@@ -1074,7 +1074,7 @@
Target target = TARGET;
byte[] b1 = BYTES_1;
byte[] b2 = BYTES_2;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size; i++) {
System.arraycopy(b1, 0, b2, 0, ARRAY_BYTES);
@@ -1086,7 +1086,7 @@
Target target = TARGET;
byte[] b1 = BYTES_1;
byte[] b2 = BYTES_2;
-
+
for (int outer = iters; outer > 0; outer--) {
for (int i = 0; i < target.size(); i++) {
System.arraycopy(b1, 0, b2, 0, ARRAY_BYTES);
@@ -1098,7 +1098,7 @@
byte[] b1 = BYTES_1;
byte[] b2 = BYTES_2;
ArrayList<Object> list = INNER_LIST;
-
+
for (int outer = iters; outer > 0; outer--) {
for (Object o : list) {
System.arraycopy(b1, 0, b2, 0, ARRAY_BYTES);
diff --git a/tests/058-enum-order/src/Main.java b/tests/058-enum-order/src/Main.java
index 74048c6..2cd6052 100644
--- a/tests/058-enum-order/src/Main.java
+++ b/tests/058-enum-order/src/Main.java
@@ -21,7 +21,7 @@
public static enum Muffin {
CORN, BLUEBERRY, CRANBERRY, BRAN, BLACKBERRY;
}
-
+
public static void main(String args[]) {
Muffin[] array = Muffin.class.getEnumConstants();
for (Muffin m : array) {
diff --git a/tests/059-finalizer-throw/src/Main.java b/tests/059-finalizer-throw/src/Main.java
index 0937361..42260e4 100644
--- a/tests/059-finalizer-throw/src/Main.java
+++ b/tests/059-finalizer-throw/src/Main.java
@@ -1,5 +1,7 @@
// Copyright 2008 The Android Open Source Project
+import java.util.Timer;
+import java.util.TimerTask;
/*
* Throw an exception from a finalizer and make sure it's harmless. Under
@@ -19,6 +21,13 @@
System.gc();
System.runFinalization();
+ new Timer(true).schedule(new TimerTask() {
+ public void run() {
+ System.out.println("Timed out, exiting");
+ System.exit(1);
+ }
+ }, 30000);
+
while (!didFinal) {
try {
Thread.sleep(500);
@@ -45,4 +54,3 @@
throw new InterruptedException("whee");
}
}
-
diff --git a/tests/060-reflection-security/expected.txt b/tests/060-reflection-security/expected.txt
deleted file mode 100644
index 69d6da8..0000000
--- a/tests/060-reflection-security/expected.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-Setting SecurityManager.
-checkPermission: (java.security.SecurityPermission getProperty.package.access)
-checkPackageAccess: java.lang
-Running tests.
-
-getFields A
-checkMemberAccess: other.Blort, PUBLIC
-getFields B
-checkMemberAccess: other.Blort, PUBLIC
-java.lang.SecurityException: Denied!
-
-getDeclaredFields A
-checkMemberAccess: other.Blort, DECLARED
-checkPermission: (java.lang.RuntimePermission accessDeclaredMembers)
-getDeclaredFields B
-checkMemberAccess: other.Blort, DECLARED
-java.lang.SecurityException: Denied!
-
-getMethods A
-checkMemberAccess: other.Blort, PUBLIC
-getMethods B
-checkMemberAccess: other.Blort, PUBLIC
-java.lang.SecurityException: Denied!
-
-getDeclaredMethods A
-checkMemberAccess: other.Blort, DECLARED
-checkPermission: (java.lang.RuntimePermission accessDeclaredMembers)
-getDeclaredMethods B
-checkMemberAccess: other.Blort, DECLARED
-java.lang.SecurityException: Denied!
-
-getConstructors A
-checkMemberAccess: other.Blort, PUBLIC
-getConstructors B
-checkMemberAccess: other.Blort, PUBLIC
-java.lang.SecurityException: Denied!
-
-getDeclaredConstructors A
-checkMemberAccess: other.Blort, DECLARED
-checkPermission: (java.lang.RuntimePermission accessDeclaredMembers)
-getDeclaredConstructors B
-checkMemberAccess: other.Blort, DECLARED
-java.lang.SecurityException: Denied!
-
-getClasses A
-checkMemberAccess: other.Blort, PUBLIC
-getClasses B
-checkMemberAccess: other.Blort, PUBLIC
-java.lang.SecurityException: Denied!
-
-getDeclaredClasses A
-checkMemberAccess: other.Blort, DECLARED
-checkPermission: (java.lang.RuntimePermission accessDeclaredMembers)
-getDeclaredClasses B
-checkMemberAccess: other.Blort, DECLARED
-java.lang.SecurityException: Denied!
-
-Done!
diff --git a/tests/060-reflection-security/info.txt b/tests/060-reflection-security/info.txt
deleted file mode 100644
index ed0adf5..0000000
--- a/tests/060-reflection-security/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is a basic test of how a SecurityManager can impact reflection calls.
diff --git a/tests/060-reflection-security/src/Enforcer.java b/tests/060-reflection-security/src/Enforcer.java
deleted file mode 100644
index ad68817..0000000
--- a/tests/060-reflection-security/src/Enforcer.java
+++ /dev/null
@@ -1,66 +0,0 @@
-import java.lang.reflect.Member;
-import java.security.Permission;
-
-public class Enforcer extends SecurityManager {
- public static final Enforcer THE_ONE = new Enforcer();
-
- /** whether to deny the next request */
- private boolean deny;
-
- /**
- * Not publicly constructable. Use {@link #THE_ONE}.
- */
- private Enforcer() {
- deny = false;
- }
-
- /**
- * Deny the next request.
- */
- public void denyNext() {
- deny = true;
- }
-
- /**
- * Throw an exception if the instance had been asked to deny a request.
- */
- private void denyIfAppropriate() {
- if (deny) {
- deny = false;
- throw new SecurityException("Denied!");
- }
- }
-
- public void checkPackageAccess(String pkg) {
- System.out.println("checkPackageAccess: " + pkg);
- denyIfAppropriate();
- super.checkPackageAccess(pkg);
- }
-
- public void checkMemberAccess(Class c, int which) {
- String member;
-
- switch (which) {
- case Member.DECLARED: member = "DECLARED"; break;
- case Member.PUBLIC: member = "PUBLIC"; break;
- default: member = "<" + which + ">?"; break;
- }
-
- System.out.println("checkMemberAccess: " + c.getName() + ", " +
- member);
- denyIfAppropriate();
- super.checkMemberAccess(c, which);
- }
-
- public void checkPermission(Permission perm) {
- System.out.println("checkPermission: " + perm);
- denyIfAppropriate();
- super.checkPermission(perm);
- }
-
- public void checkPermission(Permission perm, Object context) {
- System.out.println("checkPermission: " + perm + ", " + context);
- denyIfAppropriate();
- super.checkPermission(perm, context);
- }
-}
diff --git a/tests/060-reflection-security/src/Main.java b/tests/060-reflection-security/src/Main.java
deleted file mode 100644
index 9db0251..0000000
--- a/tests/060-reflection-security/src/Main.java
+++ /dev/null
@@ -1,158 +0,0 @@
-import other.Blort;
-
-public class Main {
- static public boolean VERBOSE = false;
-
- static public void main(String[] args) {
- if (args.length > 0) {
- if (args[0].equals("--verbose")) {
- VERBOSE = true;
- }
- }
-
- System.out.println("Setting SecurityManager.");
- System.setSecurityManager(Enforcer.THE_ONE);
- System.out.println("Running tests.");
- accessStuff();
- System.out.println("\nDone!");
- }
-
- static public void report(Throwable t) {
- if (VERBOSE) {
- t.printStackTrace(System.out);
- } else {
- System.out.println(t);
- }
- }
-
- static public void accessStuff() {
- Class c = other.Blort.class;
-
- /*
- * Note: We don't use reflection to factor out these tests,
- * becuase reflection also calls into the SecurityManager, and
- * we don't want to conflate the calls nor assume too much
- * in general about what calls reflection will cause.
- */
-
- System.out.println("\ngetFields A");
- try {
- c.getFields();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getFields B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getFields();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetDeclaredFields A");
- try {
- c.getDeclaredFields();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getDeclaredFields B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getDeclaredFields();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetMethods A");
- try {
- c.getMethods();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getMethods B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getMethods();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetDeclaredMethods A");
- try {
- c.getDeclaredMethods();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getDeclaredMethods B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getDeclaredMethods();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetConstructors A");
- try {
- c.getConstructors();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getConstructors B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getConstructors();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetDeclaredConstructors A");
- try {
- c.getDeclaredConstructors();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getDeclaredConstructors B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getDeclaredConstructors();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetClasses A");
- try {
- c.getClasses();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getClasses B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getClasses();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("\ngetDeclaredClasses A");
- try {
- c.getDeclaredClasses();
- } catch (Exception ex) {
- report(ex);
- }
-
- System.out.println("getDeclaredClasses B");
- Enforcer.THE_ONE.denyNext();
- try {
- c.getDeclaredClasses();
- } catch (Exception ex) {
- report(ex);
- }
- }
-}
diff --git a/tests/060-reflection-security/src/other/Blort.java b/tests/060-reflection-security/src/other/Blort.java
deleted file mode 100644
index 033ae69..0000000
--- a/tests/060-reflection-security/src/other/Blort.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package other;
-
-public class Blort {
- private int privateField;
- /*package*/ int packageField;
- protected int protectedField;
- public int publicField;
-
- private void privateMethod() {
- // This space intentionally left blank.
- }
-
- /*package*/ void packageMethod() {
- // This space intentionally left blank.
- }
-
- protected void protectedMethod() {
- // This space intentionally left blank.
- }
-
- public void publicMethod() {
- // This space intentionally left blank.
- }
-}
diff --git a/tests/062-character-encodings/expected.txt b/tests/062-character-encodings/expected.txt
index aa0279a..b395a2a 100644
--- a/tests/062-character-encodings/expected.txt
+++ b/tests/062-character-encodings/expected.txt
@@ -1,417 +1 @@
-Big5
- csBig5
- windows-950
- windows-950-2000
- x-big5
-BOCU-1
- csBOCU-1
- ibm-1214
- ibm-1215
-CESU-8
- ibm-9400
-cp864
- IBM864
- csIBM864
- ibm-864
- ibm-864_X110-1999
-EUC-JP
- Extended_UNIX_Code_Packed_Format_for_Japanese
- X-EUC-JP
- csEUCPkdFmtJapanese
- eucjis
- ibm-954
- ibm-954_P101-2007
- ujis
-EUC-KR
- 5601
- KSC_5601
- KS_C_5601-1987
- KS_C_5601-1989
- csEUCKR
- csKSC56011987
- iso-ir-149
- korean
- ms949
- windows-949
- windows-949-2000
-GBK
- CP936
- EUC-CN
- GB2312
- GB_2312-80
- MS936
- chinese
- csGB2312
- csISO58GB231280
- gb2312-1980
- iso-ir-58
- windows-936
- windows-936-2000
-HZ-GB-2312
- HZ
-ISO-2022-JP
- csISO2022JP
-ISO-8859-1
- 819
- 8859_1
- IBM819
- ISO_8859-1:1987
- cp819
- csISOLatin1
- ibm-819
- iso-ir-100
- l1
- latin1
-ISO-8859-10
- ISO_8859-10:1992
- csISOLatin6
- iso-8859_10-1998
- iso-ir-157
- l6
- latin6
-ISO-8859-13
- 8859_13
- 921
- cp921
- ibm-921
- ibm-921_P100-1995
- windows-28603
-ISO-8859-14
- ISO_8859-14:1998
- iso-8859_14-1998
- iso-celtic
- iso-ir-199
- l8
- latin8
-ISO-8859-15
- 8859_15
- 923
- Latin-9
- cp923
- csisolatin0
- csisolatin9
- ibm-923
- ibm-923_P100-1998
- iso8859_15_fdis
- l9
- latin0
- windows-28605
-ISO-8859-16
- ISO_8859-16:2001
- iso-8859_16-2001
- iso-ir-226
- l10
- latin10
-ISO-8859-2
- 8859_2
- 912
- ISO_8859-2:1987
- cp912
- csISOLatin2
- ibm-912
- ibm-912_P100-1995
- iso-ir-101
- l2
- latin2
- windows-28592
-ISO-8859-3
- 8859_3
- 913
- ISO_8859-3:1988
- cp913
- csISOLatin3
- ibm-913
- ibm-913_P100-2000
- iso-ir-109
- l3
- latin3
- windows-28593
-ISO-8859-4
- 8859_4
- 914
- ISO_8859-4:1988
- cp914
- csISOLatin4
- ibm-914
- ibm-914_P100-1995
- iso-ir-110
- l4
- latin4
- windows-28594
-ISO-8859-5
- 8859_5
- 915
- ISO_8859-5:1988
- cp915
- csISOLatinCyrillic
- cyrillic
- ibm-915
- ibm-915_P100-1995
- iso-ir-144
- windows-28595
-ISO-8859-6
- 1089
- 8859_6
- ASMO-708
- ECMA-114
- ISO-8859-6-E
- ISO-8859-6-I
- ISO_8859-6:1987
- arabic
- cp1089
- csISOLatinArabic
- ibm-1089
- ibm-1089_P100-1995
- iso-ir-127
- windows-28596
-ISO-8859-7
- ECMA-118
- ELOT_928
- ISO_8859-7:1987
- csISOLatinGreek
- greek
- greek8
- ibm-9005
- ibm-9005_X110-2007
- iso-ir-126
- sun_eu_greek
- windows-28597
-ISO-8859-8
- 8859_8
- ISO-8859-8-E
- ISO-8859-8-I
- ISO_8859-8:1988
- csISOLatinHebrew
- hebrew
- ibm-5012
- ibm-5012_P100-1999
- iso-ir-138
- windows-28598
-ISO-8859-9
- 8859_9
- 920
- ECMA-128
- ISO_8859-9:1989
- cp920
- csISOLatin5
- ibm-920
- ibm-920_P100-1995
- iso-ir-148
- l5
- latin5
- windows-28599
-KOI8-R
- cp878
- csKOI8R
- ibm-878
- ibm-878_P100-1996
- koi8
- windows-20866
-macintosh
- csMacintosh
- mac
- macos-0_2-10.2
- windows-10000
-SCSU
- ibm-1212
- ibm-1213
-Shift_JIS
- IBM-943C
- MS_Kanji
- cp932
- cp943c
- csShiftJIS
- csWindows31J
- ibm-943
- ibm-943_P15A-2003
- ibm-943_VSUB_VPUA
- ms932
- pck
- sjis
- windows-31j
- windows-932
- x-ms-cp932
- x-sjis
-TIS-620
- MS874
- cp874
- eucTH
- ibm-874
- ibm-9066
- tis620.2533
- windows-874
- windows-874-2000
-US-ASCII
- 646
- ANSI_X3.4-1968
- ANSI_X3.4-1986
- ASCII
- IBM367
- ISO646-US
- ISO_646.irv:1991
- ascii7
- cp367
- csASCII
- ibm-367
- iso-ir-6
- iso_646.irv:1983
- us
- windows-20127
-UTF-16
- ISO-10646-UCS-2
- csUnicode
- ibm-1204
- ibm-1205
- ucs-2
- unicode
-UTF-16BE
- UTF16_BigEndian
- cp1200
- cp1201
- ibm-1200
- ibm-1201
- ibm-13488
- ibm-13489
- ibm-17584
- ibm-17585
- ibm-21680
- ibm-21681
- ibm-25776
- ibm-25777
- ibm-61955
- ibm-61956
- windows-1201
- x-utf-16be
-UTF-16LE
- UTF16_LittleEndian
- ibm-1202
- ibm-1203
- ibm-13490
- ibm-13491
- ibm-17586
- ibm-17587
- ibm-21682
- ibm-21683
- ibm-25778
- ibm-25779
- windows-1200
- x-utf-16le
-UTF-32
- ISO-10646-UCS-4
- csUCS4
- ibm-1236
- ibm-1237
- ucs-4
-UTF-32BE
- UTF32_BigEndian
- ibm-1232
- ibm-1233
-UTF-32LE
- UTF32_LittleEndian
- ibm-1234
- ibm-1235
-UTF-7
- windows-65000
-UTF-8
- cp1208
- ibm-1208
- ibm-1209
- ibm-13496
- ibm-13497
- ibm-17592
- ibm-17593
- ibm-5304
- ibm-5305
- windows-65001
-windows-1250
- cp1250
- ibm-5346
- ibm-5346_P100-1998
-windows-1251
- ANSI1251
- cp1251
- ibm-5347
- ibm-5347_P100-1998
-windows-1252
- cp1252
- ibm-5348
- ibm-5348_P100-1997
-windows-1253
- cp1253
- ibm-5349
- ibm-5349_P100-1998
-windows-1254
- cp1254
- ibm-5350
- ibm-5350_P100-1998
-windows-1255
- cp1255
- ibm-9447
- ibm-9447_P100-2002
-windows-1256
- cp1256
- ibm-9448
- ibm-9448_X100-2005
-windows-1257
- cp1257
- ibm-9449
- ibm-9449_P100-2002
-windows-1258
- cp1258
- ibm-5354
- ibm-5354_P100-1998
-x-gsm-03.38-2000
- GSM0338
- gsm-03.38-2000
-x-ibm-1383_P110-1999
- 1383
- cp1383
- hp15CN
- ibm-1383
- ibm-1383_P110-1999
- ibm-1383_VPUA
- ibm-eucCN
-x-IMAP-mailbox-name
- IMAP-mailbox-name
-x-iscii-be
- iscii-bng
- windows-57003
- windows-57006
- x-iscii-as
-x-iscii-de
- ibm-4902
- iscii-dev
- windows-57002
-x-iscii-gu
- iscii-guj
- windows-57010
-x-iscii-ka
- iscii-knd
- windows-57008
-x-iscii-ma
- iscii-mlm
- windows-57009
-x-iscii-or
- iscii-ori
- windows-57007
-x-iscii-pa
- iscii-gur
- windows-57011
-x-iscii-ta
- iscii-tml
- windows-57004
-x-iscii-te
- iscii-tlg
- windows-57005
-x-iso-8859_11-2001
- ISO-8859-11
- iso-8859_11-2001
- thai8
-x-UTF16_OppositeEndian
- UTF16_OppositeEndian
-x-UTF16_PlatformEndian
- UTF16_PlatformEndian
-x-UTF32_OppositeEndian
- UTF32_OppositeEndian
-x-UTF32_PlatformEndian
- UTF32_PlatformEndian
+Missing: []
diff --git a/tests/062-character-encodings/src/Main.java b/tests/062-character-encodings/src/Main.java
index a9b3dac..6e9f0cd 100644
--- a/tests/062-character-encodings/src/Main.java
+++ b/tests/062-character-encodings/src/Main.java
@@ -1,30 +1,25 @@
import java.nio.charset.Charset;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.Set;
public class Main {
static public void main(String[] args) throws Exception {
- SortedMap<String, Charset> all = Charset.availableCharsets();
+ // These charsets must be provided; anything else is optional.
+ List<String> standardCharsets = Arrays.asList("US-ASCII", "ISO-8859-1",
+ "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16");
+ SortedMap<String, Charset> all = Charset.availableCharsets();
+ Set<String> needed = new HashSet<String>(standardCharsets);
for (Map.Entry<String, Charset> e : all.entrySet()) {
String canonicalName = e.getKey();
- System.out.println(canonicalName);
- Set<String> aliases = e.getValue().aliases();
- if ((aliases != null) && (aliases.size() != 0)) {
- ArrayList<String> list = new ArrayList<String>(aliases.size());
- list.addAll(aliases);
- Collections.sort(list);
- for (String s : list) {
- if (! s.equals(canonicalName)) {
- System.out.println(" " + s);
- }
- }
- } else {
- System.out.println(" (no aliases)");
- }
+ needed.remove(canonicalName);
}
+ System.out.println("Missing: " + needed);
}
}
diff --git a/tests/064-field-access/src/GetNonexistent.java b/tests/064-field-access/src/GetNonexistent.java
index b979eb2..faad686 100644
--- a/tests/064-field-access/src/GetNonexistent.java
+++ b/tests/064-field-access/src/GetNonexistent.java
@@ -19,4 +19,3 @@
Object obj = Holder.mObject;
}
}
-
diff --git a/tests/064-field-access/src/Holder.java b/tests/064-field-access/src/Holder.java
index 5ae9f71..5e34024 100644
--- a/tests/064-field-access/src/Holder.java
+++ b/tests/064-field-access/src/Holder.java
@@ -17,4 +17,3 @@
public class Holder {
public static Object mObject = new Object();
}
-
diff --git a/tests/064-field-access/src/Main.java b/tests/064-field-access/src/Main.java
index 300c6b2..c068d23 100644
--- a/tests/064-field-access/src/Main.java
+++ b/tests/064-field-access/src/Main.java
@@ -343,4 +343,3 @@
}
}
-
diff --git a/tests/064-field-access/src/other/OtherPackage.java b/tests/064-field-access/src/other/OtherPackage.java
index 49f0d78..a595db5 100644
--- a/tests/064-field-access/src/other/OtherPackage.java
+++ b/tests/064-field-access/src/other/OtherPackage.java
@@ -13,4 +13,3 @@
double pkgDoubleField = 3.141592654;
}
-
diff --git a/tests/064-field-access/src2/Holder.java b/tests/064-field-access/src2/Holder.java
index dcb63eb..28224d7 100644
--- a/tests/064-field-access/src2/Holder.java
+++ b/tests/064-field-access/src2/Holder.java
@@ -17,4 +17,3 @@
public class Holder {
//public static Object mObject = new Object();
}
-
diff --git a/tests/065-mismatched-implements/src/Base.java b/tests/065-mismatched-implements/src/Base.java
index 7e35408..8623ad7 100644
--- a/tests/065-mismatched-implements/src/Base.java
+++ b/tests/065-mismatched-implements/src/Base.java
@@ -5,4 +5,3 @@
System.out.println("whee");
}
};
-
diff --git a/tests/065-mismatched-implements/src/Defs.java b/tests/065-mismatched-implements/src/Defs.java
index 456b6bf..bab92d8 100644
--- a/tests/065-mismatched-implements/src/Defs.java
+++ b/tests/065-mismatched-implements/src/Defs.java
@@ -5,4 +5,3 @@
// func2 not defined
}
-
diff --git a/tests/065-mismatched-implements/src/Indirect.java b/tests/065-mismatched-implements/src/Indirect.java
index dd87a65..023e409 100644
--- a/tests/065-mismatched-implements/src/Indirect.java
+++ b/tests/065-mismatched-implements/src/Indirect.java
@@ -25,4 +25,3 @@
Base base = new Base();
}
}
-
diff --git a/tests/065-mismatched-implements/src/Main.java b/tests/065-mismatched-implements/src/Main.java
index 6993b17..5975b99 100644
--- a/tests/065-mismatched-implements/src/Main.java
+++ b/tests/065-mismatched-implements/src/Main.java
@@ -27,4 +27,3 @@
}
}
}
-
diff --git a/tests/065-mismatched-implements/src2/Defs.java b/tests/065-mismatched-implements/src2/Defs.java
index a630c90..e7eb8a1 100644
--- a/tests/065-mismatched-implements/src2/Defs.java
+++ b/tests/065-mismatched-implements/src2/Defs.java
@@ -9,4 +9,3 @@
System.out.println("yo yo");
}
}
-
diff --git a/tests/066-mismatched-super/src/Base.java b/tests/066-mismatched-super/src/Base.java
index 815f974..6180c8b 100644
--- a/tests/066-mismatched-super/src/Base.java
+++ b/tests/066-mismatched-super/src/Base.java
@@ -3,4 +3,3 @@
public class Base extends Defs {
// no need to implement func(), provided by abstract class
};
-
diff --git a/tests/066-mismatched-super/src/Defs.java b/tests/066-mismatched-super/src/Defs.java
index a630c90..e7eb8a1 100644
--- a/tests/066-mismatched-super/src/Defs.java
+++ b/tests/066-mismatched-super/src/Defs.java
@@ -9,4 +9,3 @@
System.out.println("yo yo");
}
}
-
diff --git a/tests/066-mismatched-super/src/Indirect.java b/tests/066-mismatched-super/src/Indirect.java
index dd87a65..023e409 100644
--- a/tests/066-mismatched-super/src/Indirect.java
+++ b/tests/066-mismatched-super/src/Indirect.java
@@ -25,4 +25,3 @@
Base base = new Base();
}
}
-
diff --git a/tests/066-mismatched-super/src/Main.java b/tests/066-mismatched-super/src/Main.java
index 6993b17..5975b99 100644
--- a/tests/066-mismatched-super/src/Main.java
+++ b/tests/066-mismatched-super/src/Main.java
@@ -27,4 +27,3 @@
}
}
}
-
diff --git a/tests/066-mismatched-super/src2/Defs.java b/tests/066-mismatched-super/src2/Defs.java
index 456b6bf..bab92d8 100644
--- a/tests/066-mismatched-super/src2/Defs.java
+++ b/tests/066-mismatched-super/src2/Defs.java
@@ -5,4 +5,3 @@
// func2 not defined
}
-
diff --git a/tests/067-preemptive-unpark/src/Main.java b/tests/067-preemptive-unpark/src/Main.java
index 1ecac14..a16219e 100644
--- a/tests/067-preemptive-unpark/src/Main.java
+++ b/tests/067-preemptive-unpark/src/Main.java
@@ -7,11 +7,11 @@
public static void main(String[] args) throws Exception {
setUp();
-
+
ParkTester test = new ParkTester();
System.out.println("Test starting");
-
+
test.start();
UNSAFE.unpark(test);
clearStack(10);
@@ -81,7 +81,7 @@
private static class ParkTester extends Thread {
public volatile boolean parkNow = false;
public volatile boolean success = false;
-
+
public void run() {
while (!parkNow) {
try {
diff --git a/tests/068-classloader/src-ex/AbstractGet.java b/tests/068-classloader/src-ex/AbstractGet.java
index b62aa8f..db13b32 100644
--- a/tests/068-classloader/src-ex/AbstractGet.java
+++ b/tests/068-classloader/src-ex/AbstractGet.java
@@ -30,4 +30,3 @@
abstract class AbstractBase extends BaseOkay {
public abstract DoubledExtendOkay getExtended();
}
-
diff --git a/tests/068-classloader/src-ex/DoubledExtend.java b/tests/068-classloader/src-ex/DoubledExtend.java
index 17da2c2..6ad2708 100644
--- a/tests/068-classloader/src-ex/DoubledExtend.java
+++ b/tests/068-classloader/src-ex/DoubledExtend.java
@@ -18,4 +18,3 @@
return "DoubledExtend 2";
}
}
-
diff --git a/tests/068-classloader/src-ex/DoubledExtendOkay.java b/tests/068-classloader/src-ex/DoubledExtendOkay.java
index 766fa8e..9674875 100644
--- a/tests/068-classloader/src-ex/DoubledExtendOkay.java
+++ b/tests/068-classloader/src-ex/DoubledExtendOkay.java
@@ -34,4 +34,3 @@
return "DoubledExtendOkay 2";
}
}
-
diff --git a/tests/068-classloader/src-ex/DoubledImplement.java b/tests/068-classloader/src-ex/DoubledImplement.java
index b479d8f..5c44fc3 100644
--- a/tests/068-classloader/src-ex/DoubledImplement.java
+++ b/tests/068-classloader/src-ex/DoubledImplement.java
@@ -16,4 +16,3 @@
System.out.println("DoubledImplement two");
}
}
-
diff --git a/tests/068-classloader/src-ex/DoubledImplement2.java b/tests/068-classloader/src-ex/DoubledImplement2.java
index 60e820f..24ecb65 100644
--- a/tests/068-classloader/src-ex/DoubledImplement2.java
+++ b/tests/068-classloader/src-ex/DoubledImplement2.java
@@ -30,4 +30,3 @@
System.out.println("DoubledImplement2 two");
}
}
-
diff --git a/tests/068-classloader/src-ex/GetDoubled.java b/tests/068-classloader/src-ex/GetDoubled.java
index 5e20441..28ada1e 100644
--- a/tests/068-classloader/src-ex/GetDoubled.java
+++ b/tests/068-classloader/src-ex/GetDoubled.java
@@ -24,4 +24,3 @@
return new DoubledExtendOkay();
}
}
-
diff --git a/tests/068-classloader/src-ex/IfaceImpl.java b/tests/068-classloader/src-ex/IfaceImpl.java
index 94a3bb0..7e9c27d 100644
--- a/tests/068-classloader/src-ex/IfaceImpl.java
+++ b/tests/068-classloader/src-ex/IfaceImpl.java
@@ -19,4 +19,3 @@
return new DoubledImplement2();
}
}
-
diff --git a/tests/068-classloader/src-ex/IfaceSub.java b/tests/068-classloader/src-ex/IfaceSub.java
index cb932bb..7e512e7 100644
--- a/tests/068-classloader/src-ex/IfaceSub.java
+++ b/tests/068-classloader/src-ex/IfaceSub.java
@@ -17,4 +17,3 @@
public interface IfaceSub extends IfaceSuper {
public DoubledImplement2 getDoubledInstance2();
}
-
diff --git a/tests/068-classloader/src-ex/Inaccessible1.java b/tests/068-classloader/src-ex/Inaccessible1.java
index 7b28427..415a8a1 100644
--- a/tests/068-classloader/src-ex/Inaccessible1.java
+++ b/tests/068-classloader/src-ex/Inaccessible1.java
@@ -9,4 +9,3 @@
System.out.println("--- inaccessible1");
}
}
-
diff --git a/tests/068-classloader/src-ex/Inaccessible2.java b/tests/068-classloader/src-ex/Inaccessible2.java
index b612bfa..dc20c21 100644
--- a/tests/068-classloader/src-ex/Inaccessible2.java
+++ b/tests/068-classloader/src-ex/Inaccessible2.java
@@ -8,4 +8,3 @@
System.out.println("--- inaccessible2");
}
}
-
diff --git a/tests/068-classloader/src-ex/Inaccessible3.java b/tests/068-classloader/src-ex/Inaccessible3.java
index 75a01be..771d0f7 100644
--- a/tests/068-classloader/src-ex/Inaccessible3.java
+++ b/tests/068-classloader/src-ex/Inaccessible3.java
@@ -8,4 +8,3 @@
System.out.println("--- inaccessible3");
}
}
-
diff --git a/tests/068-classloader/src/Base.java b/tests/068-classloader/src/Base.java
index 37bc1f2..b297a8a 100644
--- a/tests/068-classloader/src/Base.java
+++ b/tests/068-classloader/src/Base.java
@@ -14,4 +14,3 @@
return dt.getStr();
}
}
-
diff --git a/tests/068-classloader/src/BaseOkay.java b/tests/068-classloader/src/BaseOkay.java
index c5c3f7a..48b7796 100644
--- a/tests/068-classloader/src/BaseOkay.java
+++ b/tests/068-classloader/src/BaseOkay.java
@@ -36,4 +36,3 @@
interface IDoubledExtendOkay {
public DoubledExtendOkay getExtended();
}
-
diff --git a/tests/068-classloader/src/DoubledExtend.java b/tests/068-classloader/src/DoubledExtend.java
index 44c2bce..5f8ebc2 100644
--- a/tests/068-classloader/src/DoubledExtend.java
+++ b/tests/068-classloader/src/DoubledExtend.java
@@ -18,4 +18,3 @@
return "DoubledExtend 1";
}
}
-
diff --git a/tests/068-classloader/src/DoubledExtendOkay.java b/tests/068-classloader/src/DoubledExtendOkay.java
index e8ff404..e226e5f 100644
--- a/tests/068-classloader/src/DoubledExtendOkay.java
+++ b/tests/068-classloader/src/DoubledExtendOkay.java
@@ -34,4 +34,3 @@
return "DoubledExtendOkay 1";
}
}
-
diff --git a/tests/068-classloader/src/DoubledImplement.java b/tests/068-classloader/src/DoubledImplement.java
index 5568a43..64ec5e2 100644
--- a/tests/068-classloader/src/DoubledImplement.java
+++ b/tests/068-classloader/src/DoubledImplement.java
@@ -16,4 +16,3 @@
System.out.println("DoubledImplement one");
}
}
-
diff --git a/tests/068-classloader/src/DoubledImplement2.java b/tests/068-classloader/src/DoubledImplement2.java
index 5e18315..12c036c 100644
--- a/tests/068-classloader/src/DoubledImplement2.java
+++ b/tests/068-classloader/src/DoubledImplement2.java
@@ -30,4 +30,3 @@
System.out.println("DoubledImplement2 one");
}
}
-
diff --git a/tests/068-classloader/src/FancyLoader.java b/tests/068-classloader/src/FancyLoader.java
index 1daf155..173b08f 100644
--- a/tests/068-classloader/src/FancyLoader.java
+++ b/tests/068-classloader/src/FancyLoader.java
@@ -185,7 +185,7 @@
throws ClassNotFoundException
{
Class res;
-
+
/*
* 1. Invoke findLoadedClass(String) to check if the class has
* already been loaded.
@@ -226,4 +226,3 @@
return res;
}
}
-
diff --git a/tests/068-classloader/src/ICommon.java b/tests/068-classloader/src/ICommon.java
index 4eac9be..35a98cc 100644
--- a/tests/068-classloader/src/ICommon.java
+++ b/tests/068-classloader/src/ICommon.java
@@ -6,4 +6,3 @@
public interface ICommon {
public DoubledImplement getDoubledInstance();
}
-
diff --git a/tests/068-classloader/src/ICommon2.java b/tests/068-classloader/src/ICommon2.java
index 13b2c23..6d81afc 100644
--- a/tests/068-classloader/src/ICommon2.java
+++ b/tests/068-classloader/src/ICommon2.java
@@ -20,4 +20,3 @@
public interface ICommon2 {
public DoubledImplement2 getDoubledInstance2();
}
-
diff --git a/tests/068-classloader/src/IGetDoubled.java b/tests/068-classloader/src/IGetDoubled.java
index 0a4ac91..08cd1ce 100644
--- a/tests/068-classloader/src/IGetDoubled.java
+++ b/tests/068-classloader/src/IGetDoubled.java
@@ -20,4 +20,3 @@
public interface IGetDoubled {
public DoubledExtendOkay getDoubled();
}
-
diff --git a/tests/068-classloader/src/IfaceSuper.java b/tests/068-classloader/src/IfaceSuper.java
index f01963a..36d278c 100644
--- a/tests/068-classloader/src/IfaceSuper.java
+++ b/tests/068-classloader/src/IfaceSuper.java
@@ -17,4 +17,3 @@
public interface IfaceSuper {
public DoubledImplement2 getDoubledInstance2();
}
-
diff --git a/tests/068-classloader/src/InaccessibleBase.java b/tests/068-classloader/src/InaccessibleBase.java
index d43ea00..83af665 100644
--- a/tests/068-classloader/src/InaccessibleBase.java
+++ b/tests/068-classloader/src/InaccessibleBase.java
@@ -5,4 +5,3 @@
*/
class InaccessibleBase {
}
-
diff --git a/tests/068-classloader/src/InaccessibleInterface.java b/tests/068-classloader/src/InaccessibleInterface.java
index 6df7501..7f52b80 100644
--- a/tests/068-classloader/src/InaccessibleInterface.java
+++ b/tests/068-classloader/src/InaccessibleInterface.java
@@ -5,4 +5,3 @@
*/
interface InaccessibleInterface {
}
-
diff --git a/tests/068-classloader/src/Main.java b/tests/068-classloader/src/Main.java
index 0788b52..1bc7b04 100644
--- a/tests/068-classloader/src/Main.java
+++ b/tests/068-classloader/src/Main.java
@@ -423,4 +423,3 @@
di2.one();
}
}
-
diff --git a/tests/068-classloader/src/SimpleBase.java b/tests/068-classloader/src/SimpleBase.java
index 5e1fb5a..fd56db9 100644
--- a/tests/068-classloader/src/SimpleBase.java
+++ b/tests/068-classloader/src/SimpleBase.java
@@ -6,4 +6,3 @@
public class SimpleBase {
public SimpleBase() {}
}
-
diff --git a/tests/069-field-type/info.txt b/tests/069-field-type/info.txt
index 58db32e..6e3a22f 100644
--- a/tests/069-field-type/info.txt
+++ b/tests/069-field-type/info.txt
@@ -2,4 +2,3 @@
inappropriate object type in an instance field. By compiling two
versions of the field-holder class we can bypass the compiler's type
safety.
-
diff --git a/tests/069-field-type/src/Blah.java b/tests/069-field-type/src/Blah.java
index 932f276..fd98336 100644
--- a/tests/069-field-type/src/Blah.java
+++ b/tests/069-field-type/src/Blah.java
@@ -7,4 +7,3 @@
System.out.println("run");
}
}
-
diff --git a/tests/069-field-type/src/Holder.java b/tests/069-field-type/src/Holder.java
index ec56e69..e3c9f89 100644
--- a/tests/069-field-type/src/Holder.java
+++ b/tests/069-field-type/src/Holder.java
@@ -5,4 +5,3 @@
public class Holder {
public Runnable mValue;
}
-
diff --git a/tests/069-field-type/src/Main.java b/tests/069-field-type/src/Main.java
index 72268e9..f9885e6 100644
--- a/tests/069-field-type/src/Main.java
+++ b/tests/069-field-type/src/Main.java
@@ -32,4 +32,3 @@
System.out.println("Done");
}
}
-
diff --git a/tests/069-field-type/src2/Blah.java b/tests/069-field-type/src2/Blah.java
index b40e732..1bffff6 100644
--- a/tests/069-field-type/src2/Blah.java
+++ b/tests/069-field-type/src2/Blah.java
@@ -8,4 +8,3 @@
return 0;
}
}
-
diff --git a/tests/070-nio-buffer/src/Main.java b/tests/070-nio-buffer/src/Main.java
index 8cdaa51..bfcab3a 100644
--- a/tests/070-nio-buffer/src/Main.java
+++ b/tests/070-nio-buffer/src/Main.java
@@ -89,10 +89,9 @@
int1.clear ();
int1.put (data);
int1.position (0);
-
+
int1.clear ();
int1.put (data);
int1.position (0);
}
}
-
diff --git a/tests/071-dexfile/src-ex/Another.java b/tests/071-dexfile/src-ex/Another.java
index e732b5b..c978c59 100644
--- a/tests/071-dexfile/src-ex/Another.java
+++ b/tests/071-dexfile/src-ex/Another.java
@@ -26,4 +26,3 @@
}
}
}
-
diff --git a/tests/071-dexfile/src/Main.java b/tests/071-dexfile/src/Main.java
index 42c841d..d71aec0 100644
--- a/tests/071-dexfile/src/Main.java
+++ b/tests/071-dexfile/src/Main.java
@@ -143,4 +143,3 @@
return (ClassLoader) dclObj;
}
}
-
diff --git a/tests/072-precise-gc/src/Main.java b/tests/072-precise-gc/src/Main.java
index 9b2315d..e049221 100644
--- a/tests/072-precise-gc/src/Main.java
+++ b/tests/072-precise-gc/src/Main.java
@@ -111,4 +111,3 @@
System.out.println(str0+str1+str2+str3+str4+str5+str6+str7+str8+str9);
}
}
-
diff --git a/tests/073-mismatched-field/src/IMain.java b/tests/073-mismatched-field/src/IMain.java
index 301dd21..3ad5ecb 100644
--- a/tests/073-mismatched-field/src/IMain.java
+++ b/tests/073-mismatched-field/src/IMain.java
@@ -17,4 +17,3 @@
public interface IMain {
//static int f = 123;
}
-
diff --git a/tests/073-mismatched-field/src/Main.java b/tests/073-mismatched-field/src/Main.java
index fb9f32a..70709c0 100644
--- a/tests/073-mismatched-field/src/Main.java
+++ b/tests/073-mismatched-field/src/Main.java
@@ -29,4 +29,3 @@
}
}
}
-
diff --git a/tests/073-mismatched-field/src/SuperMain.java b/tests/073-mismatched-field/src/SuperMain.java
index 7447739..48a9bab 100644
--- a/tests/073-mismatched-field/src/SuperMain.java
+++ b/tests/073-mismatched-field/src/SuperMain.java
@@ -17,4 +17,3 @@
public class SuperMain {
public int f = 456;
}
-
diff --git a/tests/073-mismatched-field/src2/IMain.java b/tests/073-mismatched-field/src2/IMain.java
index 585c738..136f2a1 100644
--- a/tests/073-mismatched-field/src2/IMain.java
+++ b/tests/073-mismatched-field/src2/IMain.java
@@ -17,4 +17,3 @@
public interface IMain {
static int f = 123;
}
-
diff --git a/tests/074-gc-thrash/info.txt b/tests/074-gc-thrash/info.txt
index c195adb..ded1582 100644
--- a/tests/074-gc-thrash/info.txt
+++ b/tests/074-gc-thrash/info.txt
@@ -1,2 +1 @@
This thrashes the memory allocator and garbage collector for a brief period.
-
diff --git a/tests/074-gc-thrash/src/Main.java b/tests/074-gc-thrash/src/Main.java
index f79e5ce..f85aa4b 100644
--- a/tests/074-gc-thrash/src/Main.java
+++ b/tests/074-gc-thrash/src/Main.java
@@ -335,4 +335,3 @@
public void pretendToUse(byte[] chunk) {}
}
-
diff --git a/tests/075-verification-error/src/Main.java b/tests/075-verification-error/src/Main.java
index f357242..51d648c 100644
--- a/tests/075-verification-error/src/Main.java
+++ b/tests/075-verification-error/src/Main.java
@@ -146,4 +146,3 @@
}
}
}
-
diff --git a/tests/075-verification-error/src/MaybeAbstract.java b/tests/075-verification-error/src/MaybeAbstract.java
index 43c002b..6d3b05b 100644
--- a/tests/075-verification-error/src/MaybeAbstract.java
+++ b/tests/075-verification-error/src/MaybeAbstract.java
@@ -18,4 +18,3 @@
public MaybeAbstract() {}
int foo() { return 0; }
}
-
diff --git a/tests/075-verification-error/src/other/InaccessibleClass.java b/tests/075-verification-error/src/other/InaccessibleClass.java
index 254eaa3..b9bdfc4 100644
--- a/tests/075-verification-error/src/other/InaccessibleClass.java
+++ b/tests/075-verification-error/src/other/InaccessibleClass.java
@@ -21,4 +21,3 @@
public static int blah = 5;
}
-
diff --git a/tests/075-verification-error/src/other/InaccessibleMethod.java b/tests/075-verification-error/src/other/InaccessibleMethod.java
index 49a0b29..0460373 100644
--- a/tests/075-verification-error/src/other/InaccessibleMethod.java
+++ b/tests/075-verification-error/src/other/InaccessibleMethod.java
@@ -19,4 +19,3 @@
public class InaccessibleMethod {
public static void test() {}
}
-
diff --git a/tests/075-verification-error/src/other/Mutant.java b/tests/075-verification-error/src/other/Mutant.java
index 6c869c0..ec4754b 100644
--- a/tests/075-verification-error/src/other/Mutant.java
+++ b/tests/075-verification-error/src/other/Mutant.java
@@ -41,4 +41,3 @@
System.out.println("nay");
}
}
-
diff --git a/tests/075-verification-error/src2/MaybeAbstract.java b/tests/075-verification-error/src2/MaybeAbstract.java
index bfbfd45..8b70a07 100644
--- a/tests/075-verification-error/src2/MaybeAbstract.java
+++ b/tests/075-verification-error/src2/MaybeAbstract.java
@@ -18,4 +18,3 @@
public MaybeAbstract() {}
int foo() { return 0; }
}
-
diff --git a/tests/075-verification-error/src2/other/InaccessibleClass.java b/tests/075-verification-error/src2/other/InaccessibleClass.java
index a3cfbff..812fac9 100644
--- a/tests/075-verification-error/src2/other/InaccessibleClass.java
+++ b/tests/075-verification-error/src2/other/InaccessibleClass.java
@@ -21,4 +21,3 @@
public static int blah = 5;
}
-
diff --git a/tests/075-verification-error/src2/other/InaccessibleMethod.java b/tests/075-verification-error/src2/other/InaccessibleMethod.java
index 6e2738e..9fb844e 100644
--- a/tests/075-verification-error/src2/other/InaccessibleMethod.java
+++ b/tests/075-verification-error/src2/other/InaccessibleMethod.java
@@ -19,4 +19,3 @@
public class InaccessibleMethod {
/*package*/ static void test() {}
}
-
diff --git a/tests/075-verification-error/src2/other/Mutant.java b/tests/075-verification-error/src2/other/Mutant.java
index 220fda0..67cd36d 100644
--- a/tests/075-verification-error/src2/other/Mutant.java
+++ b/tests/075-verification-error/src2/other/Mutant.java
@@ -41,5 +41,3 @@
System.out.println("nay");
}
}
-
-
diff --git a/tests/077-method-override/src/Base.java b/tests/077-method-override/src/Base.java
index eed6f22..befe2e2 100644
--- a/tests/077-method-override/src/Base.java
+++ b/tests/077-method-override/src/Base.java
@@ -81,4 +81,3 @@
System.out.println("overrideStaticWithVirtual: Base");
}
}
-
diff --git a/tests/077-method-override/src/Derived.java b/tests/077-method-override/src/Derived.java
index 09ffdf6..7dc43d0 100644
--- a/tests/077-method-override/src/Derived.java
+++ b/tests/077-method-override/src/Derived.java
@@ -57,4 +57,3 @@
System.out.println("overrideStaticWithVirtual: Derived");
}
}
-
diff --git a/tests/077-method-override/src/Main.java b/tests/077-method-override/src/Main.java
index fa401cd..2d10ee0 100644
--- a/tests/077-method-override/src/Main.java
+++ b/tests/077-method-override/src/Main.java
@@ -51,4 +51,3 @@
}
}
}
-
diff --git a/tests/077-method-override/src2/Base.java b/tests/077-method-override/src2/Base.java
index 8be42bc..ab2a28b 100644
--- a/tests/077-method-override/src2/Base.java
+++ b/tests/077-method-override/src2/Base.java
@@ -80,4 +80,3 @@
System.out.println("overrideStaticWithVirtual: Base");
}
}
-
diff --git a/tests/079-phantom/src/Bitmap.java b/tests/079-phantom/src/Bitmap.java
index 4d9c259..9d03cbd 100644
--- a/tests/079-phantom/src/Bitmap.java
+++ b/tests/079-phantom/src/Bitmap.java
@@ -150,4 +150,3 @@
interrupt();
}
}
-
diff --git a/tests/079-phantom/src/Main.java b/tests/079-phantom/src/Main.java
index 3965481..9c459c9 100644
--- a/tests/079-phantom/src/Main.java
+++ b/tests/079-phantom/src/Main.java
@@ -83,4 +83,3 @@
mBitmap3 = mBitmap4 = new Bitmap("three/four", 20, 20, dataB);
}
}
-
diff --git a/tests/084-class-init/expected.txt b/tests/084-class-init/expected.txt
new file mode 100644
index 0000000..9865edb
--- /dev/null
+++ b/tests/084-class-init/expected.txt
@@ -0,0 +1,8 @@
+Got expected EIIE for FIELD0
+Got expected NCDFE for FIELD0
+Got expected NCDFE for FIELD1
+SlowInit static block pre-sleep
+SlowInit static block post-sleep
+Fields (child thread): 111222333444
+MethodThread message
+Fields (main thread): 111222333444
diff --git a/tests/084-class-init/info.txt b/tests/084-class-init/info.txt
new file mode 100644
index 0000000..00fa31b
--- /dev/null
+++ b/tests/084-class-init/info.txt
@@ -0,0 +1 @@
+Test class initialization edge cases and race conditions.
diff --git a/tests/084-class-init/src/IntHolder.java b/tests/084-class-init/src/IntHolder.java
new file mode 100644
index 0000000..4012d6e
--- /dev/null
+++ b/tests/084-class-init/src/IntHolder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Holds an int.
+ */
+public class IntHolder {
+ private int mValue = 0;
+
+ /**
+ * Constructs an IntHolder with the specified value. Throws an
+ * exception if the initial value is less than zero.
+ */
+ public IntHolder(int initialVal) {
+ if (initialVal < 0)
+ throw new RuntimeException("negative number");
+
+ mValue = initialVal;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+ public void setValue(int val) {
+ mValue = val;
+ }
+}
diff --git a/tests/084-class-init/src/Main.java b/tests/084-class-init/src/Main.java
new file mode 100644
index 0000000..89b76f5
--- /dev/null
+++ b/tests/084-class-init/src/Main.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ checkExceptions();
+ checkTiming();
+ }
+
+ public static void sleep(int msec) {
+ try {
+ Thread.sleep(msec);
+ } catch (InterruptedException ie) {
+ System.err.println("sleep interrupted");
+ }
+ }
+
+ static void checkExceptions() {
+ try {
+ System.out.println(PartialInit.FIELD0);
+ System.err.println("Construction of PartialInit succeeded unexpectedly");
+ } catch (ExceptionInInitializerError eiie) {
+ System.out.println("Got expected EIIE for FIELD0");
+ }
+
+ try {
+ System.out.println(PartialInit.FIELD0);
+ System.err.println("Load of FIELD0 succeeded unexpectedly");
+ } catch (NoClassDefFoundError ncdfe) {
+ System.out.println("Got expected NCDFE for FIELD0");
+ }
+ try {
+ System.out.println(PartialInit.FIELD1);
+ System.err.println("Load of FIELD1 succeeded unexpectedly");
+ } catch (NoClassDefFoundError ncdfe) {
+ System.out.println("Got expected NCDFE for FIELD1");
+ }
+ }
+
+ static void checkTiming() {
+ FieldThread fieldThread = new FieldThread();
+ MethodThread methodThread = new MethodThread();
+
+ fieldThread.start();
+ methodThread.start();
+
+ /* start class init */
+ IntHolder zero = SlowInit.FIELD0;
+
+ /* init complete; allow other threads time to finish printing */
+ Main.sleep(500);
+
+ /* print all values */
+ System.out.println("Fields (main thread): " +
+ SlowInit.FIELD0.getValue() + SlowInit.FIELD1.getValue() +
+ SlowInit.FIELD2.getValue() + SlowInit.FIELD3.getValue());
+ }
+
+ static class FieldThread extends Thread {
+ public void run() {
+ /* allow class init to start */
+ Main.sleep(200);
+
+ /* print fields; should delay until class init completes */
+ System.out.println("Fields (child thread): " +
+ SlowInit.FIELD0.getValue() + SlowInit.FIELD1.getValue() +
+ SlowInit.FIELD2.getValue() + SlowInit.FIELD3.getValue());
+ }
+ }
+
+ static class MethodThread extends Thread {
+ public void run() {
+ /* allow class init to start */
+ Main.sleep(400);
+
+ /* use a method that shouldn't be accessible yet */
+ SlowInit.printMsg("MethodThread message");
+ }
+ }
+}
diff --git a/dexdump/OpCodeNames.h b/tests/084-class-init/src/PartialInit.java
similarity index 66%
copy from dexdump/OpCodeNames.h
copy to tests/084-class-init/src/PartialInit.java
index 1aec0d1..d4c71ff 100644
--- a/dexdump/OpCodeNames.h
+++ b/tests/084-class-init/src/PartialInit.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * Dalvik opcode names.
- */
-#ifndef _DEXDUMP_OPCODENAMES
-#define _DEXDUMP_OPCODENAMES
-#include "libdex/OpCode.h"
-const char* getOpcodeName(OpCode op);
-
-#endif /*_DEXDUMP_OPCODENAMES*/
+/**
+ * Partially-initialized class.
+ */
+public class PartialInit {
+ public static final IntHolder FIELD0 = new IntHolder(1); // succeeds
+ public static final IntHolder FIELD1 = new IntHolder(-2); // throws
+}
diff --git a/tests/084-class-init/src/SlowInit.java b/tests/084-class-init/src/SlowInit.java
new file mode 100644
index 0000000..8ac72be
--- /dev/null
+++ b/tests/084-class-init/src/SlowInit.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class that initializes with a pause.
+ */
+public class SlowInit {
+
+ public static final IntHolder FIELD0 = new IntHolder(0);
+ public static final IntHolder FIELD1 = new IntHolder(0);
+ public static final IntHolder FIELD2 = new IntHolder(0);
+ public static final IntHolder FIELD3 = new IntHolder(0);
+
+ public static void printMsg(String msg) {
+ System.out.println(msg);
+ }
+
+ static {
+ FIELD0.setValue(111);
+ FIELD1.setValue(222);
+ printMsg("SlowInit static block pre-sleep");
+ Main.sleep(600);
+ printMsg("SlowInit static block post-sleep");
+ FIELD2.setValue(333);
+ FIELD3.setValue(444);
+ };
+}
diff --git a/tests/084-old-style-inner-class/build b/tests/084-old-style-inner-class/build
new file mode 100644
index 0000000..dc6f3bb
--- /dev/null
+++ b/tests/084-old-style-inner-class/build
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# We compile for a 1.4 target to suppress the use of EnclosingMethod
+# attributes.
+mkdir classes
+${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
+
+# Suppress stderr to keep the inner class warnings out of the expected output.
+dx --debug --dex --dump-to=classes.lst --output=classes.dex \
+ --dump-width=1000 classes 2>/dev/null
+
+zip test.jar classes.dex
diff --git a/tests/084-old-style-inner-class/expected.txt b/tests/084-old-style-inner-class/expected.txt
new file mode 100644
index 0000000..63a0076
--- /dev/null
+++ b/tests/084-old-style-inner-class/expected.txt
@@ -0,0 +1,8 @@
+Class: Main$1
+ getDeclaringClass(): (null)
+ getEnclosingClass(): (null)
+ getEnclosingMethod(): (null)
+Class: Main$2
+ getDeclaringClass(): (null)
+ getEnclosingClass(): (null)
+ getEnclosingMethod(): (null)
diff --git a/tests/084-old-style-inner-class/info.txt b/tests/084-old-style-inner-class/info.txt
new file mode 100644
index 0000000..9e5c4f9
--- /dev/null
+++ b/tests/084-old-style-inner-class/info.txt
@@ -0,0 +1,2 @@
+Test that the conversion of an old-style (pre-1.5) inner class results
+in a loss of inner class reflection information.
diff --git a/tests/084-old-style-inner-class/src/Main.java b/tests/084-old-style-inner-class/src/Main.java
new file mode 100644
index 0000000..c9a5b72
--- /dev/null
+++ b/tests/084-old-style-inner-class/src/Main.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+/**
+ * Test reflection on old-style inner classes.
+ */
+public class Main {
+ private static Runnable theRunnable = new Runnable() {
+ public void run() { }
+ };
+
+ private static Runnable create() {
+ return new Runnable() {
+ public void run() { }
+ };
+ }
+
+ private static String nameOf(Class clazz) {
+ return (clazz == null) ? "(null)" : clazz.getName();
+ }
+
+ private static String nameOf(Method meth) {
+ return (meth == null) ? "(null)" : meth.toString();
+ }
+
+ private static void infoFor(Class clazz) {
+ System.out.println("Class: " + nameOf(clazz) + "\n" +
+ " getDeclaringClass(): " +
+ nameOf(clazz.getDeclaringClass()) + "\n" +
+ " getEnclosingClass(): " +
+ nameOf(clazz.getEnclosingClass()) + "\n" +
+ " getEnclosingMethod(): " +
+ nameOf(clazz.getEnclosingMethod()));
+ }
+
+ public static void main(String args[]) {
+ infoFor(theRunnable.getClass());
+ infoFor(create().getClass());
+ }
+}
diff --git a/tests/086-null-super/expected.txt b/tests/086-null-super/expected.txt
new file mode 100644
index 0000000..20c6796
--- /dev/null
+++ b/tests/086-null-super/expected.txt
@@ -0,0 +1 @@
+Got expected ITE/NPE
diff --git a/tests/086-null-super/info.txt b/tests/086-null-super/info.txt
new file mode 100644
index 0000000..f983bd0
--- /dev/null
+++ b/tests/086-null-super/info.txt
@@ -0,0 +1,7 @@
+ClassLoader.loadClass() is expected to throw an exception, usually
+ClassNotFound, if it can't find the given Class, and not return null.
+
+This is a regression test for a defect in Dalvik, which was assuming
+that if there was no exception, the value returned would be non-null.
+
+This test is not expected to work for the reference implementation.
diff --git a/tests/086-null-super/src/Main.java b/tests/086-null-super/src/Main.java
new file mode 100644
index 0000000..6decb20
--- /dev/null
+++ b/tests/086-null-super/src/Main.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Class loader test.
+ */
+public class Main {
+ /**
+ * Thrown when an unexpected Exception is caught internally.
+ */
+ static class TestFailed extends Exception {
+ public TestFailed(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ /**
+ * A class loader which loads classes from the dex file
+ * "test.jar". However, it will return null when asked to load the
+ * class InaccessibleSuper.
+ *
+ * When testing code calls BrokenDexLoader's findBrokenClass(),
+ * a BrokenDexLoader will be the defining loader for the class
+ * Inaccessible. The VM will call the defining loader for
+ * "InaccessibleSuper", which will return null, which the VM
+ * should be able to deal with gracefully.
+ *
+ * Note that this depends heavily on the Dalvik test harness.
+ */
+ static class BrokenDexLoader extends ClassLoader {
+
+ /** We return null when asked to load InaccessibleSuper. */
+ private static class InaccessibleSuper {}
+ private static class Inaccessible extends InaccessibleSuper {}
+
+ private static final String SUPERCLASS_NAME =
+ "Main$BrokenDexLoader$InaccessibleSuper";
+ private static final String CLASS_NAME =
+ "Main$BrokenDexLoader$Inaccessible";
+
+ private static final String DEX_FILE = "test.jar";
+
+ public BrokenDexLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ /**
+ * Finds the class with the specified binary name, from DEX_FILE.
+ *
+ * If we don't find a match, we throw an exception.
+ */
+ private Class<?> findDexClass(String name)
+ throws TestFailed, InvocationTargetException
+ {
+
+ try {
+ /*
+ * Find the DexFile class, and construct a DexFile object
+ * through reflection, then call loadCLass on it.
+ */
+ Class mDexClass = ClassLoader.getSystemClassLoader().
+ loadClass("dalvik/system/DexFile");
+ Constructor ctor = mDexClass.
+ getConstructor(new Class[] {String.class});
+ Object mDexFile = ctor.newInstance(DEX_FILE);
+ Method meth = mDexClass.
+ getMethod("loadClass",
+ new Class[] { String.class, ClassLoader.class });
+ /*
+ * Invoking loadClass on CLASS_NAME is expected to
+ * throw an InvocationTargetException. Anything else
+ * is an error we can't recover from.
+ */
+ meth.invoke(mDexFile, name, this);
+ } catch (NoSuchMethodException nsme) {
+ throw new TestFailed(nsme);
+ } catch (InstantiationException ie) {
+ throw new TestFailed(ie);
+ } catch (IllegalAccessException iae) {
+ throw new TestFailed(iae);
+ } catch (ClassNotFoundException cnfe) {
+ throw new TestFailed(cnfe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Load a class.
+ *
+ * Return null if the class's name is SUPERCLASS_NAME;
+ * otherwise invoke the super's loadClass method.
+ */
+ public Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ if (SUPERCLASS_NAME.equals(name)) {
+ return null;
+ }
+
+ return super.loadClass(name, resolve);
+ }
+
+ /**
+ * Attempt to find the class with the superclass we refuse to
+ * load. This is expected to throw an
+ * InvocationTargetException, with a NullPointerException as
+ * its cause.
+ */
+ public void findBrokenClass()
+ throws TestFailed, InvocationTargetException
+ {
+ findDexClass(CLASS_NAME);
+ }
+ }
+
+ /**
+ * Main entry point.
+ */
+ public static void main(String[] args)
+ throws TestFailed, ClassNotFoundException {
+ /*
+ * Run test.
+ */
+ testFailLoadAndGc();
+ }
+
+ /**
+ * See if we can GC after a failed load.
+ */
+ static void testFailLoadAndGc() throws TestFailed {
+ try {
+ BrokenDexLoader loader;
+
+ loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
+ loader.findBrokenClass();
+ System.err.println("ERROR: Inaccessible was accessible");
+ } catch (InvocationTargetException ite) {
+ Throwable cause = ite.getCause();
+ if (cause instanceof NullPointerException) {
+ System.err.println("Got expected ITE/NPE");
+ } else {
+ System.err.println("Got unexpected ITE");
+ ite.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/tests/087-gc-after-link/expected.txt b/tests/087-gc-after-link/expected.txt
new file mode 100644
index 0000000..3b2d33a
--- /dev/null
+++ b/tests/087-gc-after-link/expected.txt
@@ -0,0 +1,2 @@
+Got expected ITE/NPE
+GC complete.
diff --git a/tests/087-gc-after-link/info.txt b/tests/087-gc-after-link/info.txt
new file mode 100644
index 0000000..9483838
--- /dev/null
+++ b/tests/087-gc-after-link/info.txt
@@ -0,0 +1,8 @@
+This test causes a linkage error, which calls dvmFreeClassInnards on
+the unlinked Class.
+
+This is a regression test for a defect in Dalvik, which was assuming
+that dvmFreeClassInnards could be called twice on the same class.
+
+This test is a modified version of test 086.
+This test is not expected to work for the reference implementation.
diff --git a/tests/087-gc-after-link/src/Main.java b/tests/087-gc-after-link/src/Main.java
new file mode 100644
index 0000000..24adaf7
--- /dev/null
+++ b/tests/087-gc-after-link/src/Main.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Class loader test.
+ */
+public class Main {
+ /**
+ * Thrown when an unexpected Exception is caught internally.
+ */
+ static class TestFailed extends Exception {
+ public TestFailed(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ /**
+ * A class loader which loads classes from the dex file
+ * "test.jar". However, it will return null when asked to load the
+ * class InaccessibleSuper.
+ *
+ * When testing code calls BrokenDexLoader's findBrokenClass(),
+ * a BrokenDexLoader will be the defining loader for the class
+ * Inaccessible. The VM will call the defining loader for
+ * "InaccessibleSuper", which will return null, which the VM
+ * should be able to deal with gracefully.
+ *
+ * Note that this depends heavily on the Dalvik test harness.
+ */
+ static class BrokenDexLoader extends ClassLoader {
+
+ /** We return null when asked to load InaccessibleSuper. */
+ private static class InaccessibleSuper {}
+ private static class Inaccessible extends InaccessibleSuper {}
+
+ private static final String SUPERCLASS_NAME =
+ "Main$BrokenDexLoader$InaccessibleSuper";
+ private static final String CLASS_NAME =
+ "Main$BrokenDexLoader$Inaccessible";
+
+ private static final String DEX_FILE = "test.jar";
+
+ public BrokenDexLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ /**
+ * Finds the class with the specified binary name, from DEX_FILE.
+ *
+ * If we don't find a match, we throw an exception.
+ */
+ private Class<?> findDexClass(String name)
+ throws TestFailed, InvocationTargetException
+ {
+
+ try {
+ /*
+ * Find the DexFile class, and construct a DexFile object
+ * through reflection, then call loadCLass on it.
+ */
+ Class mDexClass = ClassLoader.getSystemClassLoader().
+ loadClass("dalvik/system/DexFile");
+ Constructor ctor = mDexClass.
+ getConstructor(new Class[] {String.class});
+ Object mDexFile = ctor.newInstance(DEX_FILE);
+ Method meth = mDexClass.
+ getMethod("loadClass",
+ new Class[] { String.class, ClassLoader.class });
+ /*
+ * Invoking loadClass on CLASS_NAME is expected to
+ * throw an InvocationTargetException. Anything else
+ * is an error we can't recover from.
+ */
+ meth.invoke(mDexFile, name, this);
+ } catch (NoSuchMethodException nsme) {
+ throw new TestFailed(nsme);
+ } catch (InstantiationException ie) {
+ throw new TestFailed(ie);
+ } catch (IllegalAccessException iae) {
+ throw new TestFailed(iae);
+ } catch (ClassNotFoundException cnfe) {
+ throw new TestFailed(cnfe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Load a class.
+ *
+ * Return null if the class's name is SUPERCLASS_NAME;
+ * otherwise invoke the super's loadClass method.
+ */
+ public Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ if (SUPERCLASS_NAME.equals(name)) {
+ return null;
+ }
+
+ return super.loadClass(name, resolve);
+ }
+
+ /**
+ * Attempt to find the class with the superclass we refuse to
+ * load. This is expected to throw an
+ * InvocationTargetException, with a NullPointerException as
+ * its cause.
+ */
+ public void findBrokenClass()
+ throws TestFailed, InvocationTargetException
+ {
+ findDexClass(CLASS_NAME);
+ }
+ }
+
+ /**
+ * Main entry point.
+ */
+ public static void main(String[] args)
+ throws TestFailed, ClassNotFoundException {
+ /*
+ * Run test.
+ */
+ testFailLoadAndGc();
+ }
+
+ /**
+ * See if we can GC after a failed load.
+ */
+ static void testFailLoadAndGc() throws TestFailed {
+ try {
+ BrokenDexLoader loader;
+
+ loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
+ loader.findBrokenClass();
+ System.err.println("ERROR: Inaccessible was accessible");
+ } catch (InvocationTargetException ite) {
+ Throwable cause = ite.getCause();
+ if (cause instanceof NullPointerException) {
+ System.err.println("Got expected ITE/NPE");
+ } else {
+ System.err.println("Got unexpected ITE");
+ ite.printStackTrace();
+ }
+ }
+ System.gc();
+ System.out.println("GC complete.");
+ }
+}
diff --git a/tests/README.txt b/tests/README.txt
index 276abbd..eb1ce36 100644
--- a/tests/README.txt
+++ b/tests/README.txt
@@ -11,4 +11,3 @@
directory; this can be used to exercise "API mismatch" situations by
replacing class files created in the first pass. The "src-ex" directory
is built separately, and is intended for exercising class loaders.
-
diff --git a/tests/etc/default-build b/tests/etc/default-build
index b0bf491..b8df442 100755
--- a/tests/etc/default-build
+++ b/tests/etc/default-build
@@ -41,4 +41,3 @@
mv classes.dex classes-ex.dex
mv classes-1.dex classes.dex
fi
-
diff --git a/tests/run-all-tests b/tests/run-all-tests
index ac86e1e..ac01803 100755
--- a/tests/run-all-tests
+++ b/tests/run-all-tests
@@ -122,4 +122,3 @@
for i in $failNames; do
echo "failed: $i"
done
-
diff --git a/tools/deadcode.py b/tools/deadcode.py
index eb71b7c..2ef8c70 100755
--- a/tools/deadcode.py
+++ b/tools/deadcode.py
@@ -9,7 +9,7 @@
When found, the name of the section is extracted. The entire contents
of that section is added to a result hashmap with the section name
as the key"""
-
+
# Match lines like
# |section_name:
# capturing section_name
@@ -19,11 +19,11 @@
start = 0
anchor = -1
sectionName = ''
-
+
while True:
# Look for a section header
result = headerPattern.search(buffer, start)
-
+
# If there are no more, add a section from the last header to EOF
if result is None:
if anchor is not -1:
@@ -34,17 +34,17 @@
# map indexed by the section name
if anchor is not -1:
sections[sectionName] = buffer[anchor:result.start()]
-
+
sectionName = result.group(1)
start = result.end()
anchor = start
-
+
return sections
def FindMethods(section):
"""Spin through the 'method code index' section and extract all
method signatures. When found, they are added to a result list."""
-
+
# Match lines like:
# |[abcd] com/example/app/Class.method:(args)return
# capturing the method signature
@@ -56,7 +56,7 @@
while True:
# Look for a method name
result = methodPattern.search(section, start)
-
+
if result is None:
return methods
@@ -68,16 +68,16 @@
"""Spin through all the input method signatures. For each one, return
whether or not there is method invokation line in the codes section that
lists the method as the target."""
-
+
start = 0
-
+
while True:
# Find the next reference to the method signature
match = codes.find(method, start)
-
+
if match is -1:
break;
-
+
# Find the beginning of the line the method reference is on
startOfLine = codes.rfind("\n", 0, match) + 1
@@ -86,9 +86,9 @@
# than the beginning of the code section for that method.
if codes.find("invoke", startOfLine, match) is not -1:
return True
-
+
start = match + len(method)
-
+
return False
@@ -120,7 +120,7 @@
if not CallsMethod(codes, method):
print "\t", method
count += 1
-
+
if count is 0:
print "\tNone"
diff --git a/tools/dexcheck b/tools/dexcheck
index ff3e98d..2ec8b29 100755
--- a/tools/dexcheck
+++ b/tools/dexcheck
@@ -14,9 +14,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# This requires read permission on /data/dalvik-cache. On an eng build this
-# works, on userdebug you will need to "adb root", or "su" followed by
-# "chmod 777 /data/dalvik-cache".
+#
+# This tool checks the integrity of the optimized dex files on a single
+# Android device connected to your computer.
+#
+# Brief HOW-TO:
+#
+# 1. Disconnect all but one device from USB.
+# 2. Set up a standard shell environment (envsetup.sh, lunch, etc.).
+# 3. Run "adb root" if necessary to ensure read permission on
+# /data/dalvik-cache. If in doubt, run the command. Power users may
+# also use "su" followed by "chmod 777 /data/dalvik-cache".
+# 4. Run this script, e.g. from the build root, "dalvik/tools/dexcheck".
+#
+# If all of the dex files are okay, you will just see a series of
+# lines written to your shell window naming each of the files. If
+# there is a problem, though, you will see something like this:
+#
+# system@app@Maps.apk@classes.dex
+# Failure in system@app@Maps.apk@classes.dex: ERROR: DEX parse failed
+#
+# When this happens, the log ("adb logcat") will generally have at
+# least a little more information about the dex level of the problem.
+# However, any error at all usually indicates some form of lower level
+# filesystem or filesystem cache corruption.
+#
# Get the list of files. Use "sed" to drop the trailing carriage return.
files=`adb shell "cd /data/dalvik-cache; echo *" | sed -e s/.$//`
@@ -43,4 +65,3 @@
done
exit $failure
-
diff --git a/tools/dexdeps/README.txt b/tools/dexdeps/README.txt
index 14d65b0..060aecb 100644
--- a/tools/dexdeps/README.txt
+++ b/tools/dexdeps/README.txt
@@ -25,4 +25,3 @@
"xml" produces a larger output file, readable with an XML browser. Types
are shown in a more human-readable form (e.g. "[I" becomes "int[]").
-
diff --git a/tools/dexdeps/src/Android.mk b/tools/dexdeps/src/Android.mk
index 756a0b3..7c0ef2f 100644
--- a/tools/dexdeps/src/Android.mk
+++ b/tools/dexdeps/src/Android.mk
@@ -29,4 +29,3 @@
INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
include $(BUILD_DROIDDOC)
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/ClassRef.java b/tools/dexdeps/src/com/android/dexdeps/ClassRef.java
index 8065a0a..7f6edc9 100644
--- a/tools/dexdeps/src/com/android/dexdeps/ClassRef.java
+++ b/tools/dexdeps/src/com/android/dexdeps/ClassRef.java
@@ -67,4 +67,3 @@
return mClassName;
}
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/DexData.java b/tools/dexdeps/src/com/android/dexdeps/DexData.java
index 0a7fa2d..7ce5d04 100644
--- a/tools/dexdeps/src/com/android/dexdeps/DexData.java
+++ b/tools/dexdeps/src/com/android/dexdeps/DexData.java
@@ -591,4 +591,3 @@
public int classIdx; // index into type_ids
}
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/DexDataException.java b/tools/dexdeps/src/com/android/dexdeps/DexDataException.java
index e51853f..873db94 100644
--- a/tools/dexdeps/src/com/android/dexdeps/DexDataException.java
+++ b/tools/dexdeps/src/com/android/dexdeps/DexDataException.java
@@ -21,4 +21,3 @@
*/
public class DexDataException extends RuntimeException {
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/FieldRef.java b/tools/dexdeps/src/com/android/dexdeps/FieldRef.java
index 2726a7a..93e87cb 100644
--- a/tools/dexdeps/src/com/android/dexdeps/FieldRef.java
+++ b/tools/dexdeps/src/com/android/dexdeps/FieldRef.java
@@ -49,4 +49,3 @@
return mFieldName;
}
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/Main.java b/tools/dexdeps/src/com/android/dexdeps/Main.java
index b1f7f96..d48889d 100644
--- a/tools/dexdeps/src/com/android/dexdeps/Main.java
+++ b/tools/dexdeps/src/com/android/dexdeps/Main.java
@@ -200,4 +200,3 @@
System.err.println(" --format={xml,brief}");
}
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/MethodRef.java b/tools/dexdeps/src/com/android/dexdeps/MethodRef.java
index 96522eb..67dce62 100644
--- a/tools/dexdeps/src/com/android/dexdeps/MethodRef.java
+++ b/tools/dexdeps/src/com/android/dexdeps/MethodRef.java
@@ -85,4 +85,3 @@
return builder.toString();
}
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/Output.java b/tools/dexdeps/src/com/android/dexdeps/Output.java
index 122544c..b786825 100644
--- a/tools/dexdeps/src/com/android/dexdeps/Output.java
+++ b/tools/dexdeps/src/com/android/dexdeps/Output.java
@@ -298,4 +298,3 @@
}
}
}
-
diff --git a/tools/dexdeps/src/com/android/dexdeps/UsageException.java b/tools/dexdeps/src/com/android/dexdeps/UsageException.java
index f9f971b..e695fc7 100644
--- a/tools/dexdeps/src/com/android/dexdeps/UsageException.java
+++ b/tools/dexdeps/src/com/android/dexdeps/UsageException.java
@@ -21,4 +21,3 @@
*/
public class UsageException extends RuntimeException {
}
-
diff --git a/tools/dmtracedump/Android.mk b/tools/dmtracedump/Android.mk
index ef9a9c2..e3f321e 100644
--- a/tools/dmtracedump/Android.mk
+++ b/tools/dmtracedump/Android.mk
@@ -1,4 +1,4 @@
-#
+#
# Copyright 2006 The Android Open Source Project
#
# Java method trace dump tool
@@ -20,5 +20,3 @@
LOCAL_C_INCLUDES += dalvik/vm
LOCAL_MODULE := create_test_dmtrace
include $(BUILD_HOST_EXECUTABLE)
-
-
diff --git a/tools/dmtracedump/CreateTestTrace.c b/tools/dmtracedump/CreateTestTrace.c
index 9d72b1f..0b85d51 100644
--- a/tools/dmtracedump/CreateTestTrace.c
+++ b/tools/dmtracedump/CreateTestTrace.c
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -214,7 +214,7 @@
save_cp = cp;
while (*cp != '\n')
cp += 1;
-
+
/* Remove trailing spaces */
cp -= 1;
while (isspace(*cp))
diff --git a/tools/dmtracedump/TraceDump.c b/tools/dmtracedump/TraceDump.c
index 3dc1893..02cdf98 100644
--- a/tools/dmtracedump/TraceDump.c
+++ b/tools/dmtracedump/TraceDump.c
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -59,7 +59,7 @@
#define DEFAULT_ACTIVE_THREADS 8
-char *htmlHeader =
+char *htmlHeader =
"<html>\n<head>\n<script type=\"text/javascript\" src=\"%ssortable.js\"></script>\n"
"<script langugage=\"javascript\">\n"
"function toggle(item) {\n"
@@ -100,10 +100,10 @@
"</head><body>\n\n";
char *htmlFooter = "\n</body>\n</html>\n";
-char *profileSeparator =
+char *profileSeparator =
"======================================================================";
-
-const char* tableHeader =
+
+const char* tableHeader =
"<table class='sortable' id='%s'><tr>\n"
"<th>Method</th>\n"
"<th>Run 1 (us)</th>\n"
@@ -112,18 +112,18 @@
"<th>Diff (%%)</th>\n"
"<th>1: # calls</th>\n"
"<th>2: # calls</th>\n"
- "</tr>\n";
-
-const char* tableHeaderMissing =
+ "</tr>\n";
+
+const char* tableHeaderMissing =
"<table class='sortable' id='%s'>\n"
"<th>Method</th>\n"
"<th>Exclusive</th>\n"
"<th>Inclusive</th>\n"
"<th># calls</th>\n";
-
-#define GRAPH_LABEL_VISITED 0x0001
+
+#define GRAPH_LABEL_VISITED 0x0001
#define GRAPH_NODE_VISITED 0x0002
-
+
/*
* Values from the header of the data file.
*/
@@ -1227,7 +1227,7 @@
if (id == EOF)
return 1;
*threadId = id;
-
+
*methodVal = read4LE(dataFp);
*elapsedTime = read4LE(dataFp);
if (feof(dataFp)) {
@@ -1465,7 +1465,7 @@
for (ii = 0; ii < num_entries - 1; ++ii)
sorted[ii].next = &sorted[ii + 1];
sorted[num_entries - 1].next = NULL;
-
+
return sorted;
}
@@ -1488,7 +1488,7 @@
char *className, *methodName, *signature;
char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
char signatureBuf[HTML_BUFSIZE];
-
+
anchor_close = "";
if (gOptions.outputHtml)
anchor_close = "</a>";
@@ -1690,7 +1690,7 @@
}
/* check to make sure that the child method meets the threshold of the parent */
-int checkThreshold(MethodEntry* parent, MethodEntry* child)
+int checkThreshold(MethodEntry* parent, MethodEntry* child)
{
double parentTime = parent->elapsedInclusive;
double childTime = child->elapsedInclusive;
@@ -1700,18 +1700,18 @@
void createLabels(FILE* file, MethodEntry* method)
{
- fprintf(file, "node%d[label = \"[%d] %s.%s (%llu, %llu, %d)\"]\n",
- method->index, method->index, method->className, method->methodName,
+ fprintf(file, "node%d[label = \"[%d] %s.%s (%llu, %llu, %d)\"]\n",
+ method->index, method->index, method->className, method->methodName,
method->elapsedInclusive / 1000,
method->elapsedExclusive / 1000,
method->numCalls[0]);
- method->graphState = GRAPH_LABEL_VISITED;
+ method->graphState = GRAPH_LABEL_VISITED;
TimedMethod* child;
for (child = method->children[0] ; child ; child = child->next) {
MethodEntry* childMethod = child->method;
-
+
if ((childMethod->graphState & GRAPH_LABEL_VISITED) == 0 && checkThreshold(method, childMethod)) {
createLabels(file, child->method);
}
@@ -1721,7 +1721,7 @@
void createLinks(FILE* file, MethodEntry* method)
{
method->graphState |= GRAPH_NODE_VISITED;
-
+
TimedMethod* child;
for (child = method->children[0] ; child ; child = child->next) {
MethodEntry* childMethod = child->method;
@@ -1746,19 +1746,19 @@
}
FILE* file = fopen(path, "w+");
-
+
fprintf(file, "digraph g {\nnode [shape = record,height=.1];\n");
-
+
createLabels(file, dataKeys->methods);
createLinks(file, dataKeys->methods);
-
+
fprintf(file, "}");
fclose(file);
-
+
// now that we have the dot file generate the image
char command[1024];
snprintf(command, 1024, "dot -Tpng -o '%s' '%s'", gOptions.graphFileName, path);
-
+
system(command);
if (! gOptions.keepDotFile) {
@@ -2931,7 +2931,7 @@
*/
DataKeys* parseDataKeys(TraceData* traceData, const char* traceFileName,
uint64_t* threadTime, Filter** filters)
-{
+{
DataKeys* dataKeys = NULL;
MethodEntry **pMethods = NULL;
MethodEntry* method;
@@ -2940,7 +2940,7 @@
int ii, jj, numThreads;
uint64_t currentTime;
MethodEntry* caller;
-
+
dataFp = fopen(traceFileName, "r");
if (dataFp == NULL)
goto bail;
@@ -3178,7 +3178,7 @@
}
caller = &dataKeys->methods[TOPLEVEL_INDEX];
caller->elapsedInclusive = sumThreadTime;
-
+
#if 0
fclose(dumpStream);
#endif
@@ -3190,7 +3190,7 @@
bail:
if (dataFp != NULL)
fclose(dataFp);
-
+
return dataKeys;
}
@@ -3207,7 +3207,7 @@
MethodEntry* entry = &dataKeys->methods[ii];
pMethods[ii] = entry;
}
-
+
return pMethods;
}
@@ -3253,7 +3253,7 @@
if (result == 0) {
result = strcmp(methodA->signature, methodB->signature);
if (result == 0) {
- return strcmp(methodA->className, methodB->className);
+ return strcmp(methodA->className, methodB->className);
}
}
return result;
@@ -3262,21 +3262,21 @@
int findMatch(MethodEntry** methods, int size, MethodEntry* matchThis)
{
int i;
-
+
for (i = 0 ; i < size ; i++) {
MethodEntry* method = methods[i];
-
+
if (method != NULL && !compareMethodNamesForDiff(&method, &matchThis)) {
-// printf("%s.%s == %s.%s<br>\n", matchThis->className, matchThis->methodName,
+// printf("%s.%s == %s.%s<br>\n", matchThis->className, matchThis->methodName,
// method->className, method->methodName);
-
+
return i;
/* if (!compareMethodNames(&method, &matchThis)) {
return i;
}
*/ }
}
-
+
return -1;
}
@@ -3286,13 +3286,13 @@
const DiffEntry* entryA = (const DiffEntry*)a;
const DiffEntry* entryB = (const DiffEntry*)b;
-
+
if (entryA->differenceExclusive < entryB->differenceExclusive) {
return 1;
} else if (entryA->differenceExclusive > entryB->differenceExclusive) {
return -1;
}
-
+
return 0;
}
@@ -3302,37 +3302,37 @@
const DiffEntry* entryA = (const DiffEntry*)a;
const DiffEntry* entryB = (const DiffEntry*)b;
-
+
if (entryA->differenceInclusive < entryB->differenceInclusive) {
return 1;
} else if (entryA->differenceInclusive > entryB->differenceInclusive) {
return -1;
}
-
+
return 0;
}
-void printMissingMethod(MethodEntry* method)
+void printMissingMethod(MethodEntry* method)
{
char classBuf[HTML_BUFSIZE];
char methodBuf[HTML_BUFSIZE];
char* className;
char* methodName;
-
+
className = htmlEscape(method->className, classBuf, HTML_BUFSIZE);
methodName = htmlEscape(method->methodName, methodBuf, HTML_BUFSIZE);
-
- if (gOptions.outputHtml) printf("<tr><td>\n");
-
+
+ if (gOptions.outputHtml) printf("<tr><td>\n");
+
printf("%s.%s ", className, methodName);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%lld ", method->elapsedExclusive);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%lld ", method->elapsedInclusive);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%d\n", method->numCalls[0]);
if (gOptions.outputHtml) printf("</td><td>\n");
}
@@ -3342,8 +3342,8 @@
{
MethodEntry** methods1 = parseMethodEntries(d1);
MethodEntry** methods2 = parseMethodEntries(d2);
-
- // sort and assign the indicies
+
+ // sort and assign the indicies
int i;
qsort(methods1, d1->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
for (i = 0; i < d1->numMethods; ++i) {
@@ -3354,17 +3354,17 @@
for (i = 0; i < d2->numMethods; ++i) {
methods2[i]->index = i;
}
-
+
int max = (d1->numMethods < d2->numMethods) ? d2->numMethods : d1->numMethods;
max++;
DiffEntry* diffs = (DiffEntry*)malloc(max * sizeof(DiffEntry));
memset(diffs, 0, max * sizeof(DiffEntry));
DiffEntry* ptr = diffs;
-
+
// printf("<br>d1->numMethods: %d d1->numMethods: %d<br>\n", d1->numMethods, d2->numMethods);
-
+
int matches = 0;
-
+
for (i = 0 ; i < d1->numMethods ; i++) {
int match = findMatch(methods2, d2->numMethods, methods1[i]);
if (match >= 0) {
@@ -3384,13 +3384,13 @@
ptr->differenceInclusive = i2 - i1;
ptr->differenceInclusivePercentage = ((double)i2 / (double)i1) * 100.0;
}
-
+
// clear these out so we don't find them again and we know which ones
// we have left over
methods1[i] = NULL;
methods2[match] = NULL;
ptr++;
-
+
matches++;
}
}
@@ -3399,7 +3399,7 @@
qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesExculsive);
ptr = diffs;
-
+
if (gOptions.outputHtml) {
printf(htmlHeader, gOptions.sortableUrl);
printf("<h3>Table of Contents</h3>\n");
@@ -3412,12 +3412,12 @@
printf("<a name=\"exclusive\"></a><h3 id=\"exclusive\">Exclusive</h3>\n");
printf(tableHeader, "exclusive_table");
}
-
+
char classBuf[HTML_BUFSIZE];
char methodBuf[HTML_BUFSIZE];
char* className;
char* methodName;
-
+
while (ptr->method1 != NULL && ptr->method2 != NULL) {
if (gOptions.outputHtml) printf("<tr><td>\n");
@@ -3426,16 +3426,16 @@
printf("%s.%s ", className, methodName);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%lld ", ptr->method1->elapsedExclusive);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%llu ", ptr->method2->elapsedExclusive);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%lld ", ptr->differenceExclusive);
if (gOptions.outputHtml) printf("</td><td>");
-
+
printf("%.2f\n", ptr->differenceExclusivePercentage);
if (gOptions.outputHtml) printf("</td><td>\n");
@@ -3444,12 +3444,12 @@
printf("%d\n", ptr->method2->numCalls[0]);
if (gOptions.outputHtml) printf("</td></tr>\n");
-
+
ptr++;
}
-
+
if (gOptions.outputHtml) printf("</table>\n");
-
+
if (gOptions.outputHtml) {
printf(htmlHeader, gOptions.sortableUrl);
printf("Run 1: %s<br>\n", gOptions.diffFileName);
@@ -3457,10 +3457,10 @@
printf("<a name=\"inclusive\"></a><h3 id=\"inculisve\">Inclusive</h3>\n");
printf(tableHeader, "inclusive_table");
}
-
+
qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesInculsive);
ptr = diffs;
-
+
while (ptr->method1 != NULL && ptr->method2 != NULL) {
if (gOptions.outputHtml) printf("<tr><td>\n");
@@ -3496,25 +3496,25 @@
printf("<h3>Run 1 methods not found in Run 2</h3>");
printf(tableHeaderMissing);
}
-
+
for (i = 0; i < d1->numMethods; ++i) {
if (methods1[i] != NULL) {
printMissingMethod(methods1[i]);
}
}
-
+
if (gOptions.outputHtml) {
printf("</table>\n");
printf("<h3>Run 2 methods not found in Run 1</h3>");
printf(tableHeaderMissing);
}
-
+
for (i = 0; i < d2->numMethods; ++i) {
if (methods2[i] != NULL) {
printMissingMethod(methods2[i]);
}
}
-
+
if (gOptions.outputHtml) printf("</body></html\n");
}
@@ -3613,9 +3613,9 @@
uint64_t sum2;
TraceData data2;
DataKeys* d2 = parseDataKeys(&data2, gOptions.diffFileName, &sum2, filters);
-
+
createDiff(d2, sum2, dataKeys, sumThreadTime);
-
+
freeDataKeys(d2);
} else {
MethodEntry** methods = parseMethodEntries(dataKeys);
@@ -3626,7 +3626,7 @@
}
free(methods);
}
-
+
freeDataKeys(dataKeys);
return 0;
diff --git a/tools/dmtracedump/dmtracedump.pl b/tools/dmtracedump/dmtracedump.pl
index fbd00ac..6e487c6 100755
--- a/tools/dmtracedump/dmtracedump.pl
+++ b/tools/dmtracedump/dmtracedump.pl
@@ -12,9 +12,7 @@
print("dmtracedump -h -p $input > $output\n");
system("dmtracedump -h -p '$input' > '$output'");
-
+
}
closedir DIR;
-
-
diff --git a/tools/dmtracedump/dumpdir.sh b/tools/dmtracedump/dumpdir.sh
index 34937d7..81992a2 100644
--- a/tools/dmtracedump/dumpdir.sh
+++ b/tools/dmtracedump/dumpdir.sh
@@ -9,4 +9,3 @@
G=$2/`echo $F | sed "s/.*\\///g"`.html
dmtracedump -h -p $F > $G
done
-
diff --git a/tools/gclog.py b/tools/gclog.py
index 4d5b704..d008f6a 100755
--- a/tools/gclog.py
+++ b/tools/gclog.py
@@ -232,4 +232,3 @@
start()
-
diff --git a/tools/gdbjithelper/README.txt b/tools/gdbjithelper/README.txt
index 032b244..aab1a00 100644
--- a/tools/gdbjithelper/README.txt
+++ b/tools/gdbjithelper/README.txt
@@ -26,7 +26,7 @@
Step 2
-
+
Push $OUT/EXECUTABLES/gdbjithelper_intermediates/LINKED/gdbjithelper to
/system/bin on the device or emulator
@@ -63,4 +63,3 @@
Issue the following command to see code around LR
x /20i (char *) &codeLR+1
-
diff --git a/tools/gdbjithelper/gdbjithelper.c b/tools/gdbjithelper/gdbjithelper.c
index 862fcae..817d5a4 100644
--- a/tools/gdbjithelper/gdbjithelper.c
+++ b/tools/gdbjithelper/gdbjithelper.c
@@ -40,7 +40,7 @@
* 463ba204 4191debc 01010000 4284aa74 68b00054
* 463ba214 045cf205 cc016468 0718f2a5 d0102800
* 463ba224 4c13c701 a20aa108 efb0f775 e008e010
- *
+ *
* code around lr:
* 463ba1a8 42e19e58 f2050050 cc01045c 0718f2a5
* 463ba1b8 d00f2800 4c13c701 a20aa108 efe4f775
diff --git a/tools/hprof-conv/Android.mk b/tools/hprof-conv/Android.mk
index fbac5fa..3d39d7b 100644
--- a/tools/hprof-conv/Android.mk
+++ b/tools/hprof-conv/Android.mk
@@ -18,4 +18,3 @@
LOCAL_SRC_FILES := HprofConv.c
LOCAL_MODULE := hprof-conv
include $(BUILD_HOST_EXECUTABLE)
-
diff --git a/tools/hprof-conv/HprofConv.c b/tools/hprof-conv/HprofConv.c
index 10f3d2c..02cb7f4 100644
--- a/tools/hprof-conv/HprofConv.c
+++ b/tools/hprof-conv/HprofConv.c
@@ -80,7 +80,7 @@
HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,
HPROF_ROOT_VM_INTERNAL = 0x8d,
HPROF_ROOT_JNI_MONITOR = 0x8e,
- HPROF_UNREACHABLE = 0x90,
+ HPROF_UNREACHABLE = 0x90, /* deprecated */
HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
} HprofHeapTag;
@@ -716,4 +716,3 @@
fclose(out);
return (cc != 0);
}
-
diff --git a/vm/AllocTracker.c b/vm/AllocTracker.c
index 9fb1c4d..168713c 100644
--- a/vm/AllocTracker.c
+++ b/vm/AllocTracker.c
@@ -609,7 +609,7 @@
*/
int idx = headIndex();
int count = gDvm.allocRecordCount;
-
+
LOGI("Tracked allocations, (head=%d count=%d)\n",
gDvm.allocRecordHead, count);
while (count--) {
@@ -651,4 +651,3 @@
free(data);
}
}
-
diff --git a/vm/Android.mk b/vm/Android.mk
index 238d2ed..be71d3c 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -32,9 +32,12 @@
# Build for the target (device).
#
-ifeq ($(TARGET_ARCH_VARIANT),armv5te)
- WITH_JIT := false
+ifeq ($(TARGET_CPU_SMP),true)
+ target_smp_flag := -DANDROID_SMP=1
+else
+ target_smp_flag := -DANDROID_SMP=0
endif
+host_smp_flag := -DANDROID_SMP=1
# Build the installed version (libdvm.so) first
include $(LOCAL_PATH)/ReconfigureDvm.mk
@@ -47,6 +50,7 @@
endif
LOCAL_MODULE_TAGS := user
LOCAL_MODULE := libdvm
+LOCAL_CFLAGS += $(target_smp_flag)
include $(BUILD_SHARED_LIBRARY)
# If WITH_JIT is configured, build multiple versions of libdvm.so to facilitate
@@ -59,7 +63,7 @@
# Enable assertions and JIT-tuning
LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \
- -DWITH_JIT_TUNING -DJIT_STATS
+ -DWITH_JIT_TUNING $(target_smp_flag)
LOCAL_MODULE := libdvm_assert
include $(BUILD_SHARED_LIBRARY)
@@ -69,7 +73,7 @@
# Enable assertions and JIT self-verification
LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \
- -DWITH_SELF_VERIFICATION
+ -DWITH_SELF_VERIFICATION $(target_smp_flag)
LOCAL_MODULE := libdvm_sv
include $(BUILD_SHARED_LIBRARY)
@@ -78,6 +82,7 @@
WITH_JIT := false
include $(LOCAL_PATH)/ReconfigureDvm.mk
+ LOCAL_CFLAGS += $(target_smp_flag)
LOCAL_MODULE := libdvm_interp
include $(BUILD_SHARED_LIBRARY)
@@ -94,7 +99,8 @@
# Variables used in the included Dvm.mk.
dvm_os := $(HOST_OS)
dvm_arch := $(HOST_ARCH)
- dvm_arch_variant := $(HOST_ARCH_VARIANT)
+ # Note: HOST_ARCH_VARIANT isn't defined.
+ dvm_arch_variant := $(HOST_ARCH)
dvm_simulator := false
include $(LOCAL_PATH)/Dvm.mk
@@ -119,6 +125,7 @@
$(patsubst libffi, ,$(LOCAL_SHARED_LIBRARIES))
endif
+ LOCAL_CFLAGS += $(host_smp_flag)
LOCAL_MODULE := libdvm-host
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/vm/Atomic.c b/vm/Atomic.c
new file mode 100644
index 0000000..4473c85
--- /dev/null
+++ b/vm/Atomic.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+
+#include <cutils/atomic.h>
+
+/*
+ * Quasi-atomic 64-bit operations, for platforms that lack the real thing.
+ *
+ * TODO: unify ARMv6/x86/sh implementations using the to-be-written
+ * spin lock implementation. We don't want to rely on mutex innards,
+ * and it would be great if all platforms were running the same code.
+ */
+
+#if defined(HAVE_MACOSX_IPC)
+
+#include <libkern/OSAtomic.h>
+
+#if defined(__ppc__) \
+ || defined(__PPC__) \
+ || defined(__powerpc__) \
+ || defined(__powerpc) \
+ || defined(__POWERPC__) \
+ || defined(_M_PPC) \
+ || defined(__PPC)
+#define NEED_QUASIATOMICS 1
+#else
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+ volatile int64_t* addr)
+{
+ return OSAtomicCompareAndSwap64Barrier(oldvalue, newvalue,
+ (int64_t*)addr) == 0;
+}
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+ int64_t oldValue;
+ do {
+ oldValue = *addr;
+ } while (dvmQuasiAtomicCas64(oldValue, value, addr));
+ return oldValue;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+ return OSAtomicAdd64Barrier(0, addr);
+}
+#endif
+
+#elif defined(__i386__) || defined(__x86_64__)
+#define NEED_QUASIATOMICS 1
+
+#elif __arm__
+#include <machine/cpu-features.h>
+
+#ifdef __ARM_HAVE_LDREXD
+int64_t dvmQuasiAtomicSwap64(int64_t newvalue, volatile int64_t* addr)
+{
+ int64_t prev;
+ int status;
+ do {
+ __asm__ __volatile__ ("@ dvmQuasiAtomicSwap64\n"
+ "ldrexd %0, %H0, [%3]\n"
+ "strexd %1, %4, %H4, [%3]"
+ : "=&r" (prev), "=&r" (status), "+m"(*addr)
+ : "r" (addr), "r" (newvalue)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+ volatile int64_t* addr)
+{
+ int64_t prev;
+ int status;
+ do {
+ __asm__ __volatile__ ("@ dvmQuasiAtomicCas64\n"
+ "ldrexd %0, %H0, [%3]\n"
+ "mov %1, #0\n"
+ "teq %0, %4\n"
+ "teqeq %H0, %H4\n"
+ "strexdeq %1, %5, %H5, [%3]"
+ : "=&r" (prev), "=&r" (status), "+m"(*addr)
+ : "r" (addr), "Ir" (oldvalue), "r" (newvalue)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev != oldvalue;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+ int64_t value;
+ __asm__ __volatile__ ("@ dvmQuasiAtomicRead64\n"
+ "ldrexd %0, %H0, [%1]"
+ : "=&r" (value)
+ : "r" (addr));
+ return value;
+}
+
+#else
+
+// on the device, we implement the 64-bit atomic operations through
+// mutex locking. normally, this is bad because we must initialize
+// a pthread_mutex_t before being able to use it, and this means
+// having to do an initialization check on each function call, and
+// that's where really ugly things begin...
+//
+// BUT, as a special twist, we take advantage of the fact that in our
+// pthread library, a mutex is simply a volatile word whose value is always
+// initialized to 0. In other words, simply declaring a static mutex
+// object initializes it !
+//
+// another twist is that we use a small array of mutexes to dispatch
+// the contention locks from different memory addresses
+//
+
+#include <pthread.h>
+
+#define SWAP_LOCK_COUNT 32U
+static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT];
+
+#define SWAP_LOCK(addr) \
+ &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
+
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+ int64_t oldValue;
+ pthread_mutex_t* lock = SWAP_LOCK(addr);
+
+ pthread_mutex_lock(lock);
+
+ oldValue = *addr;
+ *addr = value;
+
+ pthread_mutex_unlock(lock);
+ return oldValue;
+}
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+ volatile int64_t* addr)
+{
+ int result;
+ pthread_mutex_t* lock = SWAP_LOCK(addr);
+
+ pthread_mutex_lock(lock);
+
+ if (*addr == oldvalue) {
+ *addr = newvalue;
+ result = 0;
+ } else {
+ result = 1;
+ }
+ pthread_mutex_unlock(lock);
+ return result;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+ int64_t result;
+ pthread_mutex_t* lock = SWAP_LOCK(addr);
+
+ pthread_mutex_lock(lock);
+ result = *addr;
+ pthread_mutex_unlock(lock);
+ return result;
+}
+
+#endif /*__ARM_HAVE_LDREXD*/
+
+/*****************************************************************************/
+#elif __sh__
+#define NEED_QUASIATOMICS 1
+
+#else
+#error "Unsupported atomic operations for this platform"
+#endif
+
+
+#if NEED_QUASIATOMICS
+
+/* Note that a spinlock is *not* a good idea in general
+ * since they can introduce subtle issues. For example,
+ * a real-time thread trying to acquire a spinlock already
+ * acquired by another thread will never yeld, making the
+ * CPU loop endlessly!
+ *
+ * However, this code is only used on the Linux simulator
+ * so it's probably ok for us.
+ *
+ * The alternative is to use a pthread mutex, but
+ * these must be initialized before being used, and
+ * then you have the problem of lazily initializing
+ * a mutex without any other synchronization primitive.
+ *
+ * TODO: these currently use sched_yield(), which is not guaranteed to
+ * do anything at all. We need to use dvmIterativeSleep or a wait /
+ * notify mechanism if the initial attempt fails.
+ */
+
+/* global spinlock for all 64-bit quasiatomic operations */
+static int32_t quasiatomic_spinlock = 0;
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+ volatile int64_t* addr)
+{
+ int result;
+
+ while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
+#ifdef HAVE_WIN32_THREADS
+ Sleep(0);
+#else
+ sched_yield();
+#endif
+ }
+
+ if (*addr == oldvalue) {
+ *addr = newvalue;
+ result = 0;
+ } else {
+ result = 1;
+ }
+
+ android_atomic_release_store(0, &quasiatomic_spinlock);
+
+ return result;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+ int64_t result;
+
+ while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
+#ifdef HAVE_WIN32_THREADS
+ Sleep(0);
+#else
+ sched_yield();
+#endif
+ }
+
+ result = *addr;
+ android_atomic_release_store(0, &quasiatomic_spinlock);
+
+ return result;
+}
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+ int64_t result;
+
+ while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
+#ifdef HAVE_WIN32_THREADS
+ Sleep(0);
+#else
+ sched_yield();
+#endif
+ }
+
+ result = *addr;
+ *addr = value;
+ android_atomic_release_store(0, &quasiatomic_spinlock);
+
+ return result;
+}
+
+#endif /*NEED_QUASIATOMICS*/
diff --git a/vm/Atomic.h b/vm/Atomic.h
index bc0203c..6c3a66f 100644
--- a/vm/Atomic.h
+++ b/vm/Atomic.h
@@ -13,36 +13,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Atomic operations
*/
#ifndef _DALVIK_ATOMIC
#define _DALVIK_ATOMIC
-#include <utils/Atomic.h> /* use common Android atomic ops */
+#include <cutils/atomic.h> /* use common Android atomic ops */
+#include <cutils/atomic-inline.h> /* and some uncommon ones */
/*
- * Memory barrier. Guarantee that register-resident variables
- * are flushed to memory, and guarantee that instructions before
- * the barrier do not get reordered to appear past it.
+ * NOTE: Two "quasiatomic" operations on the exact same memory address
+ * are guaranteed to operate atomically with respect to each other,
+ * but no guarantees are made about quasiatomic operations mixed with
+ * non-quasiatomic operations on the same address, nor about
+ * quasiatomic operations that are performed on partially-overlapping
+ * memory.
*
- * 'asm volatile ("":::"memory")' is probably overkill, but it's correct.
- * There may be a way to do it that doesn't flush every single register.
- *
- * TODO: look into the wmb() family on Linux and equivalents on other systems.
+ * None of these provide a memory barrier.
*/
-#define MEM_BARRIER() do { asm volatile ("":::"memory"); } while (0)
/*
- * Atomic compare-and-swap macro.
- *
- * If *_addr equals "_old", replace it with "_new" and return 1. Otherwise
- * return 0. (e.g. x86 "cmpxchgl" instruction.)
- *
- * Underlying function is currently declared:
- * int android_atomic_cmpxchg(int32_t old, int32_t new, volatile int32_t* addr)
+ * Swap the 64-bit value at "addr" with "value". Returns the previous
+ * value.
*/
-#define ATOMIC_CMP_SWAP(_addr, _old, _new) \
- (android_atomic_cmpxchg((_old), (_new), (_addr)) == 0)
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr);
+
+/*
+ * Read the 64-bit value at "addr".
+ */
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr);
+
+/*
+ * If the value at "addr" is equal to "oldvalue", replace it with "newvalue"
+ * and return 0. Otherwise, don't swap, and return nonzero.
+ */
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+ volatile int64_t* addr);
#endif /*_DALVIK_ATOMIC*/
diff --git a/vm/AtomicCache.c b/vm/AtomicCache.c
index cee84a8..bf8639e 100644
--- a/vm/AtomicCache.c
+++ b/vm/AtomicCache.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Mutex-free cache. Each entry has two 32-bit keys, one 32-bit value,
* and a 32-bit version.
@@ -75,7 +76,6 @@
}
-
/*
* Update a cache entry.
*
@@ -91,22 +91,24 @@
)
{
/*
- * The fields don't match, so we need to update them. There is a
- * risk that another thread is also trying to update them, so we
- * grab an ownership flag to lock out other threads.
+ * The fields don't match, so we want to update them. There is a risk
+ * that another thread is also trying to update them, so we grab an
+ * ownership flag to lock out other threads.
*
* If the lock flag was already set in "firstVersion", somebody else
- * was in mid-update. (This means that using "firstVersion" as the
- * "before" argument to the CAS would succeed when it shouldn't and
- * vice-versa -- we could also just pass in
- * (firstVersion & ~ATOMIC_LOCK_FLAG) as the first argument.)
+ * was in mid-update, and we don't want to continue here. (This means
+ * that using "firstVersion" as the "before" argument to the CAS would
+ * succeed when it shouldn't and vice-versa -- we could also just pass
+ * in (firstVersion & ~ATOMIC_LOCK_FLAG) as the first argument.)
*
- * NOTE: we don't really deal with the situation where we overflow
- * the version counter (at 2^31). Probably not a real concern.
+ * NOTE: we don't deal with the situation where we overflow the version
+ * counter and trample the ATOMIC_LOCK_FLAG (at 2^31). Probably not
+ * a real concern.
*/
if ((firstVersion & ATOMIC_LOCK_FLAG) != 0 ||
- !ATOMIC_CMP_SWAP((volatile s4*) &pEntry->version,
- firstVersion, firstVersion | ATOMIC_LOCK_FLAG))
+ android_atomic_release_cas(
+ firstVersion, firstVersion | ATOMIC_LOCK_FLAG,
+ (volatile s4*) &pEntry->version) != 0)
{
/*
* We couldn't get the write lock. Return without updating the table.
@@ -128,25 +130,30 @@
pCache->misses++;
#endif
- /* volatile incr */
+ /*
+ * We have the write lock, but somebody could be reading this entry
+ * while we work. We use memory barriers to ensure that the state
+ * is always consistent when the version number is even.
+ */
pEntry->version++;
- MEM_BARRIER();
+ ANDROID_MEMBAR_FULL();
pEntry->key1 = key1;
pEntry->key2 = key2;
pEntry->value = value;
- /* volatile incr */
+ ANDROID_MEMBAR_FULL();
pEntry->version++;
- MEM_BARRIER();
/*
* Clear the lock flag. Nobody else should have been able to modify
* pEntry->version, so if this fails the world is broken.
*/
firstVersion += 2;
- if (!ATOMIC_CMP_SWAP((volatile s4*) &pEntry->version,
- firstVersion | ATOMIC_LOCK_FLAG, firstVersion))
+ assert((firstVersion & 0x01) == 0);
+ if (android_atomic_release_cas(
+ firstVersion | ATOMIC_LOCK_FLAG, firstVersion,
+ (volatile s4*) &pEntry->version) != 0)
{
//LOGE("unable to reset the instanceof cache ownership\n");
dvmAbort();
@@ -170,4 +177,3 @@
(pCache->fail + pCache->hits + pCache->misses + pCache->fills),
pCache->numEntries);
}
-
diff --git a/vm/AtomicCache.h b/vm/AtomicCache.h
index 1d59a47..66d222e 100644
--- a/vm/AtomicCache.h
+++ b/vm/AtomicCache.h
@@ -63,17 +63,16 @@
* Do a cache lookup. We need to be able to read and write entries
* atomically. There are a couple of ways to do this:
* (1) Have a global lock. A mutex is too heavy, so instead we would use
- * an atomic flag. If the flag is set, we could sit and spin, but
- * if we're a high-priority thread that may cause a lockup. Better
- * to just ignore the cache and do the full computation.
+ * an atomic flag. If the flag is set, we could sit and spin,
+ * but if we're a high-priority thread that may cause a lockup.
+ * Better to just ignore the cache and do the full computation.
* (2) Have a "version" that gets incremented atomically when a write
* begins and again when it completes. Compare the version before
- * and after doing reads. So long as "version" is volatile the
- * compiler will do the right thing, allowing us to skip atomic
- * ops in the common read case. The table updates are expensive,
- * requiring two volatile writes and (for correctness on
- * multiprocessor systems) memory barriers. We also need some
- * sort of lock to ensure that nobody else tries to start an
+ * and after doing reads. So long as we have memory barriers in the
+ * right place the compiler and CPU will do the right thing, allowing
+ * us to skip atomic ops in the common read case. The table updates
+ * are expensive, requiring two writes with barriers. We also need
+ * some sort of lock to ensure that nobody else tries to start an
* update while we're in the middle of one.
*
* We expect a 95+% hit rate for the things we use this for, so #2 is
@@ -103,8 +102,8 @@
hash = (((u4)(_key1) >> 2) ^ (u4)(_key2)) & ((_cacheSize)-1); \
pEntry = (_cache)->entries + hash; \
\
- /* volatile read */ \
firstVersion = pEntry->version; \
+ ANDROID_MEMBAR_FULL(); \
\
if (pEntry->key1 == (u4)(_key1) && pEntry->key2 == (u4)(_key2)) { \
/* \
@@ -113,7 +112,8 @@
* We're also hosed if "firstVersion" was odd, indicating that \
* an update was in progress before we got here. \
*/ \
- value = pEntry->value; /* must grab before next check */ \
+ value = pEntry->value; \
+ ANDROID_MEMBAR_FULL(); \
\
if ((firstVersion & 0x01) != 0 || firstVersion != pEntry->version) \
{ \
diff --git a/vm/CheckJni.c b/vm/CheckJni.c
index ff0efd3..ae98c4c 100644
--- a/vm/CheckJni.c
+++ b/vm/CheckJni.c
@@ -251,13 +251,18 @@
checkNonNull(_env, _ptr, __FUNCTION__)
#define CHECK_SIG(_env, _methid, _sigbyte, _isstatic) \
checkSig(_env, _methid, _sigbyte, _isstatic, __FUNCTION__)
+#define CHECK_VIRTUAL_METHOD(_env, _obj, _methid) \
+ checkVirtualMethod(_env, _obj, _methid, __FUNCTION__)
+#define CHECK_STATIC_METHOD(_env, _clazz, _methid) \
+ checkStaticMethod(_env, _clazz, _methid, __FUNCTION__)
#define CHECK_METHOD_ARGS_A(_env, _methid, _args) \
checkMethodArgsA(_env, _methid, _args, __FUNCTION__)
#define CHECK_METHOD_ARGS_V(_env, _methid, _args) \
checkMethodArgsV(_env, _methid, _args, __FUNCTION__)
/*
- * Print trace message when both "checkJNI" and "verbose:jni" are enabled.
+ * Prints trace messages when a native method calls a JNI function such as
+ * NewByteArray. Enabled if both "-Xcheck:jni" and "-verbose:jni" are enabled.
*/
#define JNI_TRACE(_entry, _hasmeth) \
do { \
@@ -804,7 +809,7 @@
static void checkStaticFieldID(JNIEnv* env, jclass jclazz, jfieldID fieldID)
{
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
- StaticField* base = clazz->sfields;
+ StaticField* base = &clazz->sfields[0];
int fieldCount = clazz->sfieldCount;
if ((StaticField*) fieldID < base ||
@@ -857,6 +862,56 @@
}
/*
+ * Verify that "methodID" is appropriate for "jobj".
+ *
+ * Make sure the object is an instance of the method's declaring class.
+ * (Note the methodID might point to a declaration in an interface; this
+ * will be handled automatically by the instanceof check.)
+ */
+static void checkVirtualMethod(JNIEnv* env, jobject jobj, jmethodID methodID,
+ const char* func)
+{
+ JNI_ENTER();
+
+ Object* obj = dvmDecodeIndirectRef(env, jobj);
+ const Method* meth = (const Method*) methodID;
+
+ if (!dvmInstanceof(obj->clazz, meth->clazz)) {
+ LOGW("JNI WARNING: can't call %s.%s on instance of %s\n",
+ meth->clazz->descriptor, meth->name, obj->clazz->descriptor);
+ abortMaybe();
+ }
+
+ JNI_EXIT();
+}
+
+/*
+ * Verify that "methodID" is appropriate for "clazz".
+ *
+ * A mismatch isn't dangerous, because the method defines the class. In
+ * fact, jclazz is unused in the implementation. It's best if we don't
+ * allow bad code in the system though.
+ *
+ * Instances of "jclazz" must be instances of the method's declaring class.
+ */
+static void checkStaticMethod(JNIEnv* env, jclass jclazz, jmethodID methodID,
+ const char* func)
+{
+ JNI_ENTER();
+
+ ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
+ const Method* meth = (const Method*) methodID;
+
+ if (!dvmInstanceof(clazz, meth->clazz)) {
+ LOGW("JNI WARNING: can't call static %s.%s on class %s\n",
+ meth->clazz->descriptor, meth->name, clazz->descriptor);
+ // no abort
+ }
+
+ JNI_EXIT();
+}
+
+/*
* Verify that the reference arguments being passed in are appropriate for
* this method.
*
@@ -878,7 +933,6 @@
const Method* meth = (const Method*) methodID;
const char* desc = meth->shorty;
- ClassObject* clazz;
LOGV("V-checking %s.%s:%s...\n", meth->clazz->descriptor, meth->name, desc);
@@ -901,7 +955,6 @@
}
}
-bail:
JNI_EXIT();
#endif
}
@@ -918,7 +971,6 @@
const Method* meth = (const Method*) methodID;
const char* desc = meth->shorty;
- ClassObject* clazz;
int idx = 0;
LOGV("A-checking %s.%s:%s...\n", meth->clazz->descriptor, meth->name, desc);
@@ -932,7 +984,6 @@
idx++;
}
-bail:
JNI_EXIT();
#endif
}
@@ -1174,8 +1225,6 @@
int mode)
{
ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
- PrimitiveType primType = arrObj->obj.clazz->elementClass->primitiveType;
- //int len = array->length * dvmPrimitiveTypeWidth(primType);
bool release, copyBack;
u1* result;
@@ -1702,6 +1751,7 @@
CHECK_ENTER(env, kFlag_Default); \
CHECK_OBJECT(env, obj); \
CHECK_SIG(env, methodID, _retsig, false); \
+ CHECK_VIRTUAL_METHOD(env, obj, methodID); \
_retdecl; \
va_list args, tmpArgs; \
va_start(args, methodID); \
@@ -1720,6 +1770,7 @@
CHECK_ENTER(env, kFlag_Default); \
CHECK_OBJECT(env, obj); \
CHECK_SIG(env, methodID, _retsig, false); \
+ CHECK_VIRTUAL_METHOD(env, obj, methodID); \
_retdecl; \
va_list tmpArgs; \
va_copy(tmpArgs, args); \
@@ -1736,6 +1787,7 @@
CHECK_ENTER(env, kFlag_Default); \
CHECK_OBJECT(env, obj); \
CHECK_SIG(env, methodID, _retsig, false); \
+ CHECK_VIRTUAL_METHOD(env, obj, methodID); \
_retdecl; \
CHECK_METHOD_ARGS_A(env, methodID, args); \
_retasgn BASE_ENV(env)->Call##_jname##MethodA(env, obj, methodID, \
@@ -1763,6 +1815,7 @@
CHECK_CLASS(env, clazz); \
CHECK_OBJECT(env, obj); \
CHECK_SIG(env, methodID, _retsig, false); \
+ CHECK_VIRTUAL_METHOD(env, obj, methodID); \
_retdecl; \
va_list args, tmpArgs; \
va_start(args, methodID); \
@@ -1782,6 +1835,7 @@
CHECK_CLASS(env, clazz); \
CHECK_OBJECT(env, obj); \
CHECK_SIG(env, methodID, _retsig, false); \
+ CHECK_VIRTUAL_METHOD(env, obj, methodID); \
_retdecl; \
va_list tmpArgs; \
va_copy(tmpArgs, args); \
@@ -1799,6 +1853,7 @@
CHECK_CLASS(env, clazz); \
CHECK_OBJECT(env, obj); \
CHECK_SIG(env, methodID, _retsig, false); \
+ CHECK_VIRTUAL_METHOD(env, obj, methodID); \
_retdecl; \
CHECK_METHOD_ARGS_A(env, methodID, args); \
_retasgn BASE_ENV(env)->CallNonvirtual##_jname##MethodA(env, obj, \
@@ -1825,6 +1880,7 @@
CHECK_ENTER(env, kFlag_Default); \
CHECK_CLASS(env, clazz); \
CHECK_SIG(env, methodID, _retsig, true); \
+ CHECK_STATIC_METHOD(env, clazz, methodID); \
_retdecl; \
va_list args, tmpArgs; \
va_start(args, methodID); \
@@ -1843,6 +1899,7 @@
CHECK_ENTER(env, kFlag_Default); \
CHECK_CLASS(env, clazz); \
CHECK_SIG(env, methodID, _retsig, true); \
+ CHECK_STATIC_METHOD(env, clazz, methodID); \
_retdecl; \
va_list tmpArgs; \
va_copy(tmpArgs, args); \
@@ -1859,6 +1916,7 @@
CHECK_ENTER(env, kFlag_Default); \
CHECK_CLASS(env, clazz); \
CHECK_SIG(env, methodID, _retsig, true); \
+ CHECK_STATIC_METHOD(env, clazz, methodID); \
_retdecl; \
CHECK_METHOD_ARGS_A(env, methodID, args); \
_retasgn BASE_ENV(env)->CallStatic##_jname##MethodA(env, clazz, \
diff --git a/vm/Common.h b/vm/Common.h
index d0c021d..ae0938a 100644
--- a/vm/Common.h
+++ b/vm/Common.h
@@ -34,6 +34,11 @@
__FILE__, __LINE__, #x), *(int*)39=39, 0) )
#endif
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+#define LIKELY(exp) (__builtin_expect((exp) != 0, true))
+#define UNLIKELY(exp) (__builtin_expect((exp) != 0, false))
/*
* If "very verbose" logging is enabled, make it equivalent to LOGV.
diff --git a/vm/Dalvik.h b/vm/Dalvik.h
index 054b838..6418bf2 100644
--- a/vm/Dalvik.h
+++ b/vm/Dalvik.h
@@ -55,9 +55,11 @@
#include "oo/Array.h"
#include "Exception.h"
#include "alloc/Alloc.h"
+#include "alloc/CardTable.h"
#include "alloc/HeapDebug.h"
#include "alloc/HeapWorker.h"
#include "alloc/GC.h"
+#include "alloc/WriteBarrier.h"
#include "oo/AccessCheck.h"
#include "JarFile.h"
#include "Properties.h"
@@ -67,7 +69,7 @@
#include "JniInternal.h"
#include "LinearAlloc.h"
#include "analysis/DexVerify.h"
-#include "analysis/DexOptimize.h"
+#include "analysis/DexPrepare.h"
#include "analysis/RegisterMap.h"
#include "Init.h"
#include "libdex/OpCode.h"
@@ -83,5 +85,6 @@
#include "Atomic.h"
#include "interp/Interp.h"
#include "InlineNative.h"
+#include "oo/ObjectInlines.h"
#endif /*_DALVIK_DALVIK*/
diff --git a/vm/DalvikVersion.h b/vm/DalvikVersion.h
index 2e00ac4..3bc37b0 100644
--- a/vm/DalvikVersion.h
+++ b/vm/DalvikVersion.h
@@ -24,7 +24,7 @@
* The version we show to tourists.
*/
#define DALVIK_MAJOR_VERSION 1
-#define DALVIK_MINOR_VERSION 2
+#define DALVIK_MINOR_VERSION 4
#define DALVIK_BUG_VERSION 0
/*
@@ -32,6 +32,6 @@
* way classes load changes, e.g. field ordering or vtable layout. Changing
* this guarantees that the optimized form of the DEX file is regenerated.
*/
-#define DALVIK_VM_BUILD 19
+#define DALVIK_VM_BUILD 23
#endif /*_DALVIK_VERSION*/
diff --git a/vm/Ddm.c b/vm/Ddm.c
index 76cbe82..1aaebe0 100644
--- a/vm/Ddm.c
+++ b/vm/Ddm.c
@@ -411,7 +411,8 @@
int cc;
cc = read(fd, lineBuf, sizeof(lineBuf)-1);
if (cc <= 0) {
- LOGI("Unable to read '%s': got %d (errno=%d)\n", nameBuf, cc, errno);
+ const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
+ LOGI("Unable to read '%s': %s\n", nameBuf, msg);
close(fd);
return false;
}
@@ -458,8 +459,8 @@
* (4b) threadId
* (1b) thread status
* (4b) tid
- * (4b) utime
- * (4b) stime
+ * (4b) utime
+ * (4b) stime
* (1b) is daemon?
*
* The length fields exist in anticipation of adding additional fields
@@ -595,4 +596,3 @@
memcpy(arrayObj->contents, data, len);
return arrayObj;
}
-
diff --git a/vm/Debugger.c b/vm/Debugger.c
index 2f57046..9402911 100644
--- a/vm/Debugger.c
+++ b/vm/Debugger.c
@@ -137,17 +137,17 @@
}
void dvmDbgCondWait(pthread_cond_t* pCond, pthread_mutex_t* pMutex)
{
- int cc = pthread_cond_wait(pCond, pMutex);
+ int cc __attribute__ ((__unused__)) = pthread_cond_wait(pCond, pMutex);
assert(cc == 0);
}
void dvmDbgCondSignal(pthread_cond_t* pCond)
{
- int cc = pthread_cond_signal(pCond);
+ int cc __attribute__ ((__unused__)) = pthread_cond_signal(pCond);
assert(cc == 0);
}
void dvmDbgCondBroadcast(pthread_cond_t* pCond)
{
- int cc = pthread_cond_broadcast(pCond);
+ int cc __attribute__ ((__unused__)) = pthread_cond_broadcast(pCond);
assert(cc == 0);
}
@@ -183,6 +183,7 @@
*
* Lock the registry before calling here.
*/
+#ifndef NDEBUG
static bool lookupId(ObjectId id)
{
void* found;
@@ -194,6 +195,7 @@
assert(found == (void*)(u4) id);
return true;
}
+#endif
/*
* Register an object, if it hasn't already been.
@@ -271,6 +273,7 @@
*
* Note this actually takes both ObjectId and RefTypeId.
*/
+#ifndef NDEBUG
static bool objectIsRegistered(ObjectId id, RegistryType type)
{
UNUSED_PARAMETER(type);
@@ -283,6 +286,7 @@
dvmHashTableUnlock(gDvm.dbgRegistry);
return result;
}
+#endif
/*
* Convert to/from a RefTypeId.
@@ -293,10 +297,12 @@
{
return (RefTypeId) registerObject((Object*) clazz, kRefTypeId, true);
}
+#if 0
static RefTypeId classObjectToRefTypeIdNoReg(ClassObject* clazz)
{
return (RefTypeId) registerObject((Object*) clazz, kRefTypeId, false);
}
+#endif
static ClassObject* refTypeIdToClassObject(RefTypeId id)
{
assert(objectIsRegistered(id, kRefTypeId) || !gDvm.debuggerConnected);
@@ -815,7 +821,7 @@
if (strcmp(type, "Ljava/lang/String;") == 0)
return JT_STRING;
else if (strcmp(type, "Ljava/lang/Class;") == 0)
- return JT_CLASS_OBJECT;
+ return JT_CLASS_OBJECT;
else if (strcmp(type, "Ljava/lang/Thread;") == 0)
return JT_THREAD;
else if (strcmp(type, "Ljava/lang/ThreadGroup;") == 0)
@@ -1144,7 +1150,7 @@
{
StringObject* strObj;
- strObj = dvmCreateStringFromCstr(str, ALLOC_DEFAULT);
+ strObj = dvmCreateStringFromCstr(str);
dvmReleaseTrackedAlloc((Object*) strObj, NULL);
return objectToObjectId((Object*) strObj);
}
@@ -1163,6 +1169,20 @@
}
/*
+ * Allocate a new array object of the specified type and length. The
+ * type is the array type, not the element type.
+ *
+ * Add it to the registry to prevent it from being GCed.
+ */
+ObjectId dvmDbgCreateArrayObject(RefTypeId arrayTypeId, u4 length)
+{
+ ClassObject* clazz = refTypeIdToClassObject(arrayTypeId);
+ Object* newObj = (Object*) dvmAllocArrayByClass(clazz, length, ALLOC_DEFAULT);
+ dvmReleaseTrackedAlloc(newObj, NULL);
+ return objectToObjectId(newObj);
+}
+
+/*
* Determine if "instClassId" is an instance of "classId".
*/
bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId)
@@ -1249,7 +1269,7 @@
int i;
dexStringCacheInit(&stringCache);
-
+
clazz = refTypeIdToClassObject(refTypeId);
assert(clazz != NULL);
@@ -1319,7 +1339,7 @@
bool withGeneric;
} DebugCallbackContext;
-static int lineTablePositionsCb(void *cnxt, u4 address, u4 lineNum)
+static int lineTablePositionsCb(void *cnxt, u4 address, u4 lineNum)
{
DebugCallbackContext *pContext = (DebugCallbackContext *)cnxt;
@@ -1340,7 +1360,6 @@
{
Method* method;
u8 start, end;
- int i;
DebugCallbackContext context;
memset (&context, 0, sizeof(DebugCallbackContext));
@@ -1449,7 +1468,7 @@
DebugCallbackContext context;
memset (&context, 0, sizeof(DebugCallbackContext));
-
+
method = methodIdToMethod(refTypeId, methodId);
expandBufAdd4BE(pReply, method->insSize);
@@ -1659,7 +1678,7 @@
StaticField* sfield = (StaticField*) fieldIdToField(refTypeId, fieldId);
Object* objVal;
JValue value;
-
+
value.j = rawValue;
switch (sfield->field.signature[0]) {
@@ -1756,7 +1775,7 @@
Object* threadObj;
Thread* thread;
bool result = false;
-
+
threadObj = objectIdToObject(threadId);
assert(threadObj != NULL);
@@ -1803,7 +1822,7 @@
Object* threadObj;
Thread* thread;
u4 result = 0;
-
+
threadObj = objectIdToObject(threadId);
assert(threadObj != NULL);
@@ -1831,7 +1850,7 @@
Object* threadObj;
Thread* thread;
bool result;
-
+
threadObj = objectIdToObject(threadId);
assert(threadObj != NULL);
@@ -1858,7 +1877,7 @@
Object* threadObj;
Thread* thread;
bool result = false;
-
+
threadObj = objectIdToObject(threadId);
assert(threadObj != NULL);
@@ -1888,7 +1907,7 @@
{
Object* threadObj;
Thread* thread;
-
+
threadObj = objectIdToObject(threadId);
assert(threadObj != NULL);
diff --git a/vm/Debugger.h b/vm/Debugger.h
index 04477fb..d722160 100644
--- a/vm/Debugger.h
+++ b/vm/Debugger.h
@@ -191,6 +191,7 @@
ObjectId dvmDbgCreateString(const char* str);
ObjectId dvmDbgCreateObject(RefTypeId classId);
+ObjectId dvmDbgCreateArrayObject(RefTypeId arrayTypeId, u4 length);
bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId);
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index baf41c6..c624258 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -26,6 +26,7 @@
#
LOCAL_CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2 -fno-align-jumps
#LOCAL_CFLAGS += -DUSE_INDIRECT_REF
+LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter
#
# Optional features. These may impact the size or performance of the VM.
@@ -98,6 +99,7 @@
LOCAL_SRC_FILES := \
AllocTracker.c \
+ Atomic.c.arm \
AtomicCache.c \
CheckJni.c \
Ddm.c \
@@ -128,17 +130,19 @@
UtfString.c \
alloc/clz.c.arm \
alloc/Alloc.c \
+ alloc/CardTable.c \
alloc/HeapBitmap.c.arm \
alloc/HeapDebug.c \
- alloc/HeapSource.c \
alloc/HeapTable.c \
alloc/HeapWorker.c \
alloc/Heap.c.arm \
- alloc/MarkSweep.c.arm \
alloc/DdmHeap.c \
+ alloc/Verify.c \
+ alloc/Visit.c \
analysis/CodeVerify.c \
- analysis/DexOptimize.c \
+ analysis/DexPrepare.c \
analysis/DexVerify.c \
+ analysis/Optimize.c \
analysis/ReduceConstants.c \
analysis/RegisterMap.c \
analysis/VerifySubs.c \
@@ -192,19 +196,31 @@
reflect/Annotation.c \
reflect/Proxy.c \
reflect/Reflect.c \
- test/AtomicSpeed.c \
+ test/AtomicTest.c.arm \
test/TestHash.c \
test/TestIndirectRefTable.c
+WITH_COPYING_GC := $(strip $(WITH_COPYING_GC))
+
+ifeq ($(WITH_COPYING_GC),true)
+ LOCAL_CFLAGS += -DWITH_COPYING_GC
+ LOCAL_SRC_FILES += \
+ alloc/Copying.c.arm
+else
+ LOCAL_SRC_FILES += \
+ alloc/HeapSource.c \
+ alloc/MarkSweep.c.arm
+endif
+
WITH_JIT := $(strip $(WITH_JIT))
ifeq ($(WITH_JIT),true)
LOCAL_CFLAGS += -DWITH_JIT
LOCAL_SRC_FILES += \
- ../dexdump/OpCodeNames.c \
compiler/Compiler.c \
compiler/Frontend.c \
compiler/Utility.c \
+ compiler/InlineTransformation.c \
compiler/IntermediateRep.c \
compiler/Dataflow.c \
compiler/Loop.c \
@@ -225,10 +241,6 @@
hprof/HprofString.c
LOCAL_CFLAGS += -DWITH_HPROF=1
- ifeq ($(strip $(WITH_HPROF_UNREACHABLE)),true)
- LOCAL_CFLAGS += -DWITH_HPROF_UNREACHABLE=1
- endif
-
ifeq ($(strip $(WITH_HPROF_STACK)),true)
LOCAL_SRC_FILES += \
hprof/HprofStack.c \
@@ -237,10 +249,6 @@
endif # WITH_HPROF_STACK
endif # WITH_HPROF
-ifeq ($(strip $(DVM_TRACK_HEAP_MARKING)),true)
- LOCAL_CFLAGS += -DDVM_TRACK_HEAP_MARKING=1
-endif
-
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
dalvik \
@@ -266,6 +274,7 @@
ifeq ($(dvm_arch),arm)
#dvm_arch_variant := armv7-a
#LOCAL_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp
+ LOCAL_CFLAGS += -Werror
MTERP_ARCH_KNOWN := true
# Select architecture-specific sources (armv4t, armv5te etc.)
LOCAL_SRC_FILES += \
diff --git a/vm/DvmDex.c b/vm/DvmDex.c
index 258d768..02dd758 100644
--- a/vm/DvmDex.c
+++ b/vm/DvmDex.c
@@ -227,10 +227,14 @@
* This requires changing the access permissions to read-write, updating
* the value, and then resetting the permissions.
*
- * This does not make any synchronization guarantees. It's important for the
- * caller(s) to work out mutual exclusion, at least on a page granularity,
- * to avoid a race where one threads sets read-write, another thread sets
- * read-only, and then the first thread does a write.
+ * We need to ensure mutual exclusion at a page granularity to avoid a race
+ * where one threads sets read-write, another thread sets read-only, and
+ * then the first thread does a write. Since we don't do a lot of updates,
+ * and the window is small, we just use a lock across the entire DvmDex.
+ * We're only trying to make the page state change atomic; it's up to the
+ * caller to ensure that multiple threads aren't stomping on the same
+ * location (e.g. breakpoints and verifier/optimizer changes happening
+ * simultaneously).
*
* TODO: if we're back to the original state of the page, use
* madvise(MADV_DONTNEED) to release the private/dirty copy.
@@ -244,6 +248,12 @@
return true;
}
+ /*
+ * We're not holding this for long, so we don't bother with switching
+ * to VMWAIT.
+ */
+ dvmLockMutex(&pDvmDex->modLock);
+
LOGV("+++ change byte at %p from 0x%02x to 0x%02x\n", addr, *addr, newVal);
if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) != 0) {
LOGD("NOTE: DEX page access change (->RW) failed\n");
@@ -257,6 +267,8 @@
/* expected on files mounted from FAT; keep going */
}
+ dvmUnlockMutex(&pDvmDex->modLock);
+
return true;
}
@@ -273,6 +285,12 @@
return true;
}
+ /*
+ * We're not holding this for long, so we don't bother with switching
+ * to VMWAIT.
+ */
+ dvmLockMutex(&pDvmDex->modLock);
+
LOGV("+++ change 2byte at %p from 0x%04x to 0x%04x\n", addr, *addr, newVal);
if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) != 0) {
LOGD("NOTE: DEX page access change (->RW) failed\n");
@@ -286,6 +304,7 @@
/* expected on files mounted from FAT; keep going */
}
+ dvmUnlockMutex(&pDvmDex->modLock);
+
return true;
}
-
diff --git a/vm/DvmDex.h b/vm/DvmDex.h
index 9f3903a..803be1f 100644
--- a/vm/DvmDex.h
+++ b/vm/DvmDex.h
@@ -59,6 +59,9 @@
/* shared memory region with file contents */
MemMapping memMap;
+
+ /* lock ensuring mutual exclusion during updates */
+ pthread_mutex_t modLock;
} DvmDex;
diff --git a/vm/Exception.c b/vm/Exception.c
index 13b051e..3a73420 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -424,7 +424,7 @@
if (msg == NULL)
msgStr = NULL;
else {
- msgStr = dvmCreateStringFromCstr(msg, ALLOC_DEFAULT);
+ msgStr = dvmCreateStringFromCstr(msg);
if (msgStr == NULL) {
LOGW("Could not allocate message string \"%s\" while "
"throwing internal exception (%s)\n",
@@ -528,7 +528,7 @@
excepClass->descriptor, msg, initKind);
assert(strcmp(excepClass->descriptor,
"Ljava/lang/RuntimeException;") != 0);
- dvmThrowChainedException("Ljava/lang/RuntimeException;",
+ dvmThrowChainedException("Ljava/lang/RuntimeException;",
"re-throw on exception class missing constructor", NULL);
goto bail;
}
@@ -744,7 +744,7 @@
}
if (self->exception != NULL) {
- LOGI("NOTE: exception thrown while printing stack trace: %s\n",
+ LOGW("NOTE: exception thrown while printing stack trace: %s\n",
self->exception->clazz->descriptor);
}
@@ -781,7 +781,7 @@
if (handler == NULL) {
break;
}
-
+
if (handler->typeIdx == kDexNoIndex) {
/* catch-all */
LOGV("Match on catch-all block at 0x%02x in %s.%s for %s\n",
@@ -1075,7 +1075,7 @@
*intPtr++ = 0; /* no saved PC for native methods */
} else {
assert(saveArea->xtra.currentPc >= method->insns &&
- saveArea->xtra.currentPc <
+ saveArea->xtra.currentPc <
method->insns + dvmGetMethodInsnsSize(method));
*intPtr++ = (int) (saveArea->xtra.currentPc - method->insns);
}
@@ -1109,7 +1109,7 @@
{
const ArrayObject* stackData = (const ArrayObject*) ostackData;
const int* intVals;
- int i, stackSize;
+ int stackSize;
stackSize = stackData->length / 2;
intVals = (const int*) stackData->contents;
@@ -1127,7 +1127,6 @@
ArrayObject* dvmGetStackTraceRaw(const int* intVals, int stackDepth)
{
ArrayObject* steArray = NULL;
- Object** stePtr;
int i;
/* init this if we haven't yet */
@@ -1139,7 +1138,6 @@
stackDepth, kObjectArrayRefWidth, ALLOC_DEFAULT);
if (steArray == NULL)
goto bail;
- stePtr = (Object**) steArray->contents;
/*
* Allocate and initialize a StackTraceElement for each stack frame.
@@ -1168,13 +1166,13 @@
lineNumber = dvmLineNumFromPC(meth, pc);
dotName = dvmDescriptorToDot(meth->clazz->descriptor);
- className = dvmCreateStringFromCstr(dotName, ALLOC_DEFAULT);
+ className = dvmCreateStringFromCstr(dotName);
free(dotName);
- methodName = dvmCreateStringFromCstr(meth->name, ALLOC_DEFAULT);
+ methodName = dvmCreateStringFromCstr(meth->name);
sourceFile = dvmGetMethodSourceFile(meth);
if (sourceFile != NULL)
- fileName = dvmCreateStringFromCstr(sourceFile, ALLOC_DEFAULT);
+ fileName = dvmCreateStringFromCstr(sourceFile);
else
fileName = NULL;
@@ -1196,7 +1194,7 @@
if (dvmCheckException(dvmThreadSelf()))
goto bail;
- *stePtr++ = ste;
+ dvmSetObjectArrayElement(steArray, i, ste);
}
bail:
@@ -1304,4 +1302,3 @@
exception = cause;
}
}
-
diff --git a/vm/Globals.h b/vm/Globals.h
index fb2518d..5341d26 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -37,6 +37,7 @@
/* private structures */
typedef struct GcHeap GcHeap;
typedef struct BreakpointSet BreakpointSet;
+typedef struct InlineSub InlineSub;
/*
* One of these for each -ea/-da/-esa/-dsa on the command line.
@@ -103,6 +104,7 @@
void (*abortHook)(void);
int jniGrefLimit; // 0 means no limit
+ char* jniTrace;
bool reduceSignals;
bool noQuitHandler;
bool verifyDexChecksum;
@@ -112,8 +114,17 @@
DexOptimizerMode dexOptMode;
DexClassVerifyMode classVerifyMode;
+
+ /*
+ * GC option flags.
+ */
bool preciseGc;
+ bool overwriteFree;
+ bool preVerify;
+ bool postVerify;
bool generateRegisterMaps;
+ bool concurrentMarkSweep;
+ bool verifyCardTable;
int assertionCtrlCount;
AssertionControl* assertionCtrl;
@@ -167,12 +178,19 @@
/*
* Interned strings.
*/
+
+ /* A mutex that guards access to the interned string tables. */
+ pthread_mutex_t internLock;
+
+ /* Hash table of strings interned by the user. */
HashTable* internedStrings;
+ /* Hash table of strings interned by the class loader. */
+ HashTable* literalStrings;
+
/*
* Quick lookups for popular classes used internally.
*/
- ClassObject* unlinkedJavaLangClass; // see unlinkedJavaLangClassObject
ClassObject* classJavaLangClass;
ClassObject* classJavaLangClassArray;
ClassObject* classJavaLangError;
@@ -228,7 +246,7 @@
int offJavaLangClass_pd;
/* field offsets - String */
- volatile int javaLangStringReady; /* 0=not init, 1=ready, -1=initing */
+ int javaLangStringReady; /* 0=not init, 1=ready, -1=initing */
int offJavaLangString_value;
int offJavaLangString_count;
int offJavaLangString_offset;
@@ -269,7 +287,7 @@
int offJavaLangRefReference_referent;
int offJavaLangRefReference_queue;
int offJavaLangRefReference_queueNext;
- int offJavaLangRefReference_vmData;
+ int offJavaLangRefReference_pendingNext;
/* method pointers - java.lang.ref.Reference */
Method* methJavaLangRefReference_enqueueInternal;
@@ -319,12 +337,6 @@
ClassObject* volatile primitiveClass[PRIM_MAX];
/*
- * A placeholder ClassObject used during ClassObject
- * construction.
- */
- ClassObject unlinkedJavaLangClassObject;
-
- /*
* Thread list. This always has at least one element in it (main),
* and main is always the first entry.
*
@@ -432,9 +444,6 @@
ReferenceTable jniPinRefTable;
pthread_mutex_t jniPinRefLock;
- /* special ReferenceQueue for JNI weak globals */
- Object* jniWeakGlobalRefQueue;
-
/*
* Native shared library table.
*/
@@ -446,9 +455,18 @@
*/
pthread_mutex_t gcHeapLock;
+ /*
+ * Condition variable to queue threads waiting to retry an
+ * allocation. Signaled after a concurrent GC is completed.
+ */
+ pthread_cond_t gcHeapCond;
+
/* Opaque pointer representing the heap. */
GcHeap* gcHeap;
+ /* The card table base, modified as needed for marking cards. */
+ u1* biasedCardTableBase;
+
/*
* Pre-allocated throwables.
*/
@@ -488,6 +506,9 @@
/* instruction format table, used for verification */
InstructionFormat* instrFormat;
+ /* inline substitution table, used during optimization */
+ InlineSub* inlineSubs;
+
/*
* Bootstrap class loader linear allocator.
*/
@@ -730,20 +751,7 @@
/* JIT internal stats */
int compilerMaxQueued;
- int addrLookupsFound;
- int addrLookupsNotFound;
- int noChainExit[kNoChainExitLast];
- int normalExit;
- int puntExit;
int translationChains;
- int invokeMonomorphic;
- int invokePolymorphic;
- int invokeNative;
- int returnOp;
- int icPatchFast;
- int icPatchQueued;
- int icPatchDropped;
- u8 jitTime;
/* Compiled code cache */
void* codeCache;
@@ -760,6 +768,12 @@
/* Flag to indicate that the code cache is full */
bool codeCacheFull;
+ /* Page size - 1 */
+ unsigned int pageSizeMask;
+
+ /* Lock to change the protection type of the code cache */
+ pthread_mutex_t codeCacheProtectionLock;
+
/* Number of times that the code cache has been reset */
int numCodeCacheReset;
@@ -787,9 +801,6 @@
/* Vector to disable selected optimizations */
int disableOpt;
- /* Code address of special interpret-only pseudo-translation */
- void *interpretTemplate;
-
/* Table to track the overall and trace statistics of hot methods */
HashTable* methodStatsTable;
@@ -819,6 +830,30 @@
u4 *signatureBreakpoint; // Signature content
#endif
+#if defined(WITH_JIT_TUNING)
+ /* Performance tuning counters */
+ int addrLookupsFound;
+ int addrLookupsNotFound;
+ int noChainExit[kNoChainExitLast];
+ int normalExit;
+ int puntExit;
+ int invokeMonomorphic;
+ int invokePolymorphic;
+ int invokeNative;
+ int invokeMonoGetterInlined;
+ int invokeMonoSetterInlined;
+ int invokePolyGetterInlined;
+ int invokePolySetterInlined;
+ int returnOp;
+ int icPatchInit;
+ int icPatchLockFree;
+ int icPatchQueued;
+ int icPatchRejected;
+ int icPatchDropped;
+ u8 jitTime;
+ int codeCachePatches;
+#endif
+
/* Place arrays at the end to ease the display in gdb sessions */
/* Work order queue for compilations */
@@ -830,6 +865,10 @@
extern struct DvmJitGlobals gDvmJit;
+#if defined(WITH_JIT_TUNING)
+extern int gDvmICHitCount;
+#endif
+
#endif
#endif /*_DALVIK_GLOBALS*/
diff --git a/vm/Hash.c b/vm/Hash.c
index 67a25a1..7bdd92f 100644
--- a/vm/Hash.c
+++ b/vm/Hash.c
@@ -282,8 +282,8 @@
/*
* Scan every entry in the hash table and evaluate it with the specified
- * indirect function call. If the function returns 1, remove the entry from
- * the table.
+ * indirect function call. If the function returns 1, remove the entry from
+ * the table.
*
* Does NOT invoke the "free" function on the item.
*
@@ -400,7 +400,7 @@
{
const void* data = (const void*)dvmHashIterData(&iter);
int count;
-
+
count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
numEntries++;
diff --git a/vm/IndirectRefTable.c b/vm/IndirectRefTable.c
index bea0a0f..dadd03f 100644
--- a/vm/IndirectRefTable.c
+++ b/vm/IndirectRefTable.c
@@ -129,7 +129,7 @@
static inline void updateSlotRemove(IndirectRefTable* pRef, int slot)
{
if (pRef->slotData != NULL) {
- IndirectRefSlot* pSlot = &pRef->slotData[slot];
+ //IndirectRefSlot* pSlot = &pRef->slotData[slot];
//LOGI("+++ remove [%d] slot %d, serial now %d\n",
// pRef->kind, slot, pSlot->serial);
}
@@ -144,7 +144,6 @@
IRTSegmentState prevState;
prevState.all = cookie;
int topIndex = pRef->segmentState.parts.topIndex;
- int bottomIndex = prevState.parts.topIndex;
assert(obj != NULL);
assert(dvmIsValidObject(obj));
@@ -195,7 +194,7 @@
Object** pScan = &pRef->table[topIndex - 1];
assert(*pScan != NULL);
while (*--pScan != NULL) {
- assert(pScan >= pRef->table + bottomIndex);
+ assert(pScan >= pRef->table + prevState.parts.topIndex);
}
updateSlotAdd(pRef, obj, pScan - pRef->table);
result = dvmObjectToIndirectRef(pRef, obj, pScan - pRef->table,
@@ -500,4 +499,3 @@
LOGW("Memory held directly by native code is %d bytes\n", total);
free(tableCopy);
}
-
diff --git a/vm/Init.c b/vm/Init.c
index 6630395..06ceabc 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -36,8 +36,6 @@
/*
* Register VM-agnostic native methods for system classes.
- *
- * Currently defined in ../include/nativehelper/AndroidSystemNatives.h
*/
extern int jniRegisterSystemMethods(JNIEnv* env);
@@ -53,6 +51,15 @@
/* JIT-specific global state */
#if defined(WITH_JIT)
struct DvmJitGlobals gDvmJit;
+
+#if defined(WITH_JIT_TUNING)
+/*
+ * Track the number of hits in the inline cache for predicted chaining.
+ * Use an ugly global variable here since it is accessed in assembly code.
+ */
+int gDvmICHitCount;
+#endif
+
#endif
/*
@@ -104,9 +111,15 @@
dvmFprintf(stderr,
" -Xjnigreflimit:N (must be multiple of 100, >= 200)\n");
dvmFprintf(stderr, " -Xjniopts:{warnonly,forcecopy}\n");
+ dvmFprintf(stderr, " -Xjnitrace:substring (eg NativeClass or nativeMethod)\n");
dvmFprintf(stderr, " -Xdeadlockpredict:{off,warn,err,abort}\n");
dvmFprintf(stderr, " -Xstacktracefile:<filename>\n");
dvmFprintf(stderr, " -Xgc:[no]precise\n");
+ dvmFprintf(stderr, " -Xgc:[no]overwritefree\n");
+ dvmFprintf(stderr, " -Xgc:[no]preverify\n");
+ dvmFprintf(stderr, " -Xgc:[no]postverify\n");
+ dvmFprintf(stderr, " -Xgc:[no]concurrent\n");
+ dvmFprintf(stderr, " -Xgc:[no]verifycardtable\n");
dvmFprintf(stderr, " -Xgenregmap\n");
dvmFprintf(stderr, " -Xcheckdexsum\n");
#if defined(WITH_JIT)
@@ -143,9 +156,6 @@
#ifdef WITH_HPROF_STACK
" hprof_stack"
#endif
-#ifdef WITH_HPROF_STACK_UNREACHABLE
- " hprof_stack_unreachable"
-#endif
#ifdef WITH_ALLOC_LIMITS
" alloc_limits"
#endif
@@ -176,9 +186,6 @@
#ifdef PROFILE_FIELD_ACCESS
" profile_field_access"
#endif
-#ifdef DVM_TRACK_HEAP_MARKING
- " track_heap_marking"
-#endif
#if DVM_RESOLVER_CACHE == DVM_RC_REDUCING
" resolver_cache_reducing"
#elif DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
@@ -192,6 +199,9 @@
#if defined(WITH_SELF_VERIFICATION)
" self_verification"
#endif
+#if ANDROID_SMP != 0
+ " smp"
+#endif
);
#ifdef DVM_SHOW_EXCEPTION
dvmFprintf(stderr, " show_exception=%d", DVM_SHOW_EXCEPTION);
@@ -217,7 +227,7 @@
{
dvmFprintf(stdout, "DalvikVM version %d.%d.%d\n",
DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
- dvmFprintf(stdout,
+ dvmFprintf(stdout,
"Copyright (C) 2007 The Android Open Source Project\n\n"
"This software is built from source code licensed under the "
"Apache License,\n"
@@ -627,7 +637,7 @@
gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
start = buf;
- /*
+ /*
* Break comma-separated method signatures and enter them into the hash
* table individually.
*/
@@ -825,7 +835,6 @@
strncmp(argv[i], "-agentlib:jdwp=", 15) == 0)
{
const char* tail;
- bool result = false;
if (argv[i][1] == 'X')
tail = argv[i] + 10;
@@ -877,7 +886,8 @@
return -1;
}
gDvm.jniGrefLimit = lim;
-
+ } else if (strncmp(argv[i], "-Xjnitrace:", 11) == 0) {
+ gDvm.jniTrace = strdup(argv[i] + 11);
} else if (strcmp(argv[i], "-Xlog-stdio") == 0) {
gDvm.logStdio = true;
@@ -897,7 +907,8 @@
/* keep going */
}
} else {
- /* disable JIT -- nothing to do here for now */
+ /* disable JIT if it was enabled by default */
+ gDvm.executionMode = kExecutionModeInterpFast;
}
} else if (strncmp(argv[i], "-Xlockprofthreshold:", 20) == 0) {
@@ -964,6 +975,26 @@
gDvm.preciseGc = true;
else if (strcmp(argv[i] + 5, "noprecise") == 0)
gDvm.preciseGc = false;
+ else if (strcmp(argv[i] + 5, "overwritefree") == 0)
+ gDvm.overwriteFree = true;
+ else if (strcmp(argv[i] + 5, "nooverwritefree") == 0)
+ gDvm.overwriteFree = false;
+ else if (strcmp(argv[i] + 5, "preverify") == 0)
+ gDvm.preVerify = true;
+ else if (strcmp(argv[i] + 5, "nopreverify") == 0)
+ gDvm.preVerify = false;
+ else if (strcmp(argv[i] + 5, "postverify") == 0)
+ gDvm.postVerify = true;
+ else if (strcmp(argv[i] + 5, "nopostverify") == 0)
+ gDvm.postVerify = false;
+ else if (strcmp(argv[i] + 5, "concurrent") == 0)
+ gDvm.concurrentMarkSweep = true;
+ else if (strcmp(argv[i] + 5, "noconcurrent") == 0)
+ gDvm.concurrentMarkSweep = false;
+ else if (strcmp(argv[i] + 5, "verifycardtable") == 0)
+ gDvm.verifyCardTable = true;
+ else if (strcmp(argv[i] + 5, "noverifycardtable") == 0)
+ gDvm.verifyCardTable = false;
else {
dvmFprintf(stderr, "Bad value for -Xgc");
return -1;
@@ -1016,6 +1047,8 @@
gDvm.heapSizeMax = 16 * 1024 * 1024; // Spec says 75% physical mem
gDvm.stackSize = kDefaultStackSize;
+ gDvm.concurrentMarkSweep = true;
+
/* gDvm.jdwpSuspend = true; */
/* allowed unless zygote config doesn't allow it */
@@ -1352,7 +1385,7 @@
{
u8 startHeap, startQuit, startJdwp;
u8 endHeap, endQuit, endJdwp;
-
+
startHeap = dvmGetRelativeTimeUsec();
/*
@@ -1572,12 +1605,14 @@
/*
* Stop our internal threads.
*/
- dvmHeapWorkerShutdown();
+ dvmGcThreadShutdown();
if (gDvm.jdwpState != NULL)
dvmJdwpShutdown(gDvm.jdwpState);
free(gDvm.jdwpHost);
gDvm.jdwpHost = NULL;
+ free(gDvm.jniTrace);
+ gDvm.jniTrace = NULL;
free(gDvm.stackTraceFile);
gDvm.stackTraceFile = NULL;
diff --git a/vm/InlineNative.c b/vm/InlineNative.c
index ec8a1fb..aa9c5cf 100644
--- a/vm/InlineNative.c
+++ b/vm/InlineNative.c
@@ -58,6 +58,12 @@
* DO NOT replace "synchronized" methods. We do not support method
* synchronization here.
*
+ * DO NOT perform any allocations or do anything that could cause a
+ * garbage collection. The method arguments are not visible to the GC
+ * and will not be pinned or updated when memory blocks move. You are
+ * allowed to allocate and throw an exception so long as you only do so
+ * immediately before returning.
+ *
* Remember that these functions are executing while the thread is in
* the "RUNNING" state, not the "NATIVE" state. If you perform a blocking
* operation you can stall the entire VM if the GC or debugger wants to
@@ -219,7 +225,7 @@
ArrayObject* compArray;
const u2* thisChars;
const u2* compChars;
- int i, minCount, countDiff;
+ int minCount, countDiff;
thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
@@ -245,6 +251,7 @@
*/
int otherRes = __memcmp16(thisChars, compChars, minCount);
# ifdef CHECK_MEMCMP16
+ int i;
for (i = 0; i < minCount; i++) {
if (thisChars[i] != compChars[i]) {
pResult->i = (s4) thisChars[i] - (s4) compChars[i];
@@ -267,6 +274,7 @@
* the characters that overlap, and if they're all the same then return
* the difference in lengths.
*/
+ int i;
for (i = 0; i < minCount; i++) {
if (thisChars[i] != compChars[i]) {
pResult->i = (s4) thisChars[i] - (s4) compChars[i];
@@ -318,7 +326,6 @@
ArrayObject* compArray;
const u2* thisChars;
const u2* compChars;
- int i;
/* quick length check */
thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
@@ -357,6 +364,7 @@
* meaningful comparison when the strings don't match (could also test
* with palindromes).
*/
+ int i;
//for (i = 0; i < thisCount; i++)
for (i = thisCount-1; i >= 0; --i)
{
@@ -388,11 +396,27 @@
}
/*
+ * public boolean isEmpty()
+ */
+static bool javaLangString_isEmpty(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ //LOGI("String.isEmpty this=0x%08x pResult=%p\n", arg0, pResult);
+
+ /* null reference check on "this" */
+ if (!dvmValidateObject((Object*) arg0))
+ return false;
+
+ pResult->i = (dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT) == 0);
+ return true;
+}
+
+/*
* Determine the index of the first character matching "ch". The string
* to search is described by "chars", "offset", and "count".
*
- * The "ch" parameter is allowed to be > 0xffff. Our Java-language
- * implementation does not currently handle this, so neither do we.
+ * The character must be <= 0xffff. Supplementary characters are handled in
+ * Java.
*
* The "start" parameter must be clamped to [0..count].
*
@@ -439,27 +463,13 @@
}
/*
- * public int indexOf(int c)
- *
- * Scan forward through the string for a matching character.
- */
-static bool javaLangString_indexOf_I(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
- JValue* pResult)
-{
- /* null reference check on "this" */
- if (!dvmValidateObject((Object*) arg0))
- return false;
-
- pResult->i = indexOfCommon((Object*) arg0, arg1, 0);
- return true;
-}
-
-/*
* public int indexOf(int c, int start)
*
* Scan forward through the string for a matching character.
+ * The character must be <= 0xffff; this method does not handle supplementary
+ * characters.
*/
-static bool javaLangString_indexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+static bool javaLangString_fastIndexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
JValue* pResult)
{
/* null reference check on "this" */
@@ -650,10 +660,10 @@
"Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
{ javaLangString_equals,
"Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
- { javaLangString_indexOf_I,
- "Ljava/lang/String;", "indexOf", "(I)I" },
- { javaLangString_indexOf_II,
- "Ljava/lang/String;", "indexOf", "(II)I" },
+ { javaLangString_fastIndexOf_II,
+ "Ljava/lang/String;", "fastIndexOf", "(II)I" },
+ { javaLangString_isEmpty,
+ "Ljava/lang/String;", "isEmpty", "()Z" },
{ javaLangString_length,
"Ljava/lang/String;", "length", "()I" },
@@ -744,7 +754,7 @@
Method* method = gDvm.inlinedMethods[opIndex];
if (method == NULL) {
ClassObject* clazz;
-
+
clazz = dvmFindClassNoInit(
gDvmInlineOpsTable[opIndex].classDescriptor, NULL);
if (clazz == NULL) {
diff --git a/vm/InlineNative.h b/vm/InlineNative.h
index 300c94c..9b9ae39 100644
--- a/vm/InlineNative.h
+++ b/vm/InlineNative.h
@@ -54,8 +54,8 @@
INLINE_STRING_CHARAT = 1,
INLINE_STRING_COMPARETO = 2,
INLINE_STRING_EQUALS = 3,
- INLINE_STRING_INDEXOF_I = 4,
- INLINE_STRING_INDEXOF_II = 5,
+ INLINE_STRING_FASTINDEXOF_II = 4,
+ INLINE_STRING_IS_EMPTY = 5,
INLINE_STRING_LENGTH = 6,
INLINE_MATH_ABS_INT = 7,
INLINE_MATH_ABS_LONG = 8,
diff --git a/vm/Inlines.c b/vm/Inlines.c
index e314448..f1bd621 100644
--- a/vm/Inlines.c
+++ b/vm/Inlines.c
@@ -26,4 +26,3 @@
#undef LOG_TAG
#include "jdwp/JdwpPriv.h"
-
diff --git a/vm/Inlines.h b/vm/Inlines.h
index cdfaf75..f1580e3 100644
--- a/vm/Inlines.h
+++ b/vm/Inlines.h
@@ -30,4 +30,3 @@
#else
# define INLINE
#endif
-
diff --git a/vm/Intern.c b/vm/Intern.c
index 8584333..15bf8ab 100644
--- a/vm/Intern.c
+++ b/vm/Intern.c
@@ -18,26 +18,20 @@
*/
#include "Dalvik.h"
-#include <stdlib.h>
-
-#define INTERN_STRING_IMMORTAL_BIT (1<<0)
-#define SET_IMMORTAL_BIT(strObj) \
- ((uintptr_t)(strObj) | INTERN_STRING_IMMORTAL_BIT)
-#define STRIP_IMMORTAL_BIT(strObj) \
- ((uintptr_t)(strObj) & ~INTERN_STRING_IMMORTAL_BIT)
-#define IS_IMMORTAL(strObj) \
- ((uintptr_t)(strObj) & INTERN_STRING_IMMORTAL_BIT)
-
+#include <stddef.h>
/*
* Prep string interning.
*/
bool dvmStringInternStartup(void)
{
+ dvmInitMutex(&gDvm.internLock);
gDvm.internedStrings = dvmHashTableCreate(256, NULL);
if (gDvm.internedStrings == NULL)
return false;
-
+ gDvm.literalStrings = dvmHashTableCreate(256, NULL);
+ if (gDvm.literalStrings == NULL)
+ return false;
return true;
}
@@ -48,70 +42,47 @@
*/
void dvmStringInternShutdown(void)
{
+ if (gDvm.internedStrings != NULL || gDvm.literalStrings != NULL) {
+ dvmDestroyMutex(&gDvm.internLock);
+ }
dvmHashTableFree(gDvm.internedStrings);
gDvm.internedStrings = NULL;
+ dvmHashTableFree(gDvm.literalStrings);
+ gDvm.literalStrings = NULL;
}
-
-/*
- * Compare two string objects that may have INTERN_STRING_IMMORTAL_BIT
- * set in their pointer values.
- */
-static int hashcmpImmortalStrings(const void* vstrObj1, const void* vstrObj2)
-{
- return dvmHashcmpStrings((const void*) STRIP_IMMORTAL_BIT(vstrObj1),
- (const void*) STRIP_IMMORTAL_BIT(vstrObj2));
-}
-
-static StringObject* lookupInternedString(StringObject* strObj, bool immortal)
+static StringObject* lookupInternedString(StringObject* strObj, bool isLiteral)
{
StringObject* found;
u4 hash;
assert(strObj != NULL);
hash = dvmComputeStringHash(strObj);
-
- if (false) {
- char* debugStr = dvmCreateCstrFromString(strObj);
- LOGV("+++ dvmLookupInternedString searching for '%s'\n", debugStr);
- free(debugStr);
+ dvmLockMutex(&gDvm.internLock);
+ if (isLiteral) {
+ found = dvmHashTableLookup(gDvm.literalStrings, hash, strObj,
+ dvmHashcmpStrings, true);
+ if (found == strObj) {
+ dvmHashTableRemove(gDvm.internedStrings, hash, strObj);
+ }
+ } else {
+ found = dvmHashTableLookup(gDvm.literalStrings, hash, strObj,
+ dvmHashcmpStrings, false);
+ if (found == NULL) {
+ found = dvmHashTableLookup(gDvm.internedStrings, hash, strObj,
+ dvmHashcmpStrings, true);
+ }
}
-
- if (immortal) {
- strObj = (StringObject*) SET_IMMORTAL_BIT(strObj);
- }
-
- dvmHashTableLock(gDvm.internedStrings);
-
- found = (StringObject*) dvmHashTableLookup(gDvm.internedStrings,
- hash, strObj, hashcmpImmortalStrings, true);
- if (immortal && !IS_IMMORTAL(found)) {
- /* Make this entry immortal. We have to use the existing object
- * because, as an interned string, it's not allowed to change.
- *
- * There's no way to get a pointer to the actual hash table entry,
- * so the only way to modify the existing entry is to remove,
- * modify, and re-add it.
- */
- dvmHashTableRemove(gDvm.internedStrings, hash, found);
- found = (StringObject*) SET_IMMORTAL_BIT(found);
- found = (StringObject*) dvmHashTableLookup(gDvm.internedStrings,
- hash, found, hashcmpImmortalStrings, true);
- assert(IS_IMMORTAL(found));
- }
-
- dvmHashTableUnlock(gDvm.internedStrings);
-
- //if (found == strObj)
- // LOGVV("+++ added string\n");
- return (StringObject*) STRIP_IMMORTAL_BIT(found);
+ assert(found != NULL);
+ dvmUnlockMutex(&gDvm.internLock);
+ return found;
}
/*
- * Find an entry in the interned string list.
+ * Find an entry in the interned string table.
*
* If the string doesn't already exist, the StringObject is added to
- * the list. Otherwise, the existing entry is returned.
+ * the table. Otherwise, the existing entry is returned.
*/
StringObject* dvmLookupInternedString(StringObject* strObj)
{
@@ -120,45 +91,36 @@
/*
* Same as dvmLookupInternedString(), but guarantees that the
- * returned string is immortal.
+ * returned string is a literal.
*/
StringObject* dvmLookupImmortalInternedString(StringObject* strObj)
{
return lookupInternedString(strObj, true);
}
-/*
- * Mark all immortal interned string objects so that they don't
- * get collected by the GC. Non-immortal strings may or may not
- * get marked by other references.
- */
static int markStringObject(void* strObj, void* arg)
{
UNUSED_PARAMETER(arg);
-
- if (IS_IMMORTAL(strObj)) {
- dvmMarkObjectNonNull((Object*) STRIP_IMMORTAL_BIT(strObj));
- }
+ dvmMarkObjectNonNull(strObj);
return 0;
}
+/*
+ * Blacken string references from the literal string table. The
+ * literal table is a root.
+ */
void dvmGcScanInternedStrings()
{
/* It's possible for a GC to happen before dvmStringInternStartup()
* is called.
*/
- if (gDvm.internedStrings != NULL) {
- dvmHashTableLock(gDvm.internedStrings);
- dvmHashForeach(gDvm.internedStrings, markStringObject, NULL);
- dvmHashTableUnlock(gDvm.internedStrings);
+ if (gDvm.literalStrings != NULL) {
+ dvmHashForeach(gDvm.literalStrings, markStringObject, NULL);
}
}
/*
- * Called by the GC after all reachable objects have been
- * marked. isUnmarkedObject is a function suitable for passing
- * to dvmHashForeachRemove(); it must strip the low bits from
- * its pointer argument to deal with the immortal bit, though.
+ * Clear white references from the intern table.
*/
void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *))
{
@@ -166,8 +128,8 @@
* is called.
*/
if (gDvm.internedStrings != NULL) {
- dvmHashTableLock(gDvm.internedStrings);
+ dvmLockMutex(&gDvm.internLock);
dvmHashForeachRemove(gDvm.internedStrings, isUnmarkedObject);
- dvmHashTableUnlock(gDvm.internedStrings);
+ dvmUnlockMutex(&gDvm.internLock);
}
}
diff --git a/vm/JarFile.c b/vm/JarFile.c
index 0a58390..39eb8d1 100644
--- a/vm/JarFile.c
+++ b/vm/JarFile.c
@@ -276,14 +276,14 @@
if (newFile) {
u8 startWhen, extractWhen, endWhen;
bool result;
- off_t dexOffset, fileLen;
+ off_t dexOffset;
dexOffset = lseek(fd, 0, SEEK_CUR);
result = (dexOffset > 0);
if (result) {
startWhen = dvmGetRelativeTimeUsec();
- result = dexZipExtractEntryToFile(&archive, entry, fd);
+ result = dexZipExtractEntryToFile(&archive, entry, fd) == 0;
extractWhen = dvmGetRelativeTimeUsec();
}
if (result) {
@@ -368,4 +368,3 @@
free(pJarFile->cacheFileName);
free(pJarFile);
}
-
diff --git a/vm/Jni.c b/vm/Jni.c
index 6692f3b..8967f46 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -859,7 +859,6 @@
}
#endif
-bail:
dvmUnlockMutex(&gDvm.jniGlobalRefLock);
return jobj;
}
@@ -918,53 +917,6 @@
dvmUnlockMutex(&gDvm.jniGlobalRefLock);
}
-
-/*
- * Get the "magic" JNI weak global ReferenceQueue. It's allocated on
- * first use.
- *
- * Returns NULL with an exception raised if allocation fails.
- */
-static Object* getWeakGlobalRefQueue(void)
-{
- /* use an indirect variable to avoid "type-punned pointer" complaints */
- Object** pGlobalQ = &gDvm.jniWeakGlobalRefQueue;
-
- if (*pGlobalQ != NULL)
- return *pGlobalQ;
-
- ClassObject* clazz = dvmFindSystemClass("Ljava/lang/ref/ReferenceQueue;");
- if (clazz == NULL) {
- LOGE("Unable to find java.lang.ref.ReferenceQueue");
- dvmAbort();
- }
-
- /*
- * Create an instance of ReferenceQueue. The object is never actually
- * used for anything, so we don't need to call a constructor. (We could
- * get away with using an instance of Object, but this is cleaner.)
- */
- Object* queue = dvmAllocObject(clazz, ALLOC_DEFAULT);
- if (queue == NULL) {
- LOGW("Failed allocating weak global ref queue\n");
- assert(dvmCheckException(dvmThreadSelf()));
- return NULL;
- }
- dvmReleaseTrackedAlloc(queue, NULL);
-
- /*
- * Save it, using atomic ops to ensure we don't double-up. The gDvm
- * field is known to the GC.
- */
- if (!ATOMIC_CMP_SWAP((int*) pGlobalQ, 0, (int) queue)) {
- LOGD("WOW: lost race to create weak global ref queue\n");
- queue = *pGlobalQ;
- }
-
- return queue;
-}
-
-
/*
* We create a PhantomReference that references the object, add a
* global reference to it, and then flip some bits before returning it.
@@ -980,7 +932,6 @@
Thread* self = ((JNIEnvExt*)env)->self;
Object* obj = dvmDecodeIndirectRef(env, jobj);
- Object* weakGlobalQueue = getWeakGlobalRefQueue();
Object* phantomObj;
jobject phantomRef;
@@ -1004,7 +955,7 @@
JValue unused;
dvmCallMethod(self, gDvm.methJavaLangRefPhantomReference_init, phantomObj,
- &unused, jobj, weakGlobalQueue);
+ &unused, obj, NULL);
dvmReleaseTrackedAlloc(phantomObj, self);
if (dvmCheckException(self)) {
@@ -1296,8 +1247,6 @@
#else
ReferenceTable* pRefTable = getLocalRefTable(env);
Thread* self = dvmThreadSelf();
- //Object** top;
- Object** ptr;
if (dvmIsWeakGlobalRef(jobj)) {
return JNIWeakGlobalRefType;
@@ -1347,26 +1296,26 @@
if (method == NULL)
method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
if (method == NULL) {
- LOGW("ERROR: Unable to find decl for native %s.%s %s\n",
+ LOGW("ERROR: Unable to find decl for native %s.%s:%s\n",
clazz->descriptor, methodName, signature);
goto bail;
}
if (!dvmIsNativeMethod(method)) {
- LOGW("Unable to register: not native: %s.%s %s\n",
+ LOGW("Unable to register: not native: %s.%s:%s\n",
clazz->descriptor, methodName, signature);
goto bail;
}
if (method->nativeFunc != dvmResolveNativeMethod) {
- LOGW("Warning: %s.%s %s was already registered/resolved?\n",
+ /* this is allowed, but unusual */
+ LOGV("Note: %s.%s:%s was already registered\n",
clazz->descriptor, methodName, signature);
- /* keep going, I guess */
}
dvmUseJNIBridge(method, fnPtr);
- LOGV("JNI-registered %s.%s %s\n", clazz->descriptor, methodName,
+ LOGV("JNI-registered %s.%s:%s\n", clazz->descriptor, methodName,
signature);
result = true;
@@ -1384,10 +1333,10 @@
}
/*
- * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
- * to point at the actual function.
+ * Returns the appropriate JNI bridge for 'method', also taking into account
+ * the -Xcheck:jni setting.
*/
-void dvmUseJNIBridge(Method* method, void* func)
+static DalvikBridgeFunc dvmSelectJNIBridge(const Method* method)
{
enum {
kJNIGeneral = 0,
@@ -1439,11 +1388,39 @@
}
}
- if (dvmIsCheckJNIEnabled()) {
- dvmSetNativeFunc(method, checkFunc[kind], func);
- } else {
- dvmSetNativeFunc(method, stdFunc[kind], func);
- }
+ return dvmIsCheckJNIEnabled() ? checkFunc[kind] : stdFunc[kind];
+}
+
+/*
+ * Trace a call into native code.
+ */
+static void dvmTraceCallJNIMethod(const u4* args, JValue* pResult,
+ const Method* method, Thread* self)
+{
+ dvmLogNativeMethodEntry(method, args);
+ DalvikBridgeFunc bridge = dvmSelectJNIBridge(method);
+ (*bridge)(args, pResult, method, self);
+ dvmLogNativeMethodExit(method, self, *pResult);
+}
+
+/**
+ * Returns true if the -Xjnitrace setting implies we should trace 'method'.
+ */
+static bool shouldTrace(Method* method)
+{
+ return gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace);
+}
+
+/*
+ * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
+ * to point at the actual function.
+ */
+void dvmUseJNIBridge(Method* method, void* func)
+{
+ DalvikBridgeFunc bridge = shouldTrace(method)
+ ? dvmTraceCallJNIMethod
+ : dvmSelectJNIBridge(method);
+ dvmSetNativeFunc(method, bridge, func);
}
/*
@@ -1536,6 +1513,31 @@
pRefTable->nextEntry = pRefTable->table;
}
+/*
+ * Determine if the specified class can be instantiated from JNI. This
+ * is used by AllocObject / NewObject, which are documented as throwing
+ * an exception for abstract and interface classes, and not accepting
+ * array classes. We also want to reject attempts to create new Class
+ * objects, since only DefineClass should do that.
+ */
+static bool canAllocClass(ClassObject* clazz)
+{
+ if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
+ /* JNI spec defines what this throws */
+ dvmThrowExceptionFmt("Ljava/lang/InstantiationException;",
+ "Can't instantiate %s (abstract or interface)", clazz->descriptor);
+ return false;
+ } else if (dvmIsArrayClass(clazz) || clazz == gDvm.classJavaLangClass) {
+ /* spec says "must not" for arrays, ignores Class */
+ dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
+ "Can't instantiate %s (array or Class) with this JNI function",
+ clazz->descriptor);
+ return false;
+ }
+
+ return true;
+}
+
#ifdef WITH_JNI_STACK_CHECK
/*
* Compute a CRC on the entire interpreted stack.
@@ -1658,8 +1660,6 @@
jclass staticMethodClass;
JNIEnv* env = self->jniEnv;
- assert(method->insns != NULL);
-
//LOGI("JNI calling %p (%s.%s:%s):\n", method->insns,
// method->clazz->descriptor, method->name, method->shorty);
@@ -1722,6 +1722,9 @@
oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+ ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
+ assert(method->insns != NULL);
+
COMPUTE_STACK_SUM(self);
dvmPlatformInvoke(env, staticMethodClass,
method->jniArgInfo, method->insSize, modArgs, method->shorty,
@@ -1781,6 +1784,8 @@
oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+ ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
+
COMPUTE_STACK_SUM(self);
dvmPlatformInvoke(self->jniEnv, NULL,
method->jniArgInfo, method->insSize, modArgs, method->shorty,
@@ -1815,6 +1820,8 @@
oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+ ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
+
COMPUTE_STACK_SUM(self);
dvmPlatformInvoke(self->jniEnv, staticMethodClass,
method->jniArgInfo, method->insSize, args, method->shorty,
@@ -2023,7 +2030,7 @@
{
JNI_ENTER();
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls);
- Object* obj = dvmCreateReflectObjForField(jcls, (Field*) fieldID);
+ Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
dvmReleaseTrackedAlloc(obj, NULL);
jobject jobj = addLocalReference(env, obj);
JNI_EXIT();
@@ -2278,7 +2285,9 @@
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
jobject result;
- if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+ if (!canAllocClass(clazz) ||
+ (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
+ {
assert(dvmCheckException(_self));
result = NULL;
} else {
@@ -2299,7 +2308,9 @@
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
jobject result;
- if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+ if (!canAllocClass(clazz) ||
+ (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
+ {
assert(dvmCheckException(_self));
result = NULL;
} else {
@@ -2325,11 +2336,19 @@
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
jobject result;
- Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- result = addLocalReference(env, newObj);
- if (newObj != NULL) {
- JValue unused;
- dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused, args);
+ if (!canAllocClass(clazz) ||
+ (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
+ {
+ assert(dvmCheckException(_self));
+ result = NULL;
+ } else {
+ Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+ result = addLocalReference(env, newObj);
+ if (newObj != NULL) {
+ JValue unused;
+ dvmCallMethodV(_self, (Method*) methodID, newObj, true, &unused,
+ args);
+ }
}
JNI_EXIT();
@@ -2342,11 +2361,19 @@
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
jobject result;
- Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- result = addLocalReference(env, newObj);
- if (newObj != NULL) {
- JValue unused;
- dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused, args);
+ if (!canAllocClass(clazz) ||
+ (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
+ {
+ assert(dvmCheckException(_self));
+ result = NULL;
+ } else {
+ Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+ result = addLocalReference(env, newObj);
+ if (newObj != NULL) {
+ JValue unused;
+ dvmCallMethodA(_self, (Method*) methodID, newObj, true, &unused,
+ args);
+ }
}
JNI_EXIT();
@@ -2961,7 +2988,7 @@
result = NULL;
} else {
/* note newStr could come back NULL on OOM */
- StringObject* newStr = dvmCreateStringFromCstr(bytes, ALLOC_DEFAULT);
+ StringObject* newStr = dvmCreateStringFromCstr(bytes);
result = addLocalReference(env, (Object*) newStr);
dvmReleaseTrackedAlloc((Object*)newStr, NULL);
}
@@ -3144,7 +3171,7 @@
//LOGV("JNI: set element %d in array %p to %p\n", index, array, value);
Object* obj = dvmDecodeIndirectRef(env, jobj);
- ((Object**) arrayObj->contents)[index] = obj;
+ dvmSetObjectArrayElement(arrayObj, index, obj);
bail:
JNI_EXIT();
@@ -3287,6 +3314,9 @@
/*
* Register one or more native functions in one class.
+ *
+ * This can be called multiple times on the same method, allowing the
+ * caller to redefine the method implementation at will.
*/
static jint RegisterNatives(JNIEnv* env, jclass jclazz,
const JNINativeMethod* methods, jint nMethods)
@@ -3315,19 +3345,44 @@
}
/*
- * Un-register a native function.
+ * Un-register all native methods associated with the class.
+ *
+ * The JNI docs refer to this as a way to reload/relink native libraries,
+ * and say it "should not be used in normal native code". In particular,
+ * there is no need to do this during shutdown, and you do not need to do
+ * this before redefining a method implementation with RegisterNatives.
+ *
+ * It's chiefly useful for a native "plugin"-style library that wasn't
+ * loaded with System.loadLibrary() (since there's no way to unload those).
+ * For example, the library could upgrade itself by:
+ *
+ * 1. call UnregisterNatives to unbind the old methods
+ * 2. ensure that no code is still executing inside it (somehow)
+ * 3. dlclose() the library
+ * 4. dlopen() the new library
+ * 5. use RegisterNatives to bind the methods from the new library
+ *
+ * The above can work correctly without the UnregisterNatives call, but
+ * creates a window of opportunity in which somebody might try to call a
+ * method that is pointing at unmapped memory, crashing the VM. In theory
+ * the same guards that prevent dlclose() from unmapping executing code could
+ * prevent that anyway, but with this we can be more thorough and also deal
+ * with methods that only exist in the old or new form of the library (maybe
+ * the lib wants to try the call and catch the UnsatisfiedLinkError).
*/
static jint UnregisterNatives(JNIEnv* env, jclass jclazz)
{
JNI_ENTER();
- /*
- * The JNI docs refer to this as a way to reload/relink native libraries,
- * and say it "should not be used in normal native code".
- *
- * We can implement it if we decide we need it.
- */
+
+ ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
+ if (gDvm.verboseJni) {
+ LOGI("[Unregistering JNI native methods for class %s]\n",
+ clazz->descriptor);
+ }
+ dvmUnregisterJNINativeMethods(clazz);
+
JNI_EXIT();
- return JNI_ERR;
+ return JNI_OK;
}
/*
diff --git a/vm/LinearAlloc.c b/vm/LinearAlloc.c
index bf89d50..65db79e 100644
--- a/vm/LinearAlloc.c
+++ b/vm/LinearAlloc.c
@@ -419,12 +419,11 @@
#ifdef DISABLE_LINEAR_ALLOC
return realloc(mem, newSize);
#endif
- LinearAllocHdr* pHdr = getHeader(classLoader);
-
/* make sure we have the right region (and mem != NULL) */
assert(mem != NULL);
- assert(mem >= (void*) pHdr->mapAddr &&
- mem < (void*) (pHdr->mapAddr + pHdr->curOffset));
+ assert(mem >= (void*) getHeader(classLoader)->mapAddr &&
+ mem < (void*) (getHeader(classLoader)->mapAddr +
+ getHeader(classLoader)->curOffset));
const u4* pLen = getBlockHeader(mem);
LOGV("--- LinearRealloc(%d) old=%d\n", newSize, *pLen);
@@ -570,11 +569,10 @@
if (mem == NULL)
return;
- LinearAllocHdr* pHdr = getHeader(classLoader);
-
/* make sure we have the right region */
- assert(mem >= (void*) pHdr->mapAddr &&
- mem < (void*) (pHdr->mapAddr + pHdr->curOffset));
+ assert(mem >= (void*) getHeader(classLoader)->mapAddr &&
+ mem < (void*) (getHeader(classLoader)->mapAddr +
+ getHeader(classLoader)->curOffset));
if (ENFORCE_READ_ONLY)
dvmLinearSetReadWrite(classLoader, mem);
@@ -704,4 +702,3 @@
return (char*) start >= pHdr->mapAddr &&
((char*)start + length) <= (pHdr->mapAddr + pHdr->curOffset);
}
-
diff --git a/vm/Misc.c b/vm/Misc.c
index 87f4c81..2a1e244 100644
--- a/vm/Misc.c
+++ b/vm/Misc.c
@@ -26,7 +26,11 @@
#include <time.h>
#include <sys/time.h>
#include <fcntl.h>
+#include <cutils/ashmem.h>
+#include <sys/mman.h>
+#define ALIGN_UP_TO_PAGE_SIZE(p) \
+ (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
/*
* Print a hex dump in this format:
@@ -323,7 +327,7 @@
*/
int dvmCountSetBits(const BitVector* pBits)
{
- int word, bit;
+ int word;
int count = 0;
for (word = 0; word < pBits->storageSize; word++) {
@@ -686,3 +690,28 @@
return srcLength;
}
#endif
+
+/*
+ * Allocates a memory region using ashmem and mmap, initialized to
+ * zero. Actual allocation rounded up to page multiple. Returns
+ * NULL on failure.
+ */
+void *dvmAllocRegion(size_t size, int prot, const char *name) {
+ void *base;
+ int fd, ret;
+
+ size = ALIGN_UP_TO_PAGE_SIZE(size);
+ fd = ashmem_create_region(name, size);
+ if (fd == -1) {
+ return NULL;
+ }
+ base = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0);
+ ret = close(fd);
+ if (base == MAP_FAILED) {
+ return NULL;
+ }
+ if (ret == -1) {
+ return NULL;
+ }
+ return base;
+}
diff --git a/vm/Misc.h b/vm/Misc.h
index 3e04f84..358a97b 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -231,6 +231,18 @@
}
/*
+ * Get the current time, in milliseconds. This is "relative" time,
+ * meaning it could be wall-clock time or a monotonic counter, and is
+ * only suitable for computing time deltas. The value returned from
+ * this function is a u4 and should only be used for debugging
+ * messages. TODO: make this value relative to the start-up time of
+ * the VM.
+ */
+INLINE u4 dvmGetRelativeTimeMsec(void) {
+ return (u4)(dvmGetRelativeTimeUsec() / 1000);
+}
+
+/*
* Get the current per-thread CPU time. This clock increases monotonically
* when the thread is running, but not when it's sleeping or blocked on a
* synchronization object.
@@ -287,4 +299,11 @@
size_t strlcpy(char *dst, const char *src, size_t size);
#endif
+/*
+ * Allocates a memory region using ashmem and mmap, initialized to
+ * zero. Actual allocation rounded up to page multiple. Returns
+ * NULL on failure.
+ */
+void *dvmAllocRegion(size_t size, int prot, const char *name);
+
#endif /*_DALVIK_MISC*/
diff --git a/vm/Native.c b/vm/Native.c
index 967482c..4793ab3 100644
--- a/vm/Native.c
+++ b/vm/Native.c
@@ -57,7 +57,7 @@
*
* This is executed as if it were a native bridge or function. If the
* resolution succeeds, method->insns is replaced, and we don't go through
- * here again.
+ * here again unless the method is unregistered.
*
* Initializes method's class if necessary.
*
@@ -103,8 +103,7 @@
dvmAbort(); // harsh, but this is VM-internal problem
}
DalvikBridgeFunc dfunc = (DalvikBridgeFunc) func;
- dvmSetNativeFunc(method, dfunc, NULL);
- assert(method->insns == NULL);
+ dvmSetNativeFunc((Method*) method, dfunc, NULL);
dfunc(args, pResult, method, self);
return;
}
@@ -213,7 +212,6 @@
static SharedLib* addSharedLibEntry(SharedLib* pLib)
{
u4 hash = dvmComputeUtf8Hash(pLib->pathName);
- void* ent;
/*
* Do the lookup with the "add" flag set. If we add it, we will get
@@ -408,7 +406,7 @@
while (pEntry->onLoadResult == kOnLoadPending) {
LOGD("threadid=%d: waiting for %s OnLoad status\n",
self->threadId, pEntry->pathName);
- int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
pthread_cond_wait(&pEntry->onLoadCond, &pEntry->onLoadLock);
dvmChangeStatus(self, oldStatus);
}
@@ -500,7 +498,7 @@
* the GC to ignore us.
*/
Thread* self = dvmThreadSelf();
- int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
handle = dlopen(pathName, RTLD_LAZY);
dvmChangeStatus(self, oldStatus);
@@ -595,6 +593,71 @@
/*
+ * Un-register JNI native methods.
+ *
+ * There are two relevant fields in struct Method, "nativeFunc" and
+ * "insns". The former holds a function pointer to a "bridge" function
+ * (or, for internal native, the actual implementation). The latter holds
+ * a pointer to the actual JNI method.
+ *
+ * The obvious approach is to reset both fields to their initial state
+ * (nativeFunc points at dvmResolveNativeMethod, insns holds NULL), but
+ * that creates some unpleasant race conditions. In particular, if another
+ * thread is executing inside the call bridge for the method in question,
+ * and we reset insns to NULL, the VM will crash. (See the comments above
+ * dvmSetNativeFunc() for additional commentary.)
+ *
+ * We can't rely on being able to update two 32-bit fields in one atomic
+ * operation (e.g. no 64-bit atomic ops on ARMv5TE), so we want to change
+ * only one field. It turns out we can simply reset nativeFunc to its
+ * initial state, leaving insns alone, because dvmResolveNativeMethod
+ * ignores "insns" entirely.
+ *
+ * When the method is re-registered, both fields will be updated, but
+ * dvmSetNativeFunc guarantees that "insns" is updated first. This means
+ * we shouldn't be in a situation where we have a "live" call bridge and
+ * a stale implementation pointer.
+ */
+static void unregisterJNINativeMethods(Method* methods, size_t count)
+{
+ while (count != 0) {
+ count--;
+
+ Method* meth = &methods[count];
+ if (!dvmIsNativeMethod(meth))
+ continue;
+ if (dvmIsAbstractMethod(meth)) /* avoid abstract method stubs */
+ continue;
+
+ /*
+ * Strictly speaking this ought to test the function pointer against
+ * the various JNI bridge functions to ensure that we only undo
+ * methods that were registered through JNI. In practice, any
+ * native method with a non-NULL "insns" is a registered JNI method.
+ *
+ * If we inadvertently unregister an internal-native, it'll get
+ * re-resolved on the next call; unregistering an unregistered
+ * JNI method is a no-op. So we don't really need to test for
+ * anything.
+ */
+
+ LOGD("Unregistering JNI method %s.%s:%s\n",
+ meth->clazz->descriptor, meth->name, meth->shorty);
+ dvmSetNativeFunc(meth, dvmResolveNativeMethod, NULL);
+ }
+}
+
+/*
+ * Un-register all JNI native methods from a class.
+ */
+void dvmUnregisterJNINativeMethods(ClassObject* clazz)
+{
+ unregisterJNINativeMethods(clazz->directMethods, clazz->directMethodCount);
+ unregisterJNINativeMethods(clazz->virtualMethods, clazz->virtualMethodCount);
+}
+
+
+/*
* ===========================================================================
* Signature-based method lookup
* ===========================================================================
@@ -817,3 +880,113 @@
(void*) method);
}
+
+static void appendValue(char type, const JValue value, char* buf, size_t n,
+ bool appendComma)
+{
+ size_t len = strlen(buf);
+ if (len >= n - 32) { // 32 should be longer than anything we could append.
+ buf[len - 1] = '.';
+ buf[len - 2] = '.';
+ buf[len - 3] = '.';
+ return;
+ }
+ char* p = buf + len;
+ switch (type) {
+ case 'B':
+ if (value.b >= 0 && value.b < 10) {
+ sprintf(p, "%d", value.b);
+ } else {
+ sprintf(p, "0x%x (%d)", value.b, value.b);
+ }
+ break;
+ case 'C':
+ if (value.c < 0x7f && value.c >= ' ') {
+ sprintf(p, "U+%x ('%c')", value.c, value.c);
+ } else {
+ sprintf(p, "U+%x", value.c);
+ }
+ break;
+ case 'D':
+ sprintf(p, "%g", value.d);
+ break;
+ case 'F':
+ sprintf(p, "%g", value.f);
+ break;
+ case 'I':
+ sprintf(p, "%d", value.i);
+ break;
+ case 'L':
+ sprintf(p, "0x%x", value.i);
+ break;
+ case 'J':
+ sprintf(p, "%lld", value.j);
+ break;
+ case 'S':
+ sprintf(p, "%d", value.s);
+ break;
+ case 'V':
+ strcpy(p, "void");
+ break;
+ case 'Z':
+ strcpy(p, value.z ? "true" : "false");
+ break;
+ default:
+ sprintf(p, "unknown type '%c'", type);
+ break;
+ }
+
+ if (appendComma) {
+ strcat(p, ", ");
+ }
+}
+
+#define LOGI_NATIVE(...) LOG(LOG_INFO, LOG_TAG "-native", __VA_ARGS__)
+
+void dvmLogNativeMethodEntry(const Method* method, const u4* args)
+{
+ char thisString[32] = { 0 };
+ const u4* sp = args; // &args[method->registersSize - method->insSize];
+ if (!dvmIsStaticMethod(method)) {
+ sprintf(thisString, "this=0x%08x ", *sp++);
+ }
+
+ char argsString[128]= { 0 };
+ const char* desc = &method->shorty[1];
+ while (*desc != '\0') {
+ char argType = *desc++;
+ JValue value;
+ if (argType == 'D' || argType == 'J') {
+ value.j = dvmGetArgLong(sp, 0);
+ sp += 2;
+ } else {
+ value.i = *sp++;
+ }
+ appendValue(argType, value, argsString, sizeof(argsString),
+ *desc != '\0');
+ }
+
+ char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
+ LOGI_NATIVE("-> %s.%s%s %s(%s)", method->clazz->descriptor, method->name,
+ signature, thisString, argsString);
+ free(signature);
+}
+
+void dvmLogNativeMethodExit(const Method* method, Thread* self,
+ const JValue returnValue)
+{
+ char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
+ if (dvmCheckException(self)) {
+ Object* exception = dvmGetException(self);
+ LOGI_NATIVE("<- %s.%s%s threw %s", method->clazz->descriptor,
+ method->name, signature, exception->clazz->descriptor);
+ } else {
+ char returnValueString[128] = { 0 };
+ char returnType = method->shorty[0];
+ appendValue(returnType, returnValue,
+ returnValueString, sizeof(returnValueString), false);
+ LOGI_NATIVE("<- %s.%s%s returned %s", method->clazz->descriptor,
+ method->name, signature, returnValueString);
+ }
+ free(signature);
+}
diff --git a/vm/Native.h b/vm/Native.h
index 5b54fc7..a5e9ca1 100644
--- a/vm/Native.h
+++ b/vm/Native.h
@@ -78,6 +78,11 @@
void dvmResolveNativeMethod(const u4* args, JValue* pResult,
const Method* method, struct Thread* self);
+/*
+ * Unregister all JNI native methods associated with a class.
+ */
+void dvmUnregisterJNINativeMethods(ClassObject* clazz);
+
//#define GET_ARG_LONG(_args, _elem) (*(s8*)(&(_args)[_elem]))
#define GET_ARG_LONG(_args, _elem) dvmGetArgLong(_args, _elem)
@@ -105,4 +110,12 @@
#endif
}
+/*
+ * Used to implement -Xjnitrace.
+ */
+struct Thread;
+void dvmLogNativeMethodEntry(const Method* method, const u4* newFp);
+void dvmLogNativeMethodExit(const Method* method, struct Thread* self,
+ const JValue retval);
+
#endif /*_DALVIK_NATIVE*/
diff --git a/vm/PointerSet.c b/vm/PointerSet.c
index 6cc6e79..1d2e814 100644
--- a/vm/PointerSet.c
+++ b/vm/PointerSet.c
@@ -30,6 +30,7 @@
/*
* Verify that the set is in sorted order.
*/
+#ifndef NDEBUG
static bool verifySorted(PointerSet* pSet)
{
const void* last = NULL;
@@ -44,7 +45,7 @@
return true;
}
-
+#endif
/*
* Allocate a new PointerSet.
@@ -181,7 +182,7 @@
*/
bool dvmPointerSetRemoveEntry(PointerSet* pSet, const void* ptr)
{
- int i, where;
+ int where;
if (!dvmPointerSetHas(pSet, ptr, &where))
return false;
@@ -270,4 +271,3 @@
for (i = 0; i < pSet->count; i++)
printf(" %p", pSet->list[i]);
}
-
diff --git a/vm/Profile.c b/vm/Profile.c
index b079988..57c96df 100644
--- a/vm/Profile.c
+++ b/vm/Profile.c
@@ -227,7 +227,8 @@
LOGE("Can't have %d active profilers\n", newValue);
dvmAbort();
}
- } while (!ATOMIC_CMP_SWAP(&gDvm.activeProfilers, oldValue, newValue));
+ } while (android_atomic_release_cas(oldValue, newValue,
+ &gDvm.activeProfilers) != 0);
LOGD("+++ active profiler count now %d\n", newValue);
#if defined(WITH_JIT)
@@ -278,7 +279,7 @@
FILE* fp = (FILE*) vfp;
Method* meth;
char* name;
- int i, lineNum;
+ int i;
dexStringCacheInit(&stringCache);
@@ -328,7 +329,8 @@
* trace all threads).
*
* This opens the output file (if an already open fd has not been supplied,
- * and we're not going direct to DDMS) and allocates the data buffer.
+ * and we're not going direct to DDMS) and allocates the data buffer. This
+ * takes ownership of the file descriptor, closing it on completion.
*
* On failure, we throw an exception and return.
*/
@@ -376,6 +378,7 @@
goto fail;
}
}
+ traceFd = -1;
memset(state->buf, (char)FILL_PATTERN, bufferSize);
state->directToDdms = directToDdms;
@@ -404,7 +407,7 @@
storeLongLE(state->buf + 8, state->startWhen);
state->curOffset = TRACE_HEADER_LEN;
- MEM_BARRIER();
+ ANDROID_MEMBAR_FULL();
/*
* Set the "enabled" flag. Once we do this, threads will wait to be
@@ -424,6 +427,8 @@
free(state->buf);
state->buf = NULL;
}
+ if (traceFd >= 0)
+ close(traceFd);
dvmUnlockMutex(&state->startStopLock);
}
@@ -519,7 +524,7 @@
* after that completes.
*/
state->traceEnabled = false;
- MEM_BARRIER();
+ ANDROID_MEMBAR_FULL();
sched_yield();
usleep(250 * 1000);
@@ -641,7 +646,8 @@
/* append the profiling data */
if (fwrite(state->buf, finalCurOffset, 1, state->traceFile) != 1) {
int err = errno;
- LOGE("trace fwrite(%d) failed, errno=%d\n", finalCurOffset, err);
+ LOGE("trace fwrite(%d) failed: %s\n",
+ finalCurOffset, strerror(err));
dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
"Trace data write failed: %s", strerror(err));
}
@@ -654,8 +660,7 @@
state->traceFile = NULL;
/* wake any threads that were waiting for profiling to complete */
- int cc = pthread_cond_broadcast(&state->threadExitCond);
- assert(cc == 0);
+ dvmBroadcastCond(&state->threadExitCond);
dvmUnlockMutex(&state->startStopLock);
}
@@ -696,7 +701,8 @@
state->overflow = true;
return;
}
- } while (!ATOMIC_CMP_SWAP(&state->curOffset, oldOffset, newOffset));
+ } while (android_atomic_release_cas(oldOffset, newOffset,
+ &state->curOffset) != 0);
//assert(METHOD_ACTION((u4) method) == 0);
diff --git a/vm/Properties.c b/vm/Properties.c
index 91288c2..288085b 100644
--- a/vm/Properties.c
+++ b/vm/Properties.c
@@ -111,8 +111,8 @@
value = "";
}
- keyStr = dvmCreateStringFromCstr(key, ALLOC_DEFAULT);
- valueStr = dvmCreateStringFromCstr(value, ALLOC_DEFAULT);
+ keyStr = dvmCreateStringFromCstr(key);
+ valueStr = dvmCreateStringFromCstr(value);
if (keyStr == NULL || valueStr == NULL) {
LOGW("setProperty string creation failed\n");
goto bail;
@@ -199,7 +199,7 @@
setProperty(propObj, put, "file.separator", "/");
setProperty(propObj, put, "line.separator", "\n");
setProperty(propObj, put, "path.separator", ":");
-
+
/*
* These show up elsewhere, so do them here too.
*/
@@ -265,7 +265,7 @@
goto bail;
}
- keyObj = dvmCreateStringFromCstr(key, ALLOC_DEFAULT);
+ keyObj = dvmCreateStringFromCstr(key);
if (keyObj == NULL)
goto bail;
diff --git a/vm/README.txt b/vm/README.txt
index e00e240..1be1a63 100644
--- a/vm/README.txt
+++ b/vm/README.txt
@@ -17,4 +17,3 @@
work correctly.
- Use of gcc-specific and C99 constructs is allowed.
-
diff --git a/vm/RawDexFile.c b/vm/RawDexFile.c
index c55fee6..3402ff4 100644
--- a/vm/RawDexFile.c
+++ b/vm/RawDexFile.c
@@ -41,4 +41,3 @@
free(pRawDexFile->cacheFileName);
free(pRawDexFile);
}
-
diff --git a/vm/ReferenceTable.c b/vm/ReferenceTable.c
index 310669d..8984d5f 100644
--- a/vm/ReferenceTable.c
+++ b/vm/ReferenceTable.c
@@ -291,4 +291,3 @@
LOGW("Memory held directly by tracked refs is %d bytes\n", total);
free(tableCopy);
}
-
diff --git a/vm/SignalCatcher.c b/vm/SignalCatcher.c
index 2b994da..d270b6f 100644
--- a/vm/SignalCatcher.c
+++ b/vm/SignalCatcher.c
@@ -211,21 +211,12 @@
}
/*
- * Respond to a SIGUSR1 by forcing a GC. If we were built with HPROF
- * support, generate an HPROF dump file.
- *
- * (The HPROF dump generation is not all that useful now that we have
- * better ways to generate it. Consider removing this in a future release.)
+ * Respond to a SIGUSR1 by forcing a GC.
*/
static void handleSigUsr1(void)
{
-#if WITH_HPROF
- LOGI("SIGUSR1 forcing GC and HPROF dump\n");
- hprofDumpHeap(NULL, false);
-#else
LOGI("SIGUSR1 forcing GC (no HPROF)\n");
dvmCollectGarbage(false);
-#endif
}
#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
diff --git a/vm/StdioConverter.c b/vm/StdioConverter.c
index 54ceb0b..6a4d845 100644
--- a/vm/StdioConverter.c
+++ b/vm/StdioConverter.c
@@ -109,9 +109,7 @@
/* new thread owns pipeStorage */
while (!gDvm.stdioConverterReady) {
- int cc = pthread_cond_wait(&gDvm.stdioConverterCond,
- &gDvm.stdioConverterLock);
- assert(cc == 0);
+ dvmWaitCond(&gDvm.stdioConverterCond, &gDvm.stdioConverterLock);
}
dvmUnlockMutex(&gDvm.stdioConverterLock);
@@ -145,7 +143,6 @@
*/
static void* stdioConverterThreadStart(void* arg)
{
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
StdPipes* pipeStorage = (StdPipes*) arg;
BufferedData* stdoutData;
BufferedData* stderrData;
@@ -172,7 +169,6 @@
* Read until shutdown time.
*/
while (!gDvm.haltStdioConverter) {
- ssize_t actual;
fd_set readfds;
int maxFd, fdCount;
@@ -220,7 +216,6 @@
/* change back for shutdown sequence */
dvmChangeStatus(NULL, THREAD_RUNNING);
return NULL;
-#undef MAX
}
/*
@@ -289,4 +284,3 @@
return true;
}
-
diff --git a/vm/StdioConverter.h b/vm/StdioConverter.h
index eef4a72..ffbf807 100644
--- a/vm/StdioConverter.h
+++ b/vm/StdioConverter.h
@@ -23,4 +23,3 @@
void dvmStdioConverterShutdown(void);
#endif /*_DALVIK_STDOUTCONVERTER*/
-
diff --git a/vm/Sync.c b/vm/Sync.c
index ebf2ad0..2223c48 100644
--- a/vm/Sync.c
+++ b/vm/Sync.c
@@ -170,8 +170,8 @@
/* replace the head of the list with the new monitor */
do {
mon->next = gDvm.monitorList;
- } while (!ATOMIC_CMP_SWAP((int32_t*)(void*)&gDvm.monitorList,
- (int32_t)mon->next, (int32_t)mon));
+ } while (android_atomic_release_cas((int32_t)mon->next, (int32_t)mon,
+ (int32_t*)(void*)&gDvm.monitorList) != 0);
return mon;
}
@@ -312,7 +312,8 @@
* native code somewhere.
*/
assert(pthread_mutex_trylock(&mon->lock) == 0);
- pthread_mutex_destroy(&mon->lock);
+ assert(pthread_mutex_unlock(&mon->lock) == 0);
+ dvmDestroyMutex(&mon->lock);
#ifdef WITH_DEADLOCK_PREDICTION
expandObjClear(&mon->historyChildren);
expandObjClear(&mon->historyParents);
@@ -331,7 +332,6 @@
Object *obj;
assert(mon != NULL);
- assert(*mon != NULL);
assert(isUnmarkedObject != NULL);
prev = &handle;
prev->next = curr = *mon;
@@ -374,7 +374,7 @@
u4 relativePc;
char eventBuffer[132];
const char *fileName;
- char procName[33], *selfName, *ownerName;
+ char procName[33], *selfName;
char *cp;
size_t len;
int fd;
@@ -430,7 +430,6 @@
*/
static void lockMonitor(Thread* self, Monitor* mon)
{
- Thread *owner;
ThreadStatus oldStatus;
u4 waitThreshold, samplePercent;
u8 waitStart, waitEnd, waitMs;
@@ -439,7 +438,7 @@
mon->lockCount++;
return;
}
- if (pthread_mutex_trylock(&mon->lock) != 0) {
+ if (dvmTryLockMutex(&mon->lock) != 0) {
oldStatus = dvmChangeStatus(self, THREAD_MONITOR);
waitThreshold = gDvm.lockProfThreshold;
if (waitThreshold) {
@@ -471,16 +470,14 @@
*
* Returns "true" on success.
*/
+#ifdef WITH_COPYING_GC
static bool tryLockMonitor(Thread* self, Monitor* mon)
{
- int cc;
-
if (mon->owner == self) {
mon->lockCount++;
return true;
} else {
- cc = pthread_mutex_trylock(&mon->lock);
- if (cc == 0) {
+ if (dvmTryLockMutex(&mon->lock) == 0) {
mon->owner = self;
assert(mon->lockCount == 0);
return true;
@@ -489,7 +486,7 @@
}
}
}
-
+#endif
/*
* Unlock a monitor.
@@ -500,17 +497,14 @@
static bool unlockMonitor(Thread* self, Monitor* mon)
{
assert(self != NULL);
- assert(mon != NULL); // can this happen?
-
+ assert(mon != NULL);
if (mon->owner == self) {
/*
* We own the monitor, so nobody else can be in here.
*/
if (mon->lockCount == 0) {
- int cc;
mon->owner = NULL;
- cc = pthread_mutex_unlock(&mon->lock);
- assert(cc == 0);
+ dvmUnlockMutex(&mon->lock);
} else {
mon->lockCount--;
}
@@ -531,6 +525,7 @@
* Checks the wait set for circular structure. Returns 0 if the list
* is not circular. Otherwise, returns 1. Used only by asserts.
*/
+#ifndef NDEBUG
static int waitSetCheck(Monitor *mon)
{
Thread *fast, *slow;
@@ -548,6 +543,7 @@
slow = slow->waitNext;
}
}
+#endif
/*
* Links a thread into a monitor's wait set. The monitor lock must be
@@ -736,8 +732,7 @@
else
dvmChangeStatus(self, THREAD_WAIT);
- ret = pthread_mutex_lock(&self->waitMutex);
- assert(ret == 0);
+ dvmLockMutex(&self->waitMutex);
/*
* Set waitMonitor to the monitor object we will be waiting on.
@@ -754,7 +749,7 @@
if (self->interrupted) {
wasInterrupted = true;
self->waitMonitor = NULL;
- pthread_mutex_unlock(&self->waitMutex);
+ dvmUnlockMutex(&self->waitMutex);
goto done;
}
@@ -762,7 +757,7 @@
* Release the monitor lock and wait for a notification or
* a timeout to occur.
*/
- pthread_mutex_unlock(&mon->lock);
+ dvmUnlockMutex(&mon->lock);
if (!timed) {
ret = pthread_cond_wait(&self->waitCond, &self->waitMutex);
@@ -782,7 +777,7 @@
self->interrupted = false;
self->waitMonitor = NULL;
- pthread_mutex_unlock(&self->waitMutex);
+ dvmUnlockMutex(&self->waitMutex);
/* Reacquire the monitor lock. */
lockMonitor(self, mon);
@@ -836,14 +831,14 @@
thread = mon->waitSet;
mon->waitSet = thread->waitNext;
thread->waitNext = NULL;
- pthread_mutex_lock(&thread->waitMutex);
+ dvmLockMutex(&thread->waitMutex);
/* Check to see if the thread is still waiting. */
if (thread->waitMonitor != NULL) {
pthread_cond_signal(&thread->waitCond);
- pthread_mutex_unlock(&thread->waitMutex);
+ dvmUnlockMutex(&thread->waitMutex);
return;
}
- pthread_mutex_unlock(&thread->waitMutex);
+ dvmUnlockMutex(&thread->waitMutex);
}
}
@@ -868,16 +863,41 @@
thread = mon->waitSet;
mon->waitSet = thread->waitNext;
thread->waitNext = NULL;
- pthread_mutex_lock(&thread->waitMutex);
+ dvmLockMutex(&thread->waitMutex);
/* Check to see if the thread is still waiting. */
if (thread->waitMonitor != NULL) {
pthread_cond_signal(&thread->waitCond);
}
- pthread_mutex_unlock(&thread->waitMutex);
+ dvmUnlockMutex(&thread->waitMutex);
}
}
/*
+ * Changes the shape of a monitor from thin to fat, preserving the
+ * internal lock state. The calling thread must own the lock.
+ */
+static void inflateMonitor(Thread *self, Object *obj)
+{
+ Monitor *mon;
+ u4 thin;
+
+ assert(self != NULL);
+ assert(obj != NULL);
+ assert(LW_SHAPE(obj->lock) == LW_SHAPE_THIN);
+ assert(LW_LOCK_OWNER(obj->lock) == self->threadId);
+ /* Allocate and acquire a new monitor. */
+ mon = dvmCreateMonitor(obj);
+ lockMonitor(self, mon);
+ /* Propagate the lock state. */
+ thin = obj->lock;
+ mon->lockCount = LW_LOCK_COUNT(thin);
+ thin &= LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT;
+ thin |= (u4)mon | LW_SHAPE_FAT;
+ /* Publish the updated lock word. */
+ android_atomic_release_store(thin, (int32_t *)&obj->lock);
+}
+
+/*
* Implements monitorenter for "synchronized" stuff.
*
* This does not fail or throw an exception (unless deadlock prediction
@@ -886,7 +906,6 @@
void dvmLockObject(Thread* self, Object *obj)
{
volatile u4 *thinp;
- Monitor *mon;
ThreadStatus oldStatus;
useconds_t sleepDelay;
const useconds_t maxSleepDelay = 1 << 20;
@@ -909,6 +928,14 @@
* value of the recursion count field.
*/
obj->lock += 1 << LW_LOCK_COUNT_SHIFT;
+ if (LW_LOCK_COUNT(obj->lock) == LW_LOCK_COUNT_MASK) {
+ /*
+ * The reacquisition limit has been reached. Inflate
+ * the lock so the next acquire will not overflow the
+ * recursion count field.
+ */
+ inflateMonitor(self, obj);
+ }
} else if (LW_LOCK_OWNER(thin) == 0) {
/*
* The lock is unowned. Install the thread id of the
@@ -917,7 +944,8 @@
* will have tried this before calling out to the VM.
*/
newThin = thin | (threadId << LW_LOCK_OWNER_SHIFT);
- if (!ATOMIC_CMP_SWAP((int32_t *)thinp, thin, newThin)) {
+ if (android_atomic_release_cas(thin, newThin,
+ (int32_t*)thinp) != 0) {
/*
* The acquire failed. Try again.
*/
@@ -949,8 +977,8 @@
* owner field.
*/
newThin = thin | (threadId << LW_LOCK_OWNER_SHIFT);
- if (ATOMIC_CMP_SWAP((int32_t *)thinp,
- thin, newThin)) {
+ if (android_atomic_release_cas(thin, newThin,
+ (int32_t *)thinp) == 0) {
/*
* The acquire succeed. Break out of the
* loop and proceed to inflate the lock.
@@ -994,13 +1022,7 @@
/*
* Fatten the lock.
*/
- mon = dvmCreateMonitor(obj);
- lockMonitor(self, mon);
- thin = *thinp;
- thin &= LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT;
- thin |= (u4)mon | LW_SHAPE_FAT;
- MEM_BARRIER();
- obj->lock = thin;
+ inflateMonitor(self, obj);
LOG_THIN("(%d) lock %p fattened", threadId, &obj->lock);
}
} else {
@@ -1142,8 +1164,7 @@
void dvmObjectWait(Thread* self, Object *obj, s8 msec, s4 nsec,
bool interruptShouldThrow)
{
- Monitor* mon = LW_MONITOR(obj->lock);
- u4 hashState;
+ Monitor* mon;
u4 thin = obj->lock;
/* If the lock is still thin, we need to fatten it.
@@ -1162,25 +1183,11 @@
* field yet, because 'self' needs to acquire the lock before
* any other thread gets a chance.
*/
- mon = dvmCreateMonitor(obj);
-
- /* 'self' has actually locked the object one or more times;
- * make sure that the monitor reflects this.
- */
- lockMonitor(self, mon);
- mon->lockCount = LW_LOCK_COUNT(thin);
- LOG_THIN("(%d) lock 0x%08x fattened by wait() to count %d\n",
- self->threadId, (uint)&obj->lock, mon->lockCount);
-
-
- /* Make the monitor public now that it's in the right state.
- */
- thin &= LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT;
- thin |= (u4)mon | LW_SHAPE_FAT;
- MEM_BARRIER();
- obj->lock = thin;
+ inflateMonitor(self, obj);
+ LOG_THIN("(%d) lock %p fattened by wait() to count %d",
+ self->threadId, &obj->lock, mon->lockCount);
}
-
+ mon = LW_MONITOR(obj->lock);
waitMonitor(self, mon, msec, nsec, interruptShouldThrow);
}
@@ -1275,14 +1282,14 @@
{
assert(thread != NULL);
- pthread_mutex_lock(&thread->waitMutex);
+ dvmLockMutex(&thread->waitMutex);
/*
* If the interrupted flag is already set no additional action is
* required.
*/
if (thread->interrupted == true) {
- pthread_mutex_unlock(&thread->waitMutex);
+ dvmUnlockMutex(&thread->waitMutex);
return;
}
@@ -1292,7 +1299,6 @@
* something.
*/
thread->interrupted = true;
- MEM_BARRIER();
/*
* Is the thread waiting?
@@ -1305,7 +1311,7 @@
pthread_cond_signal(&thread->waitCond);
}
- pthread_mutex_unlock(&thread->waitMutex);
+ dvmUnlockMutex(&thread->waitMutex);
}
#ifndef WITH_COPYING_GC
@@ -1314,40 +1320,6 @@
return (u4)obj;
}
#else
-static size_t arrayElementWidth(const ArrayObject *array)
-{
- const char *descriptor;
-
- if (dvmIsObjectArray(array)) {
- return sizeof(Object *);
- } else {
- descriptor = array->obj.clazz->descriptor;
- switch (descriptor[1]) {
- case 'B': return 1; /* byte */
- case 'C': return 2; /* char */
- case 'D': return 8; /* double */
- case 'F': return 4; /* float */
- case 'I': return 4; /* int */
- case 'J': return 8; /* long */
- case 'S': return 2; /* short */
- case 'Z': return 1; /* boolean */
- }
- }
- LOGE("object %p has an unhandled descriptor '%s'", array, descriptor);
- dvmDumpThread(dvmThreadSelf(), false);
- dvmAbort();
- return 0; /* Quiet the compiler. */
-}
-
-static size_t arrayObjectLength(const ArrayObject *array)
-{
- size_t length;
-
- length = offsetof(ArrayObject, contents);
- length += array->length * arrayElementWidth(array);
- return length;
-}
-
/*
* Returns the identity hash code of the given object.
*/
@@ -1355,7 +1327,7 @@
{
Thread *self, *thread;
volatile u4 *lw;
- size_t length;
+ size_t size;
u4 lock, owner, hashState;
if (obj == NULL) {
@@ -1380,13 +1352,14 @@
* relocated by the collector. Use the value of the naturally
* aligned word following the instance data.
*/
+ assert(obj->clazz != gDvm.classJavaLangClass);
if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
- length = arrayObjectLength((ArrayObject *)obj);
- length = (length + 3) & ~3;
+ size = dvmArrayObjectSize((ArrayObject *)obj);
+ size = (size + 2) & ~2;
} else {
- length = obj->clazz->objectSize;
+ size = obj->clazz->objectSize;
}
- return *(u4 *)(((char *)obj) + length);
+ return *(u4 *)(((char *)obj) + size);
} else if (hashState == LW_HASH_STATE_UNHASHED) {
/*
* The object has never been hashed. Change the hash state to
@@ -1412,9 +1385,10 @@
*/
lock = DVM_LOCK_INITIAL_THIN_VALUE;
lock |= (LW_HASH_STATE_HASHED << LW_HASH_STATE_SHIFT);
- if (ATOMIC_CMP_SWAP((int32_t *)lw,
+ if (android_atomic_release_cas(
(int32_t)DVM_LOCK_INITIAL_THIN_VALUE,
- (int32_t)lock)) {
+ (int32_t)lock,
+ (int32_t *)lw) == 0) {
/*
* A new lockword has been installed with a hash state
* of hashed. Use the raw object address.
@@ -1911,11 +1885,7 @@
if (!IS_LOCK_FAT(&acqObj->lock)) {
LOGVV("fattening lockee %p (recur=%d)\n",
acqObj, LW_LOCK_COUNT(acqObj->lock.thin));
- Monitor* newMon = dvmCreateMonitor(acqObj);
- lockMonitor(self, newMon); // can't stall, don't need VMWAIT
- newMon->lockCount += LW_LOCK_COUNT(acqObj->lock);
- u4 hashState = LW_HASH_STATE(acqObj->lock) << LW_HASH_STATE_SHIFT;
- acqObj->lock = (u4)newMon | hashState | LW_SHAPE_FAT;
+ inflateMonitor(self, acqObj);
}
/* if we don't have a stack trace for this monitor, establish one */
@@ -1959,11 +1929,7 @@
if (!IS_LOCK_FAT(&mrl->obj->lock)) {
LOGVV("fattening parent %p f/b/o child %p (recur=%d)\n",
mrl->obj, acqObj, LW_LOCK_COUNT(mrl->obj->lock));
- Monitor* newMon = dvmCreateMonitor(mrl->obj);
- lockMonitor(self, newMon); // can't stall, don't need VMWAIT
- newMon->lockCount += LW_LOCK_COUNT(mrl->obj->lock);
- u4 hashState = LW_HASH_STATE(mrl->obj->lock) << LW_HASH_STATE_SHIFT;
- mrl->obj->lock = (u4)newMon | hashState | LW_SHAPE_FAT;
+ inflateMonitor(self, mrl->obj);
}
/*
@@ -2055,26 +2021,6 @@
LOGVV("+++ collecting %p\n", obj);
-#if 0
- /*
- * We're currently running through the entire set of known monitors.
- * This can be somewhat slow. We may want to keep lists of parents
- * in each child to speed up GC.
- */
- mon = gDvm.monitorList;
- while (mon != NULL) {
- Object* parent = mon->obj;
- if (parent != NULL) { /* value nulled for deleted entries */
- if (objectInChildList(parent, obj)) {
- LOGVV("removing child %p from parent %p\n", obj, parent);
- unlinkParentFromChild(parent, obj);
- mergeChildren(parent, obj);
- }
- }
- mon = mon->next;
- }
-#endif
-
/*
* For every parent of this object:
* - merge all of our children into the parent's child list (creates
diff --git a/vm/Thread.c b/vm/Thread.c
index 50f5416..40c79c4 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -449,8 +449,7 @@
* This lock is always held for very brief periods, so as long as
* mutex ordering is respected we shouldn't stall.
*/
- int cc = pthread_mutex_lock(&gDvm.threadSuspendCountLock);
- assert(cc == 0);
+ dvmLockMutex(&gDvm.threadSuspendCountLock);
}
/*
@@ -494,8 +493,7 @@
oldStatus = -1; // shut up gcc
}
- int cc = pthread_mutex_lock(&gDvm.threadListLock);
- assert(cc == 0);
+ dvmLockMutex(&gDvm.threadListLock);
if (self != NULL)
self->status = oldStatus;
@@ -506,8 +504,7 @@
*/
void dvmUnlockThreadList(void)
{
- int cc = pthread_mutex_unlock(&gDvm.threadListLock);
- assert(cc == 0);
+ dvmUnlockMutex(&gDvm.threadListLock);
}
/*
@@ -521,6 +518,7 @@
case SUSPEND_FOR_DEBUG: return "debug";
case SUSPEND_FOR_DEBUG_EVENT: return "debug-event";
case SUSPEND_FOR_STACK_DUMP: return "stack-dump";
+ case SUSPEND_FOR_VERIFY: return "verify";
#if defined(WITH_JIT)
case SUSPEND_FOR_TBL_RESIZE: return "table-resize";
case SUSPEND_FOR_IC_PATCH: return "inline-cache-patch";
@@ -547,9 +545,11 @@
int cc;
do {
- cc = pthread_mutex_trylock(&gDvm._threadSuspendLock);
+ cc = dvmTryLockMutex(&gDvm._threadSuspendLock);
if (cc != 0) {
- if (!dvmCheckSuspendPending(NULL)) {
+ Thread* self = dvmThreadSelf();
+
+ if (!dvmCheckSuspendPending(self)) {
/*
* Could be that a resume-all is in progress, and something
* grabbed the CPU when the wakeup was broadcast. The thread
@@ -571,7 +571,7 @@
*/
LOGI("threadid=%d ODD: want thread-suspend lock (%s:%s),"
" it's held, no suspend pending\n",
- dvmThreadSelf()->threadId, who, getSuspendCauseStr(why));
+ self->threadId, who, getSuspendCauseStr(why));
} else {
/* we suspended; reset timeout */
sleepIter = 0;
@@ -583,7 +583,7 @@
if (!dvmIterativeSleep(sleepIter++, kSpinSleepTime, startWhen)) {
LOGE("threadid=%d: couldn't get thread-suspend lock (%s:%s),"
" bailing\n",
- dvmThreadSelf()->threadId, who, getSuspendCauseStr(why));
+ self->threadId, who, getSuspendCauseStr(why));
/* threads are not suspended, thread dump could crash */
dvmDumpAllThreads(false);
dvmAbort();
@@ -598,8 +598,7 @@
*/
static inline void unlockThreadSuspend(void)
{
- int cc = pthread_mutex_unlock(&gDvm._threadSuspendLock);
- assert(cc == 0);
+ dvmUnlockMutex(&gDvm._threadSuspendLock);
}
@@ -630,7 +629,6 @@
int threadId = 0;
bool doWait = false;
- //dvmEnterCritical(self);
dvmLockThreadList(self);
if (self != NULL)
@@ -821,7 +819,7 @@
}
dvmReleaseTrackedAlloc(threadObj, NULL);
- threadNameStr = dvmCreateStringFromCstr("main", ALLOC_DEFAULT);
+ threadNameStr = dvmCreateStringFromCstr("main");
if (threadNameStr == NULL)
return false;
dvmReleaseTrackedAlloc((Object*)threadNameStr, NULL);
@@ -900,12 +898,7 @@
/*
* Alloc and initialize a Thread struct.
*
- * "threadObj" is the java.lang.Thread object. It will be NULL for the
- * main VM thread, but non-NULL for everything else.
- *
- * Does not create any objects, just stuff on the system (malloc) heap. (If
- * this changes, we need to use ALLOC_NO_GC. And also verify that we're
- * ready to load classes at the time this is called.)
+ * Does not create any objects, just stuff on the system (malloc) heap.
*/
static Thread* allocThread(int interpStackSize)
{
@@ -990,7 +983,7 @@
* This must be called while executing in the new thread, but before the
* thread is added to the thread list.
*
- * *** NOTE: The threadListLock must be held by the caller (needed for
+ * NOTE: The threadListLock must be held by the caller (needed for
* assignThreadId()).
*/
static bool prepareThread(Thread* thread)
@@ -1001,6 +994,10 @@
//LOGI("SYSTEM TID IS %d (pid is %d)\n", (int) thread->systemTid,
// (int) getpid());
+ /*
+ * If we were called by dvmAttachCurrentThread, the self value is
+ * already correctly established as "thread".
+ */
setThreadSelf(thread);
LOGV("threadid=%d: interp stack at %p\n",
@@ -1195,8 +1192,7 @@
*
* We reserve zero for use as an invalid ID.
*
- * This must be called with threadListLock held (unless we're still
- * initializing the system).
+ * This must be called with threadListLock held.
*/
static void assignThreadId(Thread* thread)
{
@@ -1278,7 +1274,17 @@
gDvm.methFakeNativeEntry = mainMeth;
}
- return dvmPushJNIFrame(thread, gDvm.methFakeNativeEntry);
+ if (!dvmPushJNIFrame(thread, gDvm.methFakeNativeEntry))
+ return false;
+
+ /*
+ * Null out the "String[] args" argument.
+ */
+ assert(gDvm.methFakeNativeEntry->registersSize == 1);
+ u4* framePtr = (u4*) thread->curFrame;
+ framePtr[0] = 0;
+
+ return true;
}
@@ -1292,8 +1298,13 @@
ClassObject* nativeStart;
Method* runMeth;
- nativeStart =
- dvmFindSystemClassNoInit("Ldalvik/system/NativeStart;");
+ /*
+ * TODO: cache this result so we don't have to dig for it every time
+ * somebody attaches a thread to the VM. Also consider changing this
+ * to a static method so we don't have a null "this" pointer in the
+ * "ins" on the stack. (Does it really need to look like a Runnable?)
+ */
+ nativeStart = dvmFindSystemClassNoInit("Ldalvik/system/NativeStart;");
if (nativeStart == NULL) {
LOGE("Unable to find dalvik.system.NativeStart class\n");
return false;
@@ -1305,7 +1316,20 @@
return false;
}
- return dvmPushJNIFrame(thread, runMeth);
+ if (!dvmPushJNIFrame(thread, runMeth))
+ return false;
+
+ /*
+ * Provide a NULL 'this' argument. The method we've put at the top of
+ * the stack looks like a virtual call to run() in a Runnable class.
+ * (If we declared the method static, it wouldn't take any arguments
+ * and we wouldn't have to do this.)
+ */
+ assert(runMeth->registersSize == 1);
+ u4* framePtr = (u4*) thread->curFrame;
+ framePtr[0] = 0;
+
+ return true;
}
/*
@@ -1327,13 +1351,20 @@
} else {
s = threadName + len - 15;
}
-#if defined(HAVE_PTHREAD_SETNAME_NP)
- if (pthread_setname_np(pthread_self(), s) != 0)
- LOGW("Unable to set the name of the current thread\n");
+#if defined(HAVE_ANDROID_PTHREAD_SETNAME_NP)
+ /* pthread_setname_np fails rather than truncating long strings */
+ char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+ strncpy(buf, s, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ int err = pthread_setname_np(pthread_self(), buf);
+ if (err != 0) {
+ LOGW("Unable to set the name of current thread to '%s': %s\n",
+ buf, strerror(err));
+ }
#elif defined(HAVE_PRCTL)
prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
#else
- LOGD("Unable to set current thread's name: %s\n", s);
+ LOGD("No way to set current thread's name (%s)\n", s);
#endif
}
@@ -1351,6 +1382,9 @@
* objects. We also need to create one of our internal Thread objects.
*
* Pass in a stack size of 0 to get the default.
+ *
+ * The "threadObj" reference must be pinned by the caller to prevent the GC
+ * from moving it around (e.g. added to the tracked allocation list).
*/
bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
{
@@ -1438,9 +1472,8 @@
*/
dvmUnlockThreadList();
- int cc, oldStatus;
- oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
- cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart,
+ ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart,
newThread);
oldStatus = dvmChangeStatus(self, oldStatus);
@@ -1601,6 +1634,7 @@
/*
* Finish initializing the Thread struct.
*/
+ dvmLockThreadList(self);
prepareThread(self);
LOG_THREAD("threadid=%d: created from interp\n", self->threadId);
@@ -1609,7 +1643,6 @@
* Change our status and wake our parent, who will add us to the
* thread list and advance our state to VMWAIT.
*/
- dvmLockThreadList(self);
self->status = THREAD_STARTING;
pthread_cond_broadcast(&gDvm.threadStartCond);
@@ -1698,7 +1731,6 @@
{
Object* exception;
Object* handlerObj;
- ClassObject* throwable;
Method* uncaughtHandler = NULL;
InstField* threadHandler;
@@ -1817,7 +1849,7 @@
* need to initiate a GC. We switch to VMWAIT while we pause.
*/
Thread* self = dvmThreadSelf();
- int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
dvmLockThreadList(self);
while (createStatus == 0)
pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock);
@@ -1914,56 +1946,16 @@
Method* init;
bool ok, ret;
- /* establish a basic sense of self */
+ /* allocate thread struct, and establish a basic sense of self */
self = allocThread(gDvm.stackSize);
if (self == NULL)
goto fail;
setThreadSelf(self);
/*
- * Create Thread and VMThread objects. We have to use ALLOC_NO_GC
- * because this thread is not yet visible to the VM. We could also
- * just grab the GC lock earlier, but that leaves us executing
- * interpreted code with the lock held, which is not prudent.
- *
- * The alloc calls will block if a GC is in progress, so we don't need
- * to check for global suspension here.
- *
- * It's also possible for the allocation calls to *cause* a GC.
- */
- //BUG: deadlock if a GC happens here during HeapWorker creation
- threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_NO_GC);
- if (threadObj == NULL)
- goto fail;
- vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_NO_GC);
- if (vmThreadObj == NULL)
- goto fail;
-
- self->threadObj = threadObj;
- dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)self);
-
- /*
- * Do some java.lang.Thread constructor prep before we lock stuff down.
- */
- if (pArgs->name != NULL) {
- threadNameStr = dvmCreateStringFromCstr(pArgs->name, ALLOC_NO_GC);
- if (threadNameStr == NULL) {
- assert(dvmCheckException(dvmThreadSelf()));
- goto fail;
- }
- }
-
- init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangThread, "<init>",
- "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
- if (init == NULL) {
- assert(dvmCheckException(dvmThreadSelf()));
- goto fail;
- }
-
- /*
- * Finish our thread prep. We need to do this before invoking any
- * interpreted code. prepareThread() requires that we hold the thread
- * list lock.
+ * Finish our thread prep. We need to do this before adding ourselves
+ * to the thread list or invoking any interpreted code. prepareThread()
+ * requires that we hold the thread list lock.
*/
dvmLockThreadList(self);
ok = prepareThread(self);
@@ -1985,20 +1977,11 @@
goto fail;
/*
- * The native side of the thread is ready; add it to the list.
+ * The native side of the thread is ready; add it to the list. Once
+ * it's on the list the thread is visible to the JDWP code and the GC.
*/
LOG_THREAD("threadid=%d: adding to list (attached)\n", self->threadId);
- /* Start off in VMWAIT, because we may be about to block
- * on the heap lock, and we don't want any suspensions
- * to wait for us.
- */
- self->status = THREAD_VMWAIT;
-
- /*
- * Add ourselves to the thread list. Once we finish here we are
- * visible to the debugger and the GC.
- */
dvmLockThreadList(self);
self->next = gDvm.threadList->next;
@@ -2012,20 +1995,57 @@
dvmUnlockThreadList();
/*
- * It's possible that a GC is currently running. Our thread
- * wasn't in the list when the GC started, so it's not properly
- * suspended in that case. Synchronize on the heap lock (held
- * when a GC is happening) to guarantee that any GCs from here
- * on will see this thread in the list.
+ * Switch state from initializing to running.
+ *
+ * It's possible that a GC began right before we added ourselves
+ * to the thread list, and is still going. That means our thread
+ * suspend count won't reflect the fact that we should be suspended.
+ * To deal with this, we transition to VMWAIT, pulse the heap lock,
+ * and then advance to RUNNING. That will ensure that we stall until
+ * the GC completes.
+ *
+ * Once we're in RUNNING, we're like any other thread in the VM (except
+ * for the lack of an initialized threadObj). We're then free to
+ * allocate and initialize objects.
*/
+ assert(self->status == THREAD_INITIALIZING);
+ dvmChangeStatus(self, THREAD_VMWAIT);
dvmLockMutex(&gDvm.gcHeapLock);
dvmUnlockMutex(&gDvm.gcHeapLock);
+ dvmChangeStatus(self, THREAD_RUNNING);
/*
- * Switch to the running state now that we're ready for
- * suspensions. This call may suspend.
+ * Create Thread and VMThread objects.
*/
- dvmChangeStatus(self, THREAD_RUNNING);
+ threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);
+ vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
+ if (threadObj == NULL || vmThreadObj == NULL)
+ goto fail_unlink;
+
+ /*
+ * This makes threadObj visible to the GC. We still have it in the
+ * tracked allocation table, so it can't move around on us.
+ */
+ self->threadObj = threadObj;
+ dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)self);
+
+ /*
+ * Create a string for the thread name.
+ */
+ if (pArgs->name != NULL) {
+ threadNameStr = dvmCreateStringFromCstr(pArgs->name);
+ if (threadNameStr == NULL) {
+ assert(dvmCheckException(dvmThreadSelf()));
+ goto fail_unlink;
+ }
+ }
+
+ init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangThread, "<init>",
+ "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
+ if (init == NULL) {
+ assert(dvmCheckException(self));
+ goto fail_unlink;
+ }
/*
* Now we're ready to run some interpreted code.
@@ -2045,8 +2065,6 @@
LOGE("exception thrown while constructing attached thread object\n");
goto fail_unlink;
}
- //if (isDaemon)
- // dvmSetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon, true);
/*
* Set the VMThread field, which tells interpreted code that we're alive.
@@ -2056,8 +2074,14 @@
* trying to start threads against anything it sees, which would
* generally cause problems for all thread creation. However, for
* correctness we test "vmThread" before setting it.
+ *
+ * TODO: this still has a race, it's just smaller. Not sure this is
+ * worth putting effort into fixing. Need to hold a lock while
+ * fiddling with the field, or maybe initialize the Thread object in a
+ * way that ensures another thread can't call start() on it.
*/
if (dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread) != NULL) {
+ LOGW("WOW: thread start hijack\n");
dvmThrowException("Ljava/lang/IllegalThreadStateException;",
"thread has already been started");
/* We don't want to free anything associated with the thread
@@ -2073,18 +2097,15 @@
* already present seems like a bad idea. TODO: figure this out. ]
*/
ret = false;
- } else
+ } else {
ret = true;
+ }
dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj);
- /* These are now reachable from the thread groups. */
- dvmClearAllocFlags(threadObj, ALLOC_NO_GC);
- dvmClearAllocFlags(vmThreadObj, ALLOC_NO_GC);
-
- /*
- * The thread is ready to go; let the debugger see it.
- */
- self->threadObj = threadObj;
+ /* we can now safely un-pin these */
+ dvmReleaseTrackedAlloc(threadObj, self);
+ dvmReleaseTrackedAlloc(vmThreadObj, self);
+ dvmReleaseTrackedAlloc((Object*)threadNameStr, self);
LOG_THREAD("threadid=%d: attached from native, name=%s\n",
self->threadId, pArgs->name);
@@ -2103,8 +2124,9 @@
dvmUnlockThreadList();
/* fall through to "fail" */
fail:
- dvmClearAllocFlags(threadObj, ALLOC_NO_GC);
- dvmClearAllocFlags(vmThreadObj, ALLOC_NO_GC);
+ dvmReleaseTrackedAlloc(threadObj, self);
+ dvmReleaseTrackedAlloc(vmThreadObj, self);
+ dvmReleaseTrackedAlloc((Object*)threadNameStr, self);
if (self != NULL) {
if (self->jniEnv != NULL) {
dvmDestroyJNIEnv(self->jniEnv);
@@ -2262,10 +2284,8 @@
LOGI("threadid=%d: waiting for method trace to finish\n",
self->threadId);
while (traceState->traceEnabled) {
- int cc;
- cc = pthread_cond_wait(&traceState->threadExitCond,
- &traceState->startStopLock);
- assert(cc == 0);
+ dvmWaitCond(&traceState->threadExitCond,
+ &traceState->startStopLock);
}
}
dvmUnlockMutex(&traceState->startStopLock);
@@ -2374,8 +2394,7 @@
thread->threadId, thread->suspendCount);
if (thread->suspendCount == 0) {
- int cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
- assert(cc == 0);
+ dvmBroadcastCond(&gDvm.threadSuspendCountCond);
}
unlockThreadSuspendCount();
@@ -2425,10 +2444,8 @@
}
while (self->suspendCount != 0) {
- int cc;
- cc = pthread_cond_wait(&gDvm.threadSuspendCountCond,
- &gDvm.threadSuspendCountLock);
- assert(cc == 0);
+ dvmWaitCond(&gDvm.threadSuspendCountCond,
+ &gDvm.threadSuspendCountLock);
if (self->suspendCount != 0) {
/*
* The condition was signaled but we're still suspended. This
@@ -3015,26 +3032,25 @@
* Check to see if we need to suspend ourselves. If so, go to sleep on
* a condition variable.
*
- * Takes "self" as an argument as an optimization. Pass in NULL to have
- * it do the lookup.
+ * If "newStatus" is not THREAD_UNDEFINED, we change to that state before
+ * we release the thread suspend count lock.
*
* Returns "true" if we suspended ourselves.
*/
-bool dvmCheckSuspendPending(Thread* self)
+static bool checkSuspendAndChangeStatus(Thread* self, ThreadStatus newStatus)
{
bool didSuspend;
- if (self == NULL)
- self = dvmThreadSelf();
+ assert(self != NULL);
+ assert(self->suspendCount >= 0);
- /* fast path: if count is zero, bail immediately */
- if (self->suspendCount == 0)
+ /* fast path: if count is zero and no state change, bail immediately */
+ if (self->suspendCount == 0 && newStatus == THREAD_UNDEFINED) {
return false;
+ }
lockThreadSuspendCount(); /* grab gDvm.threadSuspendCountLock */
- assert(self->suspendCount >= 0); /* XXX: valid? useful? */
-
didSuspend = (self->suspendCount != 0);
self->isSuspended = true;
LOG_THREAD("threadid=%d: self-suspending\n", self->threadId);
@@ -3050,12 +3066,31 @@
LOG_THREAD("threadid=%d: self-reviving, status=%d\n",
self->threadId, self->status);
+ /*
+ * The status change needs to happen while the suspend count lock is
+ * held. Otherwise we could switch to RUNNING after another thread
+ * increases our suspend count, which isn't a "bad" state for us
+ * (we'll suspend on the next check) but could be a problem for the
+ * other thread (which thinks we're safely in VMWAIT or NATIVE with
+ * a nonzero suspend count, and proceeds to initate GC).
+ */
+ if (newStatus != THREAD_UNDEFINED)
+ self->status = newStatus;
+
unlockThreadSuspendCount();
return didSuspend;
}
/*
+ * One-argument wrapper for checkSuspendAndChangeStatus().
+ */
+bool dvmCheckSuspendPending(Thread* self)
+{
+ return checkSuspendAndChangeStatus(self, THREAD_UNDEFINED);
+}
+
+/*
* Update our status.
*
* The "self" argument, which may be NULL, is accepted as an optimization.
@@ -3078,22 +3113,21 @@
/*
* Change our status to THREAD_RUNNING. The transition requires
* that we check for pending suspension, because the VM considers
- * us to be "asleep" in all other states.
+ * us to be "asleep" in all other states, and another thread could
+ * be performing a GC now.
*
- * We need to do the "suspend pending" check FIRST, because it grabs
- * a lock that could be held by something that wants us to suspend.
- * If we're in RUNNING it will wait for us, and we'll be waiting
- * for the lock it holds.
+ * The check for suspension requires holding the thread suspend
+ * count lock, which the suspend-all code also grabs. We want to
+ * check our suspension status and change to RUNNING atomically
+ * to avoid a situation where suspend-all thinks we're safe
+ * (e.g. VMWAIT or NATIVE with suspendCount=1) but we've actually
+ * switched to RUNNING and are executing code.
*/
assert(self->status != THREAD_RUNNING);
-
- dvmCheckSuspendPending(self);
- self->status = THREAD_RUNNING;
+ checkSuspendAndChangeStatus(self, newStatus);
} else {
/*
- * Change from one state to another, neither of which is
- * THREAD_RUNNING. This is most common during system or thread
- * initialization.
+ * Not changing to THREAD_RUNNING. No additional work required.
*/
self->status = newStatus;
}
@@ -3430,11 +3464,24 @@
char schedstatBuf[64]; // contents of /proc/[pid]/task/[tid]/schedstat
int schedstatFd;
+ /*
+ * Get the java.lang.Thread object. This function gets called from
+ * some weird debug contexts, so it's possible that there's a GC in
+ * progress on some other thread. To decrease the chances of the
+ * thread object being moved out from under us, we add the reference
+ * to the tracked allocation list, which pins it in place.
+ *
+ * If threadObj is NULL, the thread is still in the process of being
+ * attached to the VM, and there's really nothing interesting to
+ * say about it yet.
+ */
threadObj = thread->threadObj;
if (threadObj == NULL) {
- LOGW("Can't dump thread %d: threadObj not set\n", thread->threadId);
+ LOGI("Can't dump thread %d: threadObj not set\n", thread->threadId);
return;
}
+ dvmAddTrackedAlloc(threadObj, NULL);
+
nameStr = (StringObject*) dvmGetFieldObject(threadObj,
gDvm.offJavaLangThread_name);
threadName = dvmCreateCstrFromString(nameStr);
@@ -3469,7 +3516,7 @@
}
}
if (groupName == NULL)
- groupName = strdup("(BOGUS GROUP)");
+ groupName = strdup("(null; initializing?)");
dvmPrintDebugMessage(target,
"\"%s\"%s prio=%d tid=%d %s%s\n",
@@ -3531,9 +3578,9 @@
else
dvmDumpThreadStack(target, thread);
+ dvmReleaseTrackedAlloc(threadObj, NULL);
free(threadName);
free(groupName);
-
}
/*
@@ -3583,6 +3630,17 @@
dvmPrintDebugMessage(target, "DALVIK THREADS:\n");
+#ifdef HAVE_ANDROID_OS
+ dvmPrintDebugMessage(target,
+ "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x hwl=%x hwll=%x)\n",
+ gDvm.threadListLock.value,
+ gDvm._threadSuspendLock.value,
+ gDvm.threadSuspendCountLock.value,
+ gDvm.gcHeapLock.value,
+ gDvm.heapWorkerLock.value,
+ gDvm.heapWorkerListLock.value);
+#endif
+
if (grabLock)
dvmLockThreadList(dvmThreadSelf());
@@ -3798,7 +3856,7 @@
saveArea = SAVEAREA_FROM_FP(framePtr);
method = saveArea->method;
- if (method != NULL && !dvmIsNativeMethod(method)) {
+ if (method != NULL) {
#ifdef COUNT_PRECISE_METHODS
/* the GC is running, so no lock required */
if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
@@ -3965,10 +4023,6 @@
dvmReleaseRegisterMapLine(pMap, regVector);
}
}
- /* else this is a break frame and there is nothing to mark, or
- * this is a native method and the registers are just the "ins",
- * copied from various registers in the caller's set.
- */
#if WITH_EXTRA_GC_CHECKS > 1
first = false;
@@ -3999,6 +4053,7 @@
}
}
+#ifdef USE_INDIRECT_REF
static void gcScanIndirectRefTable(IndirectRefTable* pRefTable)
{
Object** op = pRefTable->table;
@@ -4012,6 +4067,7 @@
op++;
}
}
+#endif
/*
* Scan a Thread and mark any objects it references.
diff --git a/vm/Thread.h b/vm/Thread.h
index 5ca73c4..204135a 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -22,6 +22,7 @@
#include "jni.h"
+#include <errno.h>
#include <cutils/sched_policy.h>
@@ -43,6 +44,8 @@
* Note that "suspended" is orthogonal to these values (so says JDWP).
*/
typedef enum ThreadStatus {
+ THREAD_UNDEFINED = -1, /* threads are never in this state */
+
/* these match up with JDWP values */
THREAD_ZOMBIE = 0, /* TERMINATED */
THREAD_RUNNING = 1, /* RUNNABLE or running now */
@@ -168,6 +171,10 @@
* matter)
*/
void* inJitCodeCache;
+#if defined(WITH_SELF_VERIFICATION)
+ /* Buffer for register state during self verification */
+ struct ShadowSpace* shadowSpace;
+#endif
#endif
/* JNI local reference tracking */
@@ -245,11 +252,6 @@
const u2* currentPc2;
#endif
-#if defined(WITH_SELF_VERIFICATION)
- /* Buffer for register state during self verification */
- struct ShadowSpace* shadowSpace;
-#endif
-
/* system thread state */
SystemThread* systemThread;
} Thread;
@@ -299,6 +301,7 @@
SUSPEND_FOR_DEBUG_EVENT,
SUSPEND_FOR_STACK_DUMP,
SUSPEND_FOR_DEX_OPT,
+ SUSPEND_FOR_VERIFY,
#if defined(WITH_JIT)
SUSPEND_FOR_TBL_RESIZE, // jit-table resize
SUSPEND_FOR_IC_PATCH, // polymorphic callsite inline-cache patch
@@ -326,8 +329,6 @@
/*
* Check to see if we should be suspended now. If so, suspend ourselves
* by sleeping on a condition variable.
- *
- * If "self" is NULL, this will use dvmThreadSelf().
*/
bool dvmCheckSuspendPending(Thread* self);
@@ -377,7 +378,7 @@
*/
INLINE void dvmLockMutex(pthread_mutex_t* pMutex)
{
- int cc = pthread_mutex_lock(pMutex);
+ int cc __attribute__ ((__unused__)) = pthread_mutex_lock(pMutex);
assert(cc == 0);
}
@@ -386,7 +387,9 @@
*/
INLINE int dvmTryLockMutex(pthread_mutex_t* pMutex)
{
- return pthread_mutex_trylock(pMutex);
+ int cc = pthread_mutex_trylock(pMutex);
+ assert(cc == 0 || cc == EBUSY);
+ return cc;
}
/*
@@ -394,7 +397,7 @@
*/
INLINE void dvmUnlockMutex(pthread_mutex_t* pMutex)
{
- int cc = pthread_mutex_unlock(pMutex);
+ int cc __attribute__ ((__unused__)) = pthread_mutex_unlock(pMutex);
assert(cc == 0);
}
@@ -403,7 +406,25 @@
*/
INLINE void dvmDestroyMutex(pthread_mutex_t* pMutex)
{
- int cc = pthread_mutex_destroy(pMutex);
+ int cc __attribute__ ((__unused__)) = pthread_mutex_destroy(pMutex);
+ assert(cc == 0);
+}
+
+INLINE void dvmBroadcastCond(pthread_cond_t* pCond)
+{
+ int cc __attribute__ ((__unused__)) = pthread_cond_broadcast(pCond);
+ assert(cc == 0);
+}
+
+INLINE void dvmSignalCond(pthread_cond_t* pCond)
+{
+ int cc __attribute__ ((__unused__)) = pthread_cond_signal(pCond);
+ assert(cc == 0);
+}
+
+INLINE void dvmWaitCond(pthread_cond_t* pCond, pthread_mutex_t* pMutex)
+{
+ int cc __attribute__ ((__unused__)) = pthread_cond_wait(pCond, pMutex);
assert(cc == 0);
}
diff --git a/vm/UtfString.c b/vm/UtfString.c
index 8e20a0f..0b81c6d 100644
--- a/vm/UtfString.c
+++ b/vm/UtfString.c
@@ -36,6 +36,10 @@
* String implements java/lang/CharSequence, but CharSequence doesn't exist)
* we can try to create an exception string internally before anything has
* really tried to use String. In that case we basically self-destruct.
+ *
+ * We're expecting to be essentially single-threaded at this point.
+ * We employ atomics to ensure everything is observed correctly, and also
+ * to guarantee that we do detect a problem if our assumption is wrong.
*/
static bool stringStartup()
{
@@ -44,9 +48,12 @@
assert(false);
return false;
}
- assert(gDvm.javaLangStringReady == 0);
- gDvm.javaLangStringReady = -1;
+ if (android_atomic_acquire_cas(0, -1, &gDvm.javaLangStringReady) != 0) {
+ LOGE("ERROR: initial string-ready state not 0 (%d)\n",
+ gDvm.javaLangStringReady);
+ return false;
+ }
if (gDvm.classJavaLangString == NULL)
gDvm.classJavaLangString =
@@ -94,7 +101,7 @@
if (badValue)
return false;
- gDvm.javaLangStringReady = 1;
+ android_atomic_release_store(1, &gDvm.javaLangStringReady);
return true;
}
@@ -250,39 +257,32 @@
/*
* Create a new java/lang/String object, using the string data in "utf8Str".
*
- * Note that "allocFlags" affects both of the allocations here. If you
- * use ALLOC_DONT_TRACK in a context where a GC could happen between the
- * two allocations, you could lose the array reference.
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
*
* Returns NULL and throws an exception on failure.
*/
-StringObject* dvmCreateStringFromCstr(const char* utf8Str, int allocFlags)
+StringObject* dvmCreateStringFromCstr(const char* utf8Str)
{
assert(utf8Str != NULL);
-
- return dvmCreateStringFromCstrAndLength(utf8Str, dvmUtf8Len(utf8Str),
- allocFlags);
+ return dvmCreateStringFromCstrAndLength(utf8Str, dvmUtf8Len(utf8Str));
}
/*
* Create a java/lang/String from a C string, given its UTF-16 length
* (number of UTF-16 code points).
*
- * The caller must call dvmReleaseTrackedAlloc() on the return value or
- * use a non-default value for "allocFlags". It is never appropriate
- * to use ALLOC_DONT_TRACK with this function.
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
*
* Returns NULL and throws an exception on failure.
*/
StringObject* dvmCreateStringFromCstrAndLength(const char* utf8Str,
- u4 utf16Length, int allocFlags)
+ u4 utf16Length)
{
StringObject* newObj;
ArrayObject* chars;
u4 hashCode = 0;
//LOGV("Creating String from '%s'\n", utf8Str);
- assert(allocFlags != ALLOC_DONT_TRACK); /* don't currently need */
assert(utf8Str != NULL);
if (gDvm.javaLangStringReady <= 0) {
@@ -298,13 +298,13 @@
}
newObj = (StringObject*) dvmAllocObject(gDvm.classJavaLangString,
- allocFlags);
+ ALLOC_DEFAULT);
if (newObj == NULL)
return NULL;
- chars = dvmAllocPrimitiveArray('C', utf16Length, allocFlags);
+ chars = dvmAllocPrimitiveArray('C', utf16Length, ALLOC_DEFAULT);
if (chars == NULL) {
- dvmReleaseTrackedAllocIFN((Object*) newObj, NULL, allocFlags);
+ dvmReleaseTrackedAlloc((Object*) newObj, NULL);
return NULL;
}
dvmConvertUtf8ToUtf16((u2*)chars->contents, utf8Str);
@@ -312,7 +312,7 @@
dvmSetFieldObject((Object*)newObj, STRING_FIELDOFF_VALUE,
(Object*)chars);
- dvmReleaseTrackedAllocIFN((Object*) chars, NULL, allocFlags);
+ dvmReleaseTrackedAlloc((Object*) chars, NULL);
dvmSetFieldInt((Object*)newObj, STRING_FIELDOFF_COUNT, utf16Length);
dvmSetFieldInt((Object*)newObj, STRING_FIELDOFF_HASHCODE, hashCode);
/* leave offset set to zero */
@@ -521,4 +521,3 @@
(const u2*) chars2->contents + offset2,
len1 * sizeof(u2));
}
-
diff --git a/vm/UtfString.h b/vm/UtfString.h
index 8f0f972..9308d77 100644
--- a/vm/UtfString.h
+++ b/vm/UtfString.h
@@ -58,26 +58,22 @@
/*
* Create a java/lang/String from a C string.
*
- * The caller must call dvmReleaseTrackedAlloc() on the return value or
- * use a non-default value for "allocFlags". It is never appropriate
- * to use ALLOC_DONT_TRACK with this function.
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
*
* Returns NULL and throws an exception on failure.
*/
-StringObject* dvmCreateStringFromCstr(const char* utf8Str, int allocFlags);
+StringObject* dvmCreateStringFromCstr(const char* utf8Str);
/*
* Create a java/lang/String from a C string, given its UTF-16 length
* (number of UTF-16 code points).
*
- * The caller must call dvmReleaseTrackedAlloc() on the return value or
- * use a non-default value for "allocFlags". It is never appropriate
- * to use ALLOC_DONT_TRACK with this function.
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
*
* Returns NULL and throws an exception on failure.
*/
StringObject* dvmCreateStringFromCstrAndLength(const char* utf8Str,
- u4 utf16Length, int allocFlags);
+ u4 utf16Length);
/*
* Compute the number of characters in a "modified UTF-8" string. This will
diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c
index d209e4a..61a1350 100644
--- a/vm/alloc/Alloc.c
+++ b/vm/alloc/Alloc.c
@@ -51,6 +51,15 @@
}
/*
+ * Shutdown the threads internal to the garbage collector.
+ */
+void dvmGcThreadShutdown(void)
+{
+ dvmHeapWorkerShutdown();
+ dvmHeapThreadShutdown();
+}
+
+/*
* Shut the GC down.
*/
void dvmGcShutdown(void)
@@ -99,7 +108,7 @@
if (msg == NULL) {
msgStr = NULL;
} else {
- msgStr = dvmCreateStringFromCstr(msg, ALLOC_DEFAULT);
+ msgStr = dvmCreateStringFromCstr(msg);
if (msgStr == NULL) {
LOGW("Could not allocate message string \"%s\"\n", msg);
dvmReleaseTrackedAlloc(obj, self);
@@ -174,8 +183,6 @@
newObj = dvmMalloc(clazz->objectSize, flags);
if (newObj != NULL) {
DVM_OBJECT_INIT(newObj, clazz);
- LOGVV("AllocObject: %s (%d)\n", clazz->descriptor,
- (int) clazz->objectSize);
#if WITH_HPROF && WITH_HPROF_STACK
hprofFillInStackTrace(newObj);
#endif
@@ -210,8 +217,11 @@
else
flags = ALLOC_DEFAULT;
-//TODO: use clazz->objectSize for non-arrays
- size = dvmObjectSizeInHeap(obj);
+ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+ size = dvmArrayObjectSize((ArrayObject *)obj);
+ } else {
+ size = obj->clazz->objectSize;
+ }
copy = dvmMalloc(size, flags);
if (copy == NULL)
@@ -223,12 +233,7 @@
memcpy(copy, obj, size);
DVM_LOCK_INIT(©->lock);
-
- //LOGV("CloneObject: %p->%p %s (%d)\n", obj, copy, obj->clazz->name, size);
-
- // TODO: deal with reference classes
-
- /* don't call dvmReleaseTrackedAlloc -- the caller must do that */
+ dvmWriteBarrierObject(copy);
return copy;
}
@@ -249,8 +254,6 @@
if (self == NULL)
self = dvmThreadSelf();
- //LOGI("TRACK ADD %p\n", obj);
-
assert(self != NULL);
if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
LOGE("threadid=%d: unable to add %p to internal ref table\n",
@@ -275,9 +278,6 @@
self = dvmThreadSelf();
assert(self != NULL);
- //LOGI("TRACK REM %p (%s)\n", obj,
- // (obj->clazz != NULL) ? obj->clazz->name : "");
-
if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
self->internalLocalRefTable.table, obj))
{
@@ -295,7 +295,6 @@
{
dvmLockHeap();
- LOGVV("Explicit GC\n");
dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT);
dvmUnlockHeap();
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
index facc753..8244ce7 100644
--- a/vm/alloc/Alloc.h
+++ b/vm/alloc/Alloc.h
@@ -19,7 +19,7 @@
#ifndef _DALVIK_ALLOC_ALLOC
#define _DALVIK_ALLOC_ALLOC
-#include <stdlib.h>
+#include <stddef.h>
/*
* Initialization.
@@ -28,6 +28,7 @@
bool dvmCreateStockExceptions(void);
bool dvmGcStartupAfterZygote(void);
void dvmGcShutdown(void);
+void dvmGcThreadShutdown(void);
/*
* Do any last-minute preparation before we call fork() for the first time.
@@ -38,7 +39,7 @@
* Basic allocation function.
*
* The new object will be added to the "tracked alloc" table unless
- * flags is ALLOC_DONT_TRACK or ALLOC_NO_GC.
+ * flags is ALLOC_DONT_TRACK.
*
* Returns NULL and throws an exception on failure.
*/
@@ -48,25 +49,17 @@
* Allocate a new object.
*
* The new object will be added to the "tracked alloc" table unless
- * flags is ALLOC_DONT_TRACK or ALLOC_NO_GC.
+ * flags is ALLOC_DONT_TRACK.
*
* Returns NULL and throws an exception on failure.
*/
Object* dvmAllocObject(ClassObject* clazz, int flags);
-/*
- * Clear flags set by dvmMalloc. Pass in a bit mask of the flags that
- * should be cleared.
- */
-void dvmClearAllocFlags(Object* obj, int mask);
-
/* flags for dvmMalloc */
enum {
ALLOC_DEFAULT = 0x00,
- ALLOC_NO_GC = 0x01, /* do not garbage collect this object */
- ALLOC_DONT_TRACK = 0x02, /* don't add to internal tracking list */
- ALLOC_FINALIZABLE = 0x04, /* call finalize() before freeing */
- // ALLOC_NO_MOVE?
+ ALLOC_DONT_TRACK = 0x01, /* don't add to internal tracking list */
+ ALLOC_FINALIZABLE = 0x02, /* call finalize() before freeing */
};
/*
@@ -94,21 +87,16 @@
void dvmReleaseTrackedAlloc(Object* obj, Thread* self);
/*
- * Like dvmReleaseTrackedAlloc, but only does the release if "allocFlags"
- * indicates that it's necessary to do so.
- */
-INLINE void dvmReleaseTrackedAllocIFN(Object* obj, Thread* self, int allocFlags)
-{
- if ((allocFlags & (ALLOC_NO_GC|ALLOC_DONT_TRACK)) == 0)
- dvmReleaseTrackedAlloc(obj, self);
-}
-
-/*
* Returns true iff <obj> points to a valid allocated object.
*/
bool dvmIsValidObject(const Object* obj);
/*
+ * Returns true iff <ptr> points within allocation-managed address space.
+ */
+bool dvmIsValidObjectAddress(const void *ptr);
+
+/*
* Create a copy of an object.
*
* The new object will be added to the "tracked alloc" table.
diff --git a/vm/alloc/CardTable.c b/vm/alloc/CardTable.c
new file mode 100644
index 0000000..bd8de9a
--- /dev/null
+++ b/vm/alloc/CardTable.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Needed for PROT_* definitions.
+ */
+#include <sys/mman.h>
+
+#include "Dalvik.h"
+#include "alloc/HeapSource.h"
+#include "alloc/Visit.h"
+
+/*
+ * Maintain a card table from the the write barrier. All writes of
+ * non-NULL values to heap addresses should go through an entry in
+ * WriteBarrier, and from there to here.
+ *
+ * The heap is divided into "cards" of GC_CARD_SIZE bytes, as
+ * determined by GC_CARD_SHIFT. The card table contains one byte of
+ * data per card, to be used by the GC. The value of the byte will be
+ * one of GC_CARD_CLEAN or GC_CARD_DIRTY.
+ *
+ * After any store of a non-NULL object pointer into a heap object,
+ * code is obliged to mark the card dirty. The setters in
+ * ObjectInlines.h [such as dvmSetFieldObject] do this for you. The
+ * JIT and fast interpreters also contain code to mark cards as dirty.
+ *
+ * The card table's base [the "biased card table"] gets set to a
+ * rather strange value. In order to keep the JIT from having to
+ * fabricate or load GC_DIRTY_CARD to store into the card table,
+ * biased base is within the mmap allocation at a point where it's low
+ * byte is equal to GC_DIRTY_CARD. See dvmCardTableStartup for details.
+ */
+
+/*
+ * Initializes the card table; must be called before any other
+ * dvmCardTable*() functions.
+ */
+bool dvmCardTableStartup(void)
+{
+ size_t length;
+ void *allocBase;
+ u1 *biasedBase;
+ GcHeap *gcHeap = gDvm.gcHeap;
+ void *heapBase = dvmHeapSourceGetBase();
+ assert(gcHeap != NULL);
+ assert(heapBase != NULL);
+
+ /* Set up the card table */
+ length = gDvm.heapSizeMax / GC_CARD_SIZE;
+ /* Allocate an extra 256 bytes to allow fixed low-byte of base */
+ allocBase = dvmAllocRegion(length + 0x100, PROT_READ | PROT_WRITE,
+ "dalvik-card-table");
+ if (allocBase == NULL) {
+ return false;
+ }
+ gcHeap->cardTableBase = allocBase;
+ gcHeap->cardTableLength = length;
+ /* All zeros is the correct initial value; all clean. */
+ assert(GC_CARD_CLEAN == 0);
+
+ biasedBase = (u1 *)((uintptr_t)allocBase -
+ ((uintptr_t)heapBase >> GC_CARD_SHIFT));
+ if (((uintptr_t)biasedBase & 0xff) != GC_CARD_DIRTY) {
+ int offset;
+ offset = GC_CARD_DIRTY - ((uintptr_t)biasedBase & 0xff);
+ biasedBase += offset + (offset < 0 ? 0x100 : 0);
+ }
+ assert(((uintptr_t)biasedBase & 0xff) == GC_CARD_DIRTY);
+ gDvm.biasedCardTableBase = biasedBase;
+
+ return true;
+}
+
+/*
+ * Tears down the entire CardTable.
+ */
+void dvmCardTableShutdown()
+{
+ gDvm.biasedCardTableBase = NULL;
+ munmap(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength);
+}
+
+void dvmClearCardTable(void)
+{
+ assert(gDvm.gcHeap->cardTableBase != NULL);
+ memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, gDvm.gcHeap->cardTableLength);
+}
+
+/*
+ * Returns true iff the address is within the bounds of the card table.
+ */
+bool dvmIsValidCard(const u1 *cardAddr)
+{
+ GcHeap *h = gDvm.gcHeap;
+ return cardAddr >= h->cardTableBase &&
+ cardAddr < &h->cardTableBase[h->cardTableLength];
+}
+
+/*
+ * Returns the address of the relevent byte in the card table, given
+ * an address on the heap.
+ */
+u1 *dvmCardFromAddr(const void *addr)
+{
+ u1 *biasedBase = gDvm.biasedCardTableBase;
+ u1 *cardAddr = biasedBase + ((uintptr_t)addr >> GC_CARD_SHIFT);
+ assert(dvmIsValidCard(cardAddr));
+ return cardAddr;
+}
+
+/*
+ * Returns the first address in the heap which maps to this card.
+ */
+void *dvmAddrFromCard(const u1 *cardAddr)
+{
+ assert(dvmIsValidCard(cardAddr));
+ uintptr_t offset = cardAddr - gDvm.biasedCardTableBase;
+ return (void *)(offset << GC_CARD_SHIFT);
+}
+
+/*
+ * Dirties the card for the given address.
+ */
+void dvmMarkCard(const void *addr)
+{
+ u1 *cardAddr = dvmCardFromAddr(addr);
+ *cardAddr = GC_CARD_DIRTY;
+}
diff --git a/vm/alloc/CardTable.h b/vm/alloc/CardTable.h
new file mode 100644
index 0000000..7a86bd0
--- /dev/null
+++ b/vm/alloc/CardTable.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Maintain a card table from the the write barrier. All writes of
+ * non-NULL values to heap addresses should go through an entry in
+ * WriteBarrier, and from there to here.
+ */
+
+#ifndef _DALVIK_ALLOC_CARDTABLE
+#define _DALVIK_ALLOC_CARDTABLE
+
+/*
+ * TODO: Better documentation of these values pending integration of
+ * concurrent collections and the card table.
+ */
+#define GC_CARD_SHIFT 7
+#define GC_CARD_SIZE (1 << GC_CARD_SHIFT)
+#define GC_CARD_CLEAN 0
+#define GC_CARD_DIRTY 0x70
+
+/*
+ * Initializes the card table; must be called before any other
+ * dvmCardTable*() functions.
+ */
+bool dvmCardTableStartup(void);
+
+/*
+ * Tears down the entire CardTable structure.
+ */
+void dvmCardTableShutdown(void);
+
+/*
+ * Resets all of the bytes in the card table to clean.
+ */
+void dvmClearCardTable(void);
+
+/*
+ * Returns the address of the relevent byte in the card table, given
+ * an address on the heap.
+ */
+u1 *dvmCardFromAddr(const void *addr);
+
+/*
+ * Returns the first address in the heap which maps to this card.
+ */
+void *dvmAddrFromCard(const u1 *card);
+
+/*
+ * Set the card associated with the given address to GC_CARD_DIRTY.
+ */
+void dvmMarkCard(const void *addr);
+
+/*
+ * dvmAbort if any clean object in the Zygote heap contains a
+ * reference to the application heap, or if the immune limit is not as
+ * expected.
+ */
+void dvmVerifyCardTable(void);
+
+/* TODO: Clearing, querying, and iterating over the card table. */
+
+#endif /*_DALVIK_ALLOC_CARDTABLE*/
diff --git a/vm/alloc/Copying.c b/vm/alloc/Copying.c
new file mode 100644
index 0000000..622f489
--- /dev/null
+++ b/vm/alloc/Copying.c
@@ -0,0 +1,2367 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/mman.h>
+
+#include "Dalvik.h"
+#include "alloc/Heap.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/HeapSource.h"
+#include "alloc/Verify.h"
+#include "alloc/clz.h"
+
+/*
+ * A "mostly copying", generational, garbage collector.
+ *
+ * TODO: we allocate our own contiguous tract of page frames to back
+ * object allocations. To cooperate with other heaps active in the
+ * virtual machine we need to move the responsibility of allocating
+ * pages someplace outside of this code.
+ *
+ * The other major data structures that maintain the state of the heap
+ * are the block space table and the block queue.
+ *
+ * The block space table records the state of a block. We must track
+ * whether a block is:
+ *
+ * - Free or allocated in some space.
+ *
+ * - If the block holds part of a large object allocation, whether the
+ * block is the initial or a continued block of the allocation.
+ *
+ * - Whether the block is pinned, that is to say whether at least one
+ * object in the block must remain stationary. Only needed during a
+ * GC.
+ *
+ * - Which space the object belongs to. At present this means
+ * from-space or to-space.
+ *
+ * The block queue is used during garbage collection. Unlike Cheney's
+ * algorithm, from-space and to-space are not contiguous. Therefore,
+ * one cannot maintain the state of the copy with just two pointers.
+ * The block queue exists to thread lists of blocks from the various
+ * spaces together.
+ *
+ * Additionally, we record the free space frontier of the heap, as
+ * well as the address of the first object within a block, which is
+ * required to copy objects following a large object (not currently
+ * implemented). This is stored in the heap source structure. This
+ * should be moved elsewhere to support in-line allocations from Java
+ * threads.
+ *
+ * Allocation requests are satisfied by reserving storage from one or
+ * more contiguous blocks. Objects that are small enough to fit
+ * inside a block are packed together within a block. Objects that
+ * are larger than a block are allocated from contiguous sequences of
+ * blocks. When half the available blocks are filled, a garbage
+ * collection occurs. We "flip" spaces (exchange from- and to-space),
+ * copy live objects into to space, and perform pointer adjustment.
+ *
+ * Copying is made more complicated by the requirement that some
+ * objects must not be moved. This property is known as "pinning".
+ * These objects must be dealt with specially. We use Bartlett's
+ * scheme; blocks containing such objects are grayed (promoted) at the
+ * start of a garbage collection. By virtue of this trick, tracing
+ * from the roots proceeds as usual but all objects on those pages are
+ * considered promoted and therefore not moved.
+ *
+ * TODO: there is sufficient information within the garbage collector
+ * to implement Attardi's scheme for evacuating unpinned objects from
+ * a page that is otherwise pinned. This would eliminate false
+ * retention caused by the large pinning granularity.
+ *
+ * We need a scheme for medium and large objects. Ignore that for
+ * now, we can return to this later.
+ *
+ * Eventually we need to worry about promoting objects out of the
+ * copy-collected heap (tenuring) into a less volatile space. Copying
+ * may not always be the best policy for such spaces. We should
+ * consider a variant of mark, sweep, compact.
+ *
+ * The block scheme allows us to use VM page faults to maintain a
+ * write barrier. Consider having a special leaf state for a page.
+ *
+ * Bibliography:
+ *
+ * C. J. Cheney. 1970. A non-recursive list compacting
+ * algorithm. CACM. 13-11 pp677--678.
+ *
+ * Joel F. Bartlett. 1988. Compacting Garbage Collection with
+ * Ambiguous Roots. Digital Equipment Corporation.
+ *
+ * Joel F. Bartlett. 1989. Mostly-Copying Garbage Collection Picks Up
+ * Generations and C++. Digital Equipment Corporation.
+ *
+ * G. May Yip. 1991. Incremental, Generational Mostly-Copying Garbage
+ * Collection in Uncooperative Environments. Digital Equipment
+ * Corporation.
+ *
+ * Giuseppe Attardi, Tito Flagella. 1994. A Customisable Memory
+ * Management Framework. TR-94-010
+ *
+ * Giuseppe Attardi, Tito Flagella, Pietro Iglio. 1998. A customisable
+ * memory management framework for C++. Software -- Practice and
+ * Experience. 28(11), 1143-1183.
+ *
+ */
+
+#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#if 0
+#define LOG_ALLOC LOGI
+#define LOG_PIN LOGI
+#define LOG_PROM LOGI
+#define LOG_REF LOGI
+#define LOG_SCAV LOGI
+#define LOG_TRAN LOGI
+#define LOG_VER LOGI
+#else
+#define LOG_ALLOC(...) ((void)0)
+#define LOG_PIN(...) ((void)0)
+#define LOG_PROM(...) ((void)0)
+#define LOG_REF(...) ((void)0)
+#define LOG_SCAV(...) ((void)0)
+#define LOG_TRAN(...) ((void)0)
+#define LOG_VER(...) ((void)0)
+#endif
+
+static void enqueueBlock(HeapSource *heapSource, size_t block);
+static void scavengeReference(Object **obj);
+static bool toSpaceContains(const void *addr);
+static bool fromSpaceContains(const void *addr);
+static size_t sumHeapBitmap(const HeapBitmap *bitmap);
+static size_t objectSize(const Object *obj);
+static void scavengeDataObject(Object *obj);
+static void scavengeBlockQueue(void);
+
+/*
+ * We use 512-byte blocks.
+ */
+enum { BLOCK_SHIFT = 9 };
+enum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
+
+/*
+ * Space identifiers, stored into the blockSpace array.
+ */
+enum {
+ BLOCK_FREE = 0,
+ BLOCK_FROM_SPACE = 1,
+ BLOCK_TO_SPACE = 2,
+ BLOCK_CONTINUED = 7
+};
+
+/*
+ * Alignment for all allocations, in bytes.
+ */
+enum { ALLOC_ALIGNMENT = 8 };
+
+/*
+ * Sentinel value for the queue end.
+ */
+#define QUEUE_TAIL (~(size_t)0)
+
+struct HeapSource {
+
+ /* The base address of backing store. */
+ u1 *blockBase;
+
+ /* Total number of blocks available for allocation. */
+ size_t totalBlocks;
+ size_t allocBlocks;
+
+ /*
+ * The scavenger work queue. Implemented as an array of index
+ * values into the queue.
+ */
+ size_t *blockQueue;
+
+ /*
+ * Base and limit blocks. Basically the shifted start address of
+ * the block. We convert blocks to a relative number when
+ * indexing in the block queue. TODO: make the block queue base
+ * relative rather than the index into the block queue.
+ */
+ size_t baseBlock, limitBlock;
+
+ size_t queueHead;
+ size_t queueTail;
+ size_t queueSize;
+
+ /* The space of the current block 0 (free), 1 or 2. */
+ char *blockSpace;
+
+ /* Start of free space in the current block. */
+ u1 *allocPtr;
+ /* Exclusive limit of free space in the current block. */
+ u1 *allocLimit;
+
+ HeapBitmap allocBits;
+
+ /*
+ * The starting size of the heap. This value is the same as the
+ * value provided to the -Xms flag.
+ */
+ size_t minimumSize;
+
+ /*
+ * The maximum size of the heap. This value is the same as the
+ * -Xmx flag.
+ */
+ size_t maximumSize;
+
+ /*
+ * The current, committed size of the heap. At present, this is
+ * equivalent to the maximumSize.
+ */
+ size_t currentSize;
+
+ size_t bytesAllocated;
+};
+
+static unsigned long alignDown(unsigned long x, unsigned long n)
+{
+ return x & -n;
+}
+
+static unsigned long alignUp(unsigned long x, unsigned long n)
+{
+ return alignDown(x + (n - 1), n);
+}
+
+static void describeBlocks(const HeapSource *heapSource)
+{
+ size_t i;
+
+ for (i = 0; i < heapSource->totalBlocks; ++i) {
+ if ((i % 32) == 0) putchar('\n');
+ printf("%d ", heapSource->blockSpace[i]);
+ }
+ putchar('\n');
+}
+
+/*
+ * Virtual memory interface.
+ */
+
+static void *virtualAlloc(size_t length)
+{
+ void *addr;
+ int flags, prot;
+
+ flags = MAP_PRIVATE | MAP_ANONYMOUS;
+ prot = PROT_READ | PROT_WRITE;
+ addr = mmap(NULL, length, prot, flags, -1, 0);
+ if (addr == MAP_FAILED) {
+ LOGE_HEAP("mmap: %s", strerror(errno));
+ addr = NULL;
+ }
+ return addr;
+}
+
+static void virtualFree(void *addr, size_t length)
+{
+ int res;
+
+ assert(addr != NULL);
+ assert((uintptr_t)addr % SYSTEM_PAGE_SIZE == 0);
+ res = munmap(addr, length);
+ if (res == -1) {
+ LOGE_HEAP("munmap: %s", strerror(errno));
+ }
+}
+
+#ifndef NDEBUG
+static int isValidAddress(const HeapSource *heapSource, const u1 *addr)
+{
+ size_t block;
+
+ block = (uintptr_t)addr >> BLOCK_SHIFT;
+ return heapSource->baseBlock <= block &&
+ heapSource->limitBlock > block;
+}
+#endif
+
+/*
+ * Iterate over the block map looking for a contiguous run of free
+ * blocks.
+ */
+static void *allocateBlocks(HeapSource *heapSource, size_t blocks)
+{
+ void *addr;
+ size_t allocBlocks, totalBlocks;
+ size_t i, j;
+
+ allocBlocks = heapSource->allocBlocks;
+ totalBlocks = heapSource->totalBlocks;
+ /* Check underflow. */
+ assert(blocks != 0);
+ /* Check overflow. */
+ if (allocBlocks + blocks > totalBlocks / 2) {
+ return NULL;
+ }
+ /* Scan block map. */
+ for (i = 0; i < totalBlocks; ++i) {
+ /* Check fit. */
+ for (j = 0; j < blocks; ++j) { /* runs over totalBlocks */
+ if (heapSource->blockSpace[i+j] != BLOCK_FREE) {
+ break;
+ }
+ }
+ /* No fit? */
+ if (j != blocks) {
+ i += j;
+ continue;
+ }
+ /* Fit, allocate. */
+ heapSource->blockSpace[i] = BLOCK_TO_SPACE; /* why to-space? */
+ for (j = 1; j < blocks; ++j) {
+ heapSource->blockSpace[i+j] = BLOCK_CONTINUED;
+ }
+ heapSource->allocBlocks += blocks;
+ addr = &heapSource->blockBase[i*BLOCK_SIZE];
+ memset(addr, 0, blocks*BLOCK_SIZE);
+ /* Collecting? */
+ if (heapSource->queueHead != QUEUE_TAIL) {
+ LOG_ALLOC("allocateBlocks allocBlocks=%zu,block#=%zu", heapSource->allocBlocks, i);
+ /*
+ * This allocated was on behalf of the transporter when it
+ * shaded a white object gray. We enqueue the block so
+ * the scavenger can further shade the gray objects black.
+ */
+ enqueueBlock(heapSource, i);
+ }
+
+ return addr;
+ }
+ /* Insufficient space, fail. */
+ LOGE("Insufficient space, %zu blocks, %zu blocks allocated and %zu bytes allocated",
+ heapSource->totalBlocks,
+ heapSource->allocBlocks,
+ heapSource->bytesAllocated);
+ return NULL;
+}
+
+/* Converts an absolute address to a relative block number. */
+static size_t addressToBlock(const HeapSource *heapSource, const void *addr)
+{
+ assert(heapSource != NULL);
+ assert(isValidAddress(heapSource, addr));
+ return (((uintptr_t)addr) >> BLOCK_SHIFT) - heapSource->baseBlock;
+}
+
+/* Converts a relative block number to an absolute address. */
+static u1 *blockToAddress(const HeapSource *heapSource, size_t block)
+{
+ u1 *addr;
+
+ addr = (u1 *) (((uintptr_t) heapSource->baseBlock + block) * BLOCK_SIZE);
+ assert(isValidAddress(heapSource, addr));
+ return addr;
+}
+
+static void clearBlock(HeapSource *heapSource, size_t block)
+{
+ u1 *addr;
+ size_t i;
+
+ assert(heapSource != NULL);
+ assert(block < heapSource->totalBlocks);
+ addr = heapSource->blockBase + block*BLOCK_SIZE;
+ memset(addr, 0xCC, BLOCK_SIZE);
+ for (i = 0; i < BLOCK_SIZE; i += 8) {
+ dvmHeapBitmapClearObjectBit(&heapSource->allocBits, addr + i);
+ }
+}
+
+static void clearFromSpace(HeapSource *heapSource)
+{
+ size_t i, count;
+
+ assert(heapSource != NULL);
+ i = count = 0;
+ while (i < heapSource->totalBlocks) {
+ if (heapSource->blockSpace[i] != BLOCK_FROM_SPACE) {
+ ++i;
+ continue;
+ }
+ heapSource->blockSpace[i] = BLOCK_FREE;
+ clearBlock(heapSource, i);
+ ++i;
+ ++count;
+ while (i < heapSource->totalBlocks &&
+ heapSource->blockSpace[i] == BLOCK_CONTINUED) {
+ heapSource->blockSpace[i] = BLOCK_FREE;
+ clearBlock(heapSource, i);
+ ++i;
+ ++count;
+ }
+ }
+ LOG_SCAV("freed %zu blocks (%zu bytes)", count, count*BLOCK_SIZE);
+}
+
+/*
+ * Appends the given block to the block queue. The block queue is
+ * processed in-order by the scavenger.
+ */
+static void enqueueBlock(HeapSource *heapSource, size_t block)
+{
+ assert(heapSource != NULL);
+ assert(block < heapSource->totalBlocks);
+ if (heapSource->queueHead != QUEUE_TAIL) {
+ heapSource->blockQueue[heapSource->queueTail] = block;
+ } else {
+ heapSource->queueHead = block;
+ }
+ heapSource->blockQueue[block] = QUEUE_TAIL;
+ heapSource->queueTail = block;
+ ++heapSource->queueSize;
+}
+
+/*
+ * Grays all objects within the block corresponding to the given
+ * address.
+ */
+static void promoteBlockByAddr(HeapSource *heapSource, const void *addr)
+{
+ size_t block;
+
+ block = addressToBlock(heapSource, (const u1 *)addr);
+ if (heapSource->blockSpace[block] != BLOCK_TO_SPACE) {
+ // LOG_PROM("promoting block %zu %d @ %p", block, heapSource->blockSpace[block], obj);
+ heapSource->blockSpace[block] = BLOCK_TO_SPACE;
+ enqueueBlock(heapSource, block);
+ /* TODO(cshapiro): count continued blocks?*/
+ heapSource->allocBlocks += 1;
+ } else {
+ // LOG_PROM("NOT promoting block %zu %d @ %p", block, heapSource->blockSpace[block], obj);
+ }
+}
+
+GcHeap *dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
+{
+ GcHeap* gcHeap;
+ HeapSource *heapSource;
+
+ assert(startSize <= absoluteMaxSize);
+
+ heapSource = malloc(sizeof(*heapSource));
+ assert(heapSource != NULL);
+ memset(heapSource, 0, sizeof(*heapSource));
+
+ heapSource->minimumSize = alignUp(startSize, BLOCK_SIZE);
+ heapSource->maximumSize = alignUp(absoluteMaxSize, BLOCK_SIZE);
+
+ heapSource->currentSize = heapSource->maximumSize;
+
+ /* Allocate underlying storage for blocks. */
+ heapSource->blockBase = virtualAlloc(heapSource->maximumSize);
+ assert(heapSource->blockBase != NULL);
+ heapSource->baseBlock = (uintptr_t) heapSource->blockBase >> BLOCK_SHIFT;
+ heapSource->limitBlock = ((uintptr_t) heapSource->blockBase + heapSource->maximumSize) >> BLOCK_SHIFT;
+
+ heapSource->allocBlocks = 0;
+ heapSource->totalBlocks = (heapSource->limitBlock - heapSource->baseBlock);
+
+ assert(heapSource->totalBlocks = heapSource->maximumSize / BLOCK_SIZE);
+
+ {
+ size_t size = sizeof(heapSource->blockQueue[0]);
+ heapSource->blockQueue = malloc(heapSource->totalBlocks*size);
+ assert(heapSource->blockQueue != NULL);
+ memset(heapSource->blockQueue, 0xCC, heapSource->totalBlocks*size);
+ heapSource->queueHead = QUEUE_TAIL;
+ }
+
+ /* Byte indicating space residence or free status of block. */
+ {
+ size_t size = sizeof(heapSource->blockSpace[0]);
+ heapSource->blockSpace = malloc(heapSource->totalBlocks*size);
+ assert(heapSource->blockSpace != NULL);
+ memset(heapSource->blockSpace, 0, heapSource->totalBlocks*size);
+ }
+
+ dvmHeapBitmapInit(&heapSource->allocBits,
+ heapSource->blockBase,
+ heapSource->maximumSize,
+ "blockBase");
+
+ /* Initialize allocation pointers. */
+ heapSource->allocPtr = allocateBlocks(heapSource, 1);
+ heapSource->allocLimit = heapSource->allocPtr + BLOCK_SIZE;
+
+ gcHeap = malloc(sizeof(*gcHeap));
+ assert(gcHeap != NULL);
+ memset(gcHeap, 0, sizeof(*gcHeap));
+ gcHeap->heapSource = heapSource;
+
+ return gcHeap;
+}
+
+/*
+ * Perform any required heap initializations after forking from the
+ * zygote process. This is a no-op for the time being. Eventually
+ * this will demarcate the shared region of the heap.
+ */
+bool dvmHeapSourceStartupAfterZygote(void)
+{
+ return true;
+}
+
+bool dvmHeapSourceStartupBeforeFork(void)
+{
+ assert(!"implemented");
+ return false;
+}
+
+void dvmHeapSourceShutdown(GcHeap **gcHeap)
+{
+ if (*gcHeap == NULL || (*gcHeap)->heapSource == NULL)
+ return;
+ free((*gcHeap)->heapSource->blockQueue);
+ free((*gcHeap)->heapSource->blockSpace);
+ virtualFree((*gcHeap)->heapSource->blockBase,
+ (*gcHeap)->heapSource->maximumSize);
+ free((*gcHeap)->heapSource);
+ (*gcHeap)->heapSource = NULL;
+ free(*gcHeap);
+ *gcHeap = NULL;
+}
+
+size_t dvmHeapSourceGetValue(enum HeapSourceValueSpec spec,
+ size_t perHeapStats[],
+ size_t arrayLen)
+{
+ HeapSource *heapSource;
+ size_t value;
+
+ heapSource = gDvm.gcHeap->heapSource;
+ switch (spec) {
+ case HS_EXTERNAL_BYTES_ALLOCATED:
+ value = 0;
+ break;
+ case HS_EXTERNAL_LIMIT:
+ value = 0;
+ break;
+ case HS_FOOTPRINT:
+ value = heapSource->maximumSize;
+ break;
+ case HS_ALLOWED_FOOTPRINT:
+ value = heapSource->maximumSize;
+ break;
+ case HS_BYTES_ALLOCATED:
+ value = heapSource->bytesAllocated;
+ break;
+ case HS_OBJECTS_ALLOCATED:
+ value = sumHeapBitmap(&heapSource->allocBits);
+ break;
+ default:
+ assert(!"implemented");
+ value = 0;
+ }
+ if (perHeapStats) {
+ *perHeapStats = value;
+ }
+ return value;
+}
+
+/*
+ * Performs a shallow copy of the allocation bitmap into the given
+ * vector of heap bitmaps.
+ */
+void dvmHeapSourceGetObjectBitmaps(HeapBitmap objBits[], HeapBitmap markBits[],
+ size_t numHeaps)
+{
+ assert(!"implemented");
+}
+
+HeapBitmap *dvmHeapSourceGetLiveBits(void)
+{
+ return &gDvm.gcHeap->heapSource->allocBits;
+}
+
+/*
+ * Allocate the specified number of bytes from the heap. The
+ * allocation cursor points into a block of free storage. If the
+ * given allocation fits in the remaining space of the block, we
+ * advance the cursor and return a pointer to the free storage. If
+ * the allocation cannot fit in the current block but is smaller than
+ * a block we request a new block and allocate from it instead. If
+ * the allocation is larger than a block we must allocate from a span
+ * of contiguous blocks.
+ */
+void *dvmHeapSourceAlloc(size_t length)
+{
+ HeapSource *heapSource;
+ unsigned char *addr;
+ size_t aligned, available, blocks;
+
+ heapSource = gDvm.gcHeap->heapSource;
+ assert(heapSource != NULL);
+ assert(heapSource->allocPtr != NULL);
+ assert(heapSource->allocLimit != NULL);
+
+ aligned = alignUp(length, ALLOC_ALIGNMENT);
+ available = heapSource->allocLimit - heapSource->allocPtr;
+
+ /* Try allocating inside the current block. */
+ if (aligned <= available) {
+ addr = heapSource->allocPtr;
+ heapSource->allocPtr += aligned;
+ heapSource->bytesAllocated += aligned;
+ dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
+ return addr;
+ }
+
+ /* Try allocating in a new block. */
+ if (aligned <= BLOCK_SIZE) {
+ addr = allocateBlocks(heapSource, 1);
+ if (addr != NULL) {
+ heapSource->allocLimit = addr + BLOCK_SIZE;
+ heapSource->allocPtr = addr + aligned;
+ heapSource->bytesAllocated += aligned;
+ dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
+ /* TODO(cshapiro): pad out the current block. */
+ }
+ return addr;
+ }
+
+ /* Try allocating in a span of blocks. */
+ blocks = alignUp(aligned, BLOCK_SIZE) / BLOCK_SIZE;
+
+ addr = allocateBlocks(heapSource, blocks);
+ /* Propagate failure upward. */
+ if (addr != NULL) {
+ heapSource->bytesAllocated += aligned;
+ dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
+ /* TODO(cshapiro): pad out free space in the last block. */
+ }
+ return addr;
+}
+
+void *dvmHeapSourceAllocAndGrow(size_t size)
+{
+ return dvmHeapSourceAlloc(size);
+}
+
+/* TODO: refactor along with dvmHeapSourceAlloc */
+void *allocateGray(size_t size)
+{
+ HeapSource *heapSource;
+ void *addr;
+ size_t block;
+
+ /* TODO: add a check that we are in a GC. */
+ heapSource = gDvm.gcHeap->heapSource;
+ addr = dvmHeapSourceAlloc(size);
+ assert(addr != NULL);
+ block = addressToBlock(heapSource, (const u1 *)addr);
+ if (heapSource->queueHead == QUEUE_TAIL) {
+ /*
+ * Forcibly append the underlying block to the queue. This
+ * condition occurs when referents are transported following
+ * the initial trace.
+ */
+ enqueueBlock(heapSource, block);
+ LOG_PROM("forced promoting block %zu %d @ %p", block, heapSource->blockSpace[block], addr);
+ }
+ return addr;
+}
+
+bool dvmHeapSourceContainsAddress(const void *ptr)
+{
+ HeapSource *heapSource = gDvm.gcHeap->heapSource;
+ return dvmHeapBitmapCoversAddress(&heapSource->allocBits, ptr);
+}
+
+/*
+ * Returns true if the given address is within the heap and points to
+ * the header of a live object.
+ */
+bool dvmHeapSourceContains(const void *addr)
+{
+ HeapSource *heapSource;
+ HeapBitmap *bitmap;
+
+ heapSource = gDvm.gcHeap->heapSource;
+ bitmap = &heapSource->allocBits;
+ if (!dvmHeapBitmapCoversAddress(bitmap, addr)) {
+ return false;
+ } else {
+ return dvmHeapBitmapIsObjectBitSet(bitmap, addr);
+ }
+}
+
+bool dvmHeapSourceGetPtrFlag(const void *ptr, enum HeapSourcePtrFlag flag)
+{
+ assert(!"implemented");
+ return false;
+}
+
+size_t dvmHeapSourceChunkSize(const void *ptr)
+{
+ assert(!"implemented");
+ return 0;
+}
+
+size_t dvmHeapSourceFootprint(void)
+{
+ assert(!"implemented");
+ return 0;
+}
+
+/*
+ * Returns the "ideal footprint" which appears to be the number of
+ * bytes currently committed to the heap. This starts out at the
+ * start size of the heap and grows toward the maximum size.
+ */
+size_t dvmHeapSourceGetIdealFootprint(void)
+{
+ return gDvm.gcHeap->heapSource->currentSize;
+}
+
+float dvmGetTargetHeapUtilization(void)
+{
+ return 0.5f;
+}
+
+void dvmSetTargetHeapUtilization(float newTarget)
+{
+ assert(newTarget > 0.0f && newTarget < 1.0f);
+}
+
+size_t dvmMinimumHeapSize(size_t size, bool set)
+{
+ return gDvm.gcHeap->heapSource->minimumSize;
+}
+
+/*
+ * Expands the size of the heap after a collection. At present we
+ * commit the pages for maximum size of the heap so this routine is
+ * just a no-op. Eventually, we will either allocate or commit pages
+ * on an as-need basis.
+ */
+void dvmHeapSourceGrowForUtilization(void)
+{
+ /* do nothing */
+}
+
+void dvmHeapSourceTrim(size_t bytesTrimmed[], size_t arrayLen)
+{
+ /* do nothing */
+}
+
+void dvmHeapSourceWalk(void (*callback)(const void *chunkptr, size_t chunklen,
+ const void *userptr, size_t userlen,
+ void *arg),
+ void *arg)
+{
+ assert(!"implemented");
+}
+
+size_t dvmHeapSourceGetNumHeaps(void)
+{
+ return 1;
+}
+
+bool dvmTrackExternalAllocation(size_t n)
+{
+ /* do nothing */
+ return true;
+}
+
+void dvmTrackExternalFree(size_t n)
+{
+ /* do nothing */
+}
+
+size_t dvmGetExternalBytesAllocated(void)
+{
+ assert(!"implemented");
+ return 0;
+}
+
+void dvmHeapSourceFlip(void)
+{
+ HeapSource *heapSource;
+ size_t i;
+
+ heapSource = gDvm.gcHeap->heapSource;
+
+ /* Reset the block queue. */
+ heapSource->allocBlocks = 0;
+ heapSource->queueSize = 0;
+ heapSource->queueHead = QUEUE_TAIL;
+
+ /* TODO(cshapiro): pad the current (prev) block. */
+
+ heapSource->allocPtr = NULL;
+ heapSource->allocLimit = NULL;
+
+ /* Whiten all allocated blocks. */
+ for (i = 0; i < heapSource->totalBlocks; ++i) {
+ if (heapSource->blockSpace[i] == BLOCK_TO_SPACE) {
+ heapSource->blockSpace[i] = BLOCK_FROM_SPACE;
+ }
+ }
+}
+
+static void room(size_t *alloc, size_t *avail, size_t *total)
+{
+ HeapSource *heapSource;
+
+ heapSource = gDvm.gcHeap->heapSource;
+ *total = heapSource->totalBlocks*BLOCK_SIZE;
+ *alloc = heapSource->allocBlocks*BLOCK_SIZE;
+ *avail = *total - *alloc;
+}
+
+static bool isSpaceInternal(u1 *addr, int space)
+{
+ HeapSource *heapSource;
+ u1 *base, *limit;
+ size_t offset;
+ char space2;
+
+ heapSource = gDvm.gcHeap->heapSource;
+ base = heapSource->blockBase;
+ assert(addr >= base);
+ limit = heapSource->blockBase + heapSource->maximumSize;
+ assert(addr < limit);
+ offset = addr - base;
+ space2 = heapSource->blockSpace[offset >> BLOCK_SHIFT];
+ return space == space2;
+}
+
+static bool fromSpaceContains(const void *addr)
+{
+ return isSpaceInternal((u1 *)addr, BLOCK_FROM_SPACE);
+}
+
+static bool toSpaceContains(const void *addr)
+{
+ return isSpaceInternal((u1 *)addr, BLOCK_TO_SPACE);
+}
+
+/*
+ * Notifies the collector that the object at the given address must
+ * remain stationary during the current collection.
+ */
+static void pinObject(const Object *obj)
+{
+ promoteBlockByAddr(gDvm.gcHeap->heapSource, obj);
+}
+
+static size_t sumHeapBitmap(const HeapBitmap *bitmap)
+{
+ size_t i, sum;
+
+ sum = 0;
+ for (i = 0; i < bitmap->bitsLen >> 2; ++i) {
+ sum += CLZ(bitmap->bits[i]);
+ }
+ return sum;
+}
+
+/*
+ * Miscellaneous functionality.
+ */
+
+static int isForward(const void *addr)
+{
+ return (uintptr_t)addr & 0x1;
+}
+
+static void setForward(const void *toObj, void *fromObj)
+{
+ *(unsigned long *)fromObj = (uintptr_t)toObj | 0x1;
+}
+
+static void* getForward(const void *fromObj)
+{
+ return (void *)((uintptr_t)fromObj & ~0x1);
+}
+
+/* Beware, uses the same encoding as a forwarding pointers! */
+static int isPermanentString(const StringObject *obj) {
+ return (uintptr_t)obj & 0x1;
+}
+
+static void* getPermanentString(const StringObject *obj)
+{
+ return (void *)((uintptr_t)obj & ~0x1);
+}
+
+
+/*
+ * Scavenging and transporting routines follow. A transporter grays
+ * an object. A scavenger blackens an object. We define these
+ * routines for each fundamental object type. Dispatch is performed
+ * in scavengeObject.
+ */
+
+/*
+ * Class object scavenging.
+ */
+static void scavengeClassObject(ClassObject *obj)
+{
+ int i;
+
+ LOG_SCAV("scavengeClassObject(obj=%p)", obj);
+ assert(obj != NULL);
+ assert(obj->obj.clazz != NULL);
+ assert(obj->obj.clazz->descriptor != NULL);
+ assert(!strcmp(obj->obj.clazz->descriptor, "Ljava/lang/Class;"));
+ assert(obj->descriptor != NULL);
+ LOG_SCAV("scavengeClassObject: descriptor='%s',vtableCount=%zu",
+ obj->descriptor, obj->vtableCount);
+ /* Delegate class object and instance field scavenging. */
+ scavengeDataObject((Object *)obj);
+ /* Scavenge the array element class object. */
+ if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
+ scavengeReference((Object **)(void *)&obj->elementClass);
+ }
+ /* Scavenge the superclass. */
+ scavengeReference((Object **)(void *)&obj->super);
+ /* Scavenge the class loader. */
+ scavengeReference(&obj->classLoader);
+ /* Scavenge static fields. */
+ for (i = 0; i < obj->sfieldCount; ++i) {
+ char ch = obj->sfields[i].field.signature[0];
+ if (ch == '[' || ch == 'L') {
+ scavengeReference((Object **)(void *)&obj->sfields[i].value.l);
+ }
+ }
+ /* Scavenge interface class objects. */
+ for (i = 0; i < obj->interfaceCount; ++i) {
+ scavengeReference((Object **) &obj->interfaces[i]);
+ }
+}
+
+/*
+ * Array object scavenging.
+ */
+static size_t scavengeArrayObject(ArrayObject *array)
+{
+ size_t i, length;
+
+ LOG_SCAV("scavengeArrayObject(array=%p)", array);
+ /* Scavenge the class object. */
+ assert(toSpaceContains(array));
+ assert(array != NULL);
+ assert(array->obj.clazz != NULL);
+ scavengeReference((Object **) array);
+ length = dvmArrayObjectSize(array);
+ /* Scavenge the array contents. */
+ if (IS_CLASS_FLAG_SET(array->obj.clazz, CLASS_ISOBJECTARRAY)) {
+ Object **contents = (Object **)array->contents;
+ for (i = 0; i < array->length; ++i) {
+ scavengeReference(&contents[i]);
+ }
+ }
+ return length;
+}
+
+/*
+ * Reference object scavenging.
+ */
+
+static int getReferenceFlags(const Object *obj)
+{
+ int flags;
+
+ flags = CLASS_ISREFERENCE |
+ CLASS_ISWEAKREFERENCE |
+ CLASS_ISPHANTOMREFERENCE;
+ return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
+}
+
+static int isSoftReference(const Object *obj)
+{
+ return getReferenceFlags(obj) == CLASS_ISREFERENCE;
+}
+
+static int isWeakReference(const Object *obj)
+{
+ return getReferenceFlags(obj) & CLASS_ISWEAKREFERENCE;
+}
+
+#ifndef NDEBUG
+static bool isPhantomReference(const Object *obj)
+{
+ return getReferenceFlags(obj) & CLASS_ISPHANTOMREFERENCE;
+}
+#endif
+
+/*
+ * Returns true if the reference was registered with a reference queue
+ * but has not yet been appended to it.
+ */
+static bool isReferenceEnqueuable(const Object *ref)
+{
+ Object *queue, *queueNext;
+
+ queue = dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue);
+ queueNext = dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext);
+ if (queue == NULL || queueNext != NULL) {
+ /*
+ * There is no queue, or the reference has already
+ * been enqueued. The Reference.enqueue() method
+ * will do nothing even if we call it.
+ */
+ return false;
+ }
+
+ /*
+ * We need to call enqueue(), but if we called it from
+ * here we'd probably deadlock. Schedule a call.
+ */
+ return true;
+}
+
+/*
+ * Schedules a reference to be appended to its reference queue.
+ */
+static void enqueueReference(Object *ref)
+{
+ assert(ref != NULL);
+ assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
+ assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
+ if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
+ LOGE("no room for any more reference operations");
+ dvmAbort();
+ }
+}
+
+/*
+ * Sets the referent field of a reference object to NULL.
+ */
+static void clearReference(Object *obj)
+{
+ dvmSetFieldObject(obj, gDvm.offJavaLangRefReference_referent, NULL);
+}
+
+/*
+ * Clears reference objects with white referents.
+ */
+void clearWhiteReferences(Object **list)
+{
+ size_t referentOffset, queueNextOffset;
+ bool doSignal;
+
+ queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
+ referentOffset = gDvm.offJavaLangRefReference_referent;
+ doSignal = false;
+ while (*list != NULL) {
+ Object *ref = *list;
+ JValue *field = dvmFieldPtr(ref, referentOffset);
+ Object *referent = field->l;
+ *list = dvmGetFieldObject(ref, queueNextOffset);
+ dvmSetFieldObject(ref, queueNextOffset, NULL);
+ assert(referent != NULL);
+ if (isForward(referent->clazz)) {
+ field->l = referent = getForward(referent->clazz);
+ continue;
+ }
+ if (fromSpaceContains(referent)) {
+ /* Referent is white, clear it. */
+ clearReference(ref);
+ if (isReferenceEnqueuable(ref)) {
+ enqueueReference(ref);
+ doSignal = true;
+ }
+ }
+ }
+ /*
+ * If we cleared a reference with a reference queue we must notify
+ * the heap worker to append the reference.
+ */
+ if (doSignal) {
+ dvmSignalHeapWorker(false);
+ }
+ assert(*list == NULL);
+}
+
+/*
+ * Blackens referents subject to the soft reference preservation
+ * policy.
+ */
+void preserveSoftReferences(Object **list)
+{
+ Object *ref;
+ Object *prev, *next;
+ size_t referentOffset, queueNextOffset;
+ unsigned counter;
+ bool white;
+
+ queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
+ referentOffset = gDvm.offJavaLangRefReference_referent;
+ counter = 0;
+ prev = next = NULL;
+ ref = *list;
+ while (ref != NULL) {
+ JValue *field = dvmFieldPtr(ref, referentOffset);
+ Object *referent = field->l;
+ next = dvmGetFieldObject(ref, queueNextOffset);
+ assert(referent != NULL);
+ if (isForward(referent->clazz)) {
+ /* Referent is black. */
+ field->l = referent = getForward(referent->clazz);
+ white = false;
+ } else {
+ white = fromSpaceContains(referent);
+ }
+ if (!white && ((++counter) & 1)) {
+ /* Referent is white and biased toward saving, gray it. */
+ scavengeReference((Object **)(void *)&field->l);
+ white = true;
+ }
+ if (white) {
+ /* Referent is black, unlink it. */
+ if (prev != NULL) {
+ dvmSetFieldObject(ref, queueNextOffset, NULL);
+ dvmSetFieldObject(prev, queueNextOffset, next);
+ }
+ } else {
+ /* Referent is white, skip over it. */
+ prev = ref;
+ }
+ ref = next;
+ }
+ /*
+ * Restart the trace with the newly gray references added to the
+ * root set.
+ */
+ scavengeBlockQueue();
+}
+
+void processFinalizableReferences(void)
+{
+ HeapRefTable newPendingRefs;
+ LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
+ Object **ref;
+ Object **lastRef;
+ size_t totalPendCount;
+
+ /*
+ * All strongly, reachable objects are black.
+ * Any white finalizable objects need to be finalized.
+ */
+
+ /* Create a table that the new pending refs will
+ * be added to.
+ */
+ if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
+ //TODO: mark all finalizable refs and hope that
+ // we can schedule them next time. Watch out,
+ // because we may be expecting to free up space
+ // by calling finalizers.
+ LOG_REF("no room for pending finalizations\n");
+ dvmAbort();
+ }
+
+ /*
+ * Walk through finalizableRefs and move any white references to
+ * the list of new pending refs.
+ */
+ totalPendCount = 0;
+ while (finRefs != NULL) {
+ Object **gapRef;
+ size_t newPendCount = 0;
+
+ gapRef = ref = finRefs->refs.table;
+ lastRef = finRefs->refs.nextEntry;
+ while (ref < lastRef) {
+ if (fromSpaceContains(*ref)) {
+ if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
+ //TODO: add the current table and allocate
+ // a new, smaller one.
+ LOG_REF("no room for any more pending finalizations: %zd\n",
+ dvmHeapNumHeapRefTableEntries(&newPendingRefs));
+ dvmAbort();
+ }
+ newPendCount++;
+ } else {
+ /* This ref is black, so will remain on finalizableRefs.
+ */
+ if (newPendCount > 0) {
+ /* Copy it up to fill the holes.
+ */
+ *gapRef++ = *ref;
+ } else {
+ /* No holes yet; don't bother copying.
+ */
+ gapRef++;
+ }
+ }
+ ref++;
+ }
+ finRefs->refs.nextEntry = gapRef;
+ //TODO: if the table is empty when we're done, free it.
+ totalPendCount += newPendCount;
+ finRefs = finRefs->next;
+ }
+ LOG_REF("%zd finalizers triggered.\n", totalPendCount);
+ if (totalPendCount == 0) {
+ /* No objects required finalization.
+ * Free the empty temporary table.
+ */
+ dvmClearReferenceTable(&newPendingRefs);
+ return;
+ }
+
+ /* Add the new pending refs to the main list.
+ */
+ if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
+ &newPendingRefs))
+ {
+ LOG_REF("can't insert new pending finalizations\n");
+ dvmAbort();
+ }
+
+ //TODO: try compacting the main list with a memcpy loop
+
+ /* Blacken the refs we just moved; we don't want them or their
+ * children to get swept yet.
+ */
+ ref = newPendingRefs.table;
+ lastRef = newPendingRefs.nextEntry;
+ assert(ref < lastRef);
+ HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
+ while (ref < lastRef) {
+ scavengeReference(ref);
+ ref++;
+ }
+ HPROF_CLEAR_GC_SCAN_STATE();
+ scavengeBlockQueue();
+ dvmSignalHeapWorker(false);
+}
+
+/*
+ * If a reference points to from-space and has been forwarded, we snap
+ * the pointer to its new to-space address. If the reference points
+ * to an unforwarded from-space address we must enqueue the reference
+ * for later processing. TODO: implement proper reference processing
+ * and move the referent scavenging elsewhere.
+ */
+static void scavengeReferenceObject(Object *obj)
+{
+ Object *referent;
+ Object **queue;
+ size_t referentOffset, queueNextOffset;
+
+ assert(obj != NULL);
+ LOG_SCAV("scavengeReferenceObject(obj=%p),'%s'", obj, obj->clazz->descriptor);
+ scavengeDataObject(obj);
+ referentOffset = gDvm.offJavaLangRefReference_referent;
+ referent = dvmGetFieldObject(obj, referentOffset);
+ if (referent == NULL || toSpaceContains(referent)) {
+ return;
+ }
+ if (isSoftReference(obj)) {
+ queue = &gDvm.gcHeap->softReferences;
+ } else if (isWeakReference(obj)) {
+ queue = &gDvm.gcHeap->weakReferences;
+ } else {
+ assert(isPhantomReference(obj));
+ queue = &gDvm.gcHeap->phantomReferences;
+ }
+ queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
+ dvmSetFieldObject(obj, queueNextOffset, *queue);
+ *queue = obj;
+ LOG_SCAV("scavengeReferenceObject: enqueueing %p", obj);
+}
+
+/*
+ * Data object scavenging.
+ */
+static void scavengeDataObject(Object *obj)
+{
+ ClassObject *clazz;
+ int i;
+
+ // LOG_SCAV("scavengeDataObject(obj=%p)", obj);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ assert(obj->clazz->objectSize != 0);
+ assert(toSpaceContains(obj));
+ /* Scavenge the class object. */
+ clazz = obj->clazz;
+ scavengeReference((Object **) obj);
+ /* Scavenge instance fields. */
+ if (clazz->refOffsets != CLASS_WALK_SUPER) {
+ size_t refOffsets = clazz->refOffsets;
+ while (refOffsets != 0) {
+ size_t rshift = CLZ(refOffsets);
+ size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
+ Object **ref = (Object **)((u1 *)obj + offset);
+ scavengeReference(ref);
+ refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
+ }
+ } else {
+ for (; clazz != NULL; clazz = clazz->super) {
+ InstField *field = clazz->ifields;
+ for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
+ size_t offset = field->byteOffset;
+ Object **ref = (Object **)((u1 *)obj + offset);
+ scavengeReference(ref);
+ }
+ }
+ }
+}
+
+static Object *transportObject(const Object *fromObj)
+{
+ Object *toObj;
+ size_t allocSize, copySize;
+
+ LOG_TRAN("transportObject(fromObj=%p) allocBlocks=%zu",
+ fromObj,
+ gDvm.gcHeap->heapSource->allocBlocks);
+ assert(fromObj != NULL);
+ assert(fromSpaceContains(fromObj));
+ allocSize = copySize = objectSize(fromObj);
+ if (LW_HASH_STATE(fromObj->lock) != LW_HASH_STATE_UNHASHED) {
+ /*
+ * The object has been hashed or hashed and moved. We must
+ * reserve an additional word for a hash code.
+ */
+ allocSize += sizeof(u4);
+ }
+ if (LW_HASH_STATE(fromObj->lock) == LW_HASH_STATE_HASHED_AND_MOVED) {
+ /*
+ * The object has its hash code allocated. Ensure the hash
+ * code is copied along with the instance data.
+ */
+ copySize += sizeof(u4);
+ }
+ /* TODO(cshapiro): don't copy, re-map large data objects. */
+ assert(copySize <= allocSize);
+ toObj = allocateGray(allocSize);
+ assert(toObj != NULL);
+ assert(toSpaceContains(toObj));
+ memcpy(toObj, fromObj, copySize);
+ if (LW_HASH_STATE(fromObj->lock) == LW_HASH_STATE_HASHED) {
+ /*
+ * The object has had its hash code exposed. Append it to the
+ * instance and set a bit so we know to look for it there.
+ */
+ *(u4 *)(((char *)toObj) + copySize) = (u4)fromObj >> 3;
+ toObj->lock |= LW_HASH_STATE_HASHED_AND_MOVED << LW_HASH_STATE_SHIFT;
+ }
+ LOG_TRAN("transportObject: from %p/%zu to %p/%zu (%zu,%zu) %s",
+ fromObj, addressToBlock(gDvm.gcHeap->heapSource,fromObj),
+ toObj, addressToBlock(gDvm.gcHeap->heapSource,toObj),
+ copySize, allocSize, copySize < allocSize ? "DIFFERENT" : "");
+ return toObj;
+}
+
+/*
+ * Generic reference scavenging.
+ */
+
+/*
+ * Given a reference to an object, the scavenge routine will gray the
+ * reference. Any objects pointed to by the scavenger object will be
+ * transported to new space and a forwarding pointer will be installed
+ * in the header of the object.
+ */
+
+/*
+ * Blacken the given pointer. If the pointer is in from space, it is
+ * transported to new space. If the object has a forwarding pointer
+ * installed it has already been transported and the referent is
+ * snapped to the new address.
+ */
+static void scavengeReference(Object **obj)
+{
+ ClassObject *clazz;
+ Object *fromObj, *toObj;
+
+ assert(obj);
+
+ if (*obj == NULL) return;
+
+ assert(dvmIsValidObject(*obj));
+
+ /* The entire block is black. */
+ if (toSpaceContains(*obj)) {
+ LOG_SCAV("scavengeReference skipping pinned object @ %p", *obj);
+ return;
+ }
+ LOG_SCAV("scavengeReference(*obj=%p)", *obj);
+
+ assert(fromSpaceContains(*obj));
+
+ clazz = (*obj)->clazz;
+
+ if (isForward(clazz)) {
+ // LOG_SCAV("forwarding %p @ %p to %p", *obj, obj, (void *)((uintptr_t)clazz & ~0x1));
+ *obj = (Object *)getForward(clazz);
+ return;
+ }
+ fromObj = *obj;
+ if (clazz == NULL) {
+ // LOG_SCAV("scavangeReference %p has a NULL class object", fromObj);
+ assert(!"implemented");
+ toObj = NULL;
+ } else {
+ toObj = transportObject(fromObj);
+ }
+ setForward(toObj, fromObj);
+ *obj = (Object *)toObj;
+}
+
+/*
+ * Generic object scavenging.
+ */
+static void scavengeObject(Object *obj)
+{
+ ClassObject *clazz;
+
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ assert(!((uintptr_t)obj->clazz & 0x1));
+ clazz = obj->clazz;
+ if (clazz == gDvm.classJavaLangClass) {
+ scavengeClassObject((ClassObject *)obj);
+ } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
+ scavengeArrayObject((ArrayObject *)obj);
+ } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
+ scavengeReferenceObject(obj);
+ } else {
+ scavengeDataObject(obj);
+ }
+}
+
+/*
+ * External root scavenging routines.
+ */
+
+static void pinHashTableEntries(HashTable *table)
+{
+ HashEntry *entry;
+ void *obj;
+ int i;
+
+ LOG_PIN(">>> pinHashTableEntries(table=%p)", table);
+ if (table == NULL) {
+ return;
+ }
+ dvmHashTableLock(table);
+ for (i = 0; i < table->tableSize; ++i) {
+ entry = &table->pEntries[i];
+ obj = entry->data;
+ if (obj == NULL || obj == HASH_TOMBSTONE) {
+ continue;
+ }
+ pinObject(entry->data);
+ }
+ dvmHashTableUnlock(table);
+ LOG_PIN("<<< pinHashTableEntries(table=%p)", table);
+}
+
+static void pinPrimitiveClasses(void)
+{
+ size_t length;
+ size_t i;
+
+ length = ARRAYSIZE(gDvm.primitiveClass);
+ for (i = 0; i < length; i++) {
+ if (gDvm.primitiveClass[i] != NULL) {
+ pinObject((Object *)gDvm.primitiveClass[i]);
+ }
+ }
+}
+
+/*
+ * Scavenge interned strings. Permanent interned strings will have
+ * been pinned and are therefore ignored. Non-permanent strings that
+ * have been forwarded are snapped. All other entries are removed.
+ */
+static void scavengeInternedStrings(void)
+{
+ HashTable *table;
+ HashEntry *entry;
+ Object *obj;
+ int i;
+
+ table = gDvm.internedStrings;
+ if (table == NULL) {
+ return;
+ }
+ dvmHashTableLock(table);
+ for (i = 0; i < table->tableSize; ++i) {
+ entry = &table->pEntries[i];
+ obj = (Object *)entry->data;
+ if (obj == NULL || obj == HASH_TOMBSTONE) {
+ continue;
+ } else if (!isPermanentString((StringObject *)obj)) {
+ // LOG_SCAV("entry->data=%p", entry->data);
+ LOG_SCAV(">>> string obj=%p", entry->data);
+ /* TODO(cshapiro): detach white string objects */
+ scavengeReference((Object **)(void *)&entry->data);
+ LOG_SCAV("<<< string obj=%p", entry->data);
+ }
+ }
+ dvmHashTableUnlock(table);
+}
+
+static void pinInternedStrings(void)
+{
+ HashTable *table;
+ HashEntry *entry;
+ Object *obj;
+ int i;
+
+ table = gDvm.internedStrings;
+ if (table == NULL) {
+ return;
+ }
+ dvmHashTableLock(table);
+ for (i = 0; i < table->tableSize; ++i) {
+ entry = &table->pEntries[i];
+ obj = (Object *)entry->data;
+ if (obj == NULL || obj == HASH_TOMBSTONE) {
+ continue;
+ } else if (isPermanentString((StringObject *)obj)) {
+ obj = (Object *)getPermanentString((StringObject*)obj);
+ LOG_PROM(">>> pin string obj=%p", obj);
+ pinObject(obj);
+ LOG_PROM("<<< pin string obj=%p", obj);
+ }
+ }
+ dvmHashTableUnlock(table);
+}
+
+/*
+ * At present, reference tables contain references that must not be
+ * moved by the collector. Instead of scavenging each reference in
+ * the table we pin each referenced object.
+ */
+static void pinReferenceTable(const ReferenceTable *table)
+{
+ Object **entry;
+
+ assert(table != NULL);
+ assert(table->table != NULL);
+ assert(table->nextEntry != NULL);
+ for (entry = table->table; entry < table->nextEntry; ++entry) {
+ assert(entry != NULL);
+ assert(!isForward(*entry));
+ pinObject(*entry);
+ }
+}
+
+static void scavengeLargeHeapRefTable(LargeHeapRefTable *table)
+{
+ for (; table != NULL; table = table->next) {
+ Object **ref = table->refs.table;
+ for (; ref < table->refs.nextEntry; ++ref) {
+ scavengeReference(ref);
+ }
+ }
+}
+
+/* This code was copied from Thread.c */
+static void scavengeThreadStack(Thread *thread)
+{
+ const u4 *framePtr;
+#if WITH_EXTRA_GC_CHECKS > 1
+ bool first = true;
+#endif
+
+ framePtr = (const u4 *)thread->curFrame;
+ while (framePtr != NULL) {
+ const StackSaveArea *saveArea;
+ const Method *method;
+
+ saveArea = SAVEAREA_FROM_FP(framePtr);
+ method = saveArea->method;
+ if (method != NULL && !dvmIsNativeMethod(method)) {
+#ifdef COUNT_PRECISE_METHODS
+ /* the GC is running, so no lock required */
+ if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
+ LOG_SCAV("PGC: added %s.%s %p\n",
+ method->clazz->descriptor, method->name, method);
+#endif
+#if WITH_EXTRA_GC_CHECKS > 1
+ /*
+ * May also want to enable the memset() in the "invokeMethod"
+ * goto target in the portable interpreter. That sets the stack
+ * to a pattern that makes referring to uninitialized data
+ * very obvious.
+ */
+
+ if (first) {
+ /*
+ * First frame, isn't native, check the "alternate" saved PC
+ * as a sanity check.
+ *
+ * It seems like we could check the second frame if the first
+ * is native, since the PCs should be the same. It turns out
+ * this doesn't always work. The problem is that we could
+ * have calls in the sequence:
+ * interp method #2
+ * native method
+ * interp method #1
+ *
+ * and then GC while in the native method after returning
+ * from interp method #2. The currentPc on the stack is
+ * for interp method #1, but thread->currentPc2 is still
+ * set for the last thing interp method #2 did.
+ *
+ * This can also happen in normal execution:
+ * - sget-object on not-yet-loaded class
+ * - class init updates currentPc2
+ * - static field init is handled by parsing annotations;
+ * static String init requires creation of a String object,
+ * which can cause a GC
+ *
+ * Essentially, any pattern that involves executing
+ * interpreted code and then causes an allocation without
+ * executing instructions in the original method will hit
+ * this. These are rare enough that the test still has
+ * some value.
+ */
+ if (saveArea->xtra.currentPc != thread->currentPc2) {
+ LOGW("PGC: savedPC(%p) != current PC(%p), %s.%s ins=%p\n",
+ saveArea->xtra.currentPc, thread->currentPc2,
+ method->clazz->descriptor, method->name, method->insns);
+ if (saveArea->xtra.currentPc != NULL)
+ LOGE(" pc inst = 0x%04x\n", *saveArea->xtra.currentPc);
+ if (thread->currentPc2 != NULL)
+ LOGE(" pc2 inst = 0x%04x\n", *thread->currentPc2);
+ dvmDumpThread(thread, false);
+ }
+ } else {
+ /*
+ * It's unusual, but not impossible, for a non-first frame
+ * to be at something other than a method invocation. For
+ * example, if we do a new-instance on a nonexistent class,
+ * we'll have a lot of class loader activity on the stack
+ * above the frame with the "new" operation. Could also
+ * happen while we initialize a Throwable when an instruction
+ * fails.
+ *
+ * So there's not much we can do here to verify the PC,
+ * except to verify that it's a GC point.
+ */
+ }
+ assert(saveArea->xtra.currentPc != NULL);
+#endif
+
+ const RegisterMap* pMap;
+ const u1* regVector;
+ int i;
+
+ Method* nonConstMethod = (Method*) method; // quiet gcc
+ pMap = dvmGetExpandedRegisterMap(nonConstMethod);
+
+ //LOG_SCAV("PGC: %s.%s\n", method->clazz->descriptor, method->name);
+
+ if (pMap != NULL) {
+ /* found map, get registers for this address */
+ int addr = saveArea->xtra.currentPc - method->insns;
+ regVector = dvmRegisterMapGetLine(pMap, addr);
+ /*
+ if (regVector == NULL) {
+ LOG_SCAV("PGC: map but no entry for %s.%s addr=0x%04x\n",
+ method->clazz->descriptor, method->name, addr);
+ } else {
+ LOG_SCAV("PGC: found map for %s.%s 0x%04x (t=%d)\n",
+ method->clazz->descriptor, method->name, addr,
+ thread->threadId);
+ }
+ */
+ } else {
+ /*
+ * No map found. If precise GC is disabled this is
+ * expected -- we don't create pointers to the map data even
+ * if it's present -- but if it's enabled it means we're
+ * unexpectedly falling back on a conservative scan, so it's
+ * worth yelling a little.
+ */
+ if (gDvm.preciseGc) {
+ LOG_SCAV("PGC: no map for %s.%s\n", method->clazz->descriptor, method->name);
+ }
+ regVector = NULL;
+ }
+ if (regVector == NULL) {
+ /*
+ * There are no roots to scavenge. Skip over the entire frame.
+ */
+ framePtr += method->registersSize;
+ } else {
+ /*
+ * Precise scan. v0 is at the lowest address on the
+ * interpreted stack, and is the first bit in the register
+ * vector, so we can walk through the register map and
+ * memory in the same direction.
+ *
+ * A '1' bit indicates a live reference.
+ */
+ u2 bits = 1 << 1;
+ for (i = method->registersSize - 1; i >= 0; i--) {
+ u4 rval = *framePtr;
+
+ bits >>= 1;
+ if (bits == 1) {
+ /* set bit 9 so we can tell when we're empty */
+ bits = *regVector++ | 0x0100;
+ }
+
+ if (rval != 0 && (bits & 0x01) != 0) {
+ /*
+ * Non-null, register marked as live reference. This
+ * should always be a valid object.
+ */
+#if WITH_EXTRA_GC_CHECKS > 0
+ if ((rval & 0x3) != 0 || !dvmIsValidObject((Object*) rval)) {
+ /* this is very bad */
+ LOGE("PGC: invalid ref in reg %d: 0x%08x\n",
+ method->registersSize-1 - i, rval);
+ } else
+#endif
+ {
+
+ // LOG_SCAV("stack reference %u@%p", *framePtr, framePtr);
+ /* dvmMarkObjectNonNull((Object *)rval); */
+ scavengeReference((Object **) framePtr);
+ }
+ } else {
+ /*
+ * Null or non-reference, do nothing at all.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+ if (dvmIsValidObject((Object*) rval)) {
+ /* this is normal, but we feel chatty */
+ LOGD("PGC: ignoring valid ref in reg %d: 0x%08x\n",
+ method->registersSize-1 - i, rval);
+ }
+#endif
+ }
+ ++framePtr;
+ }
+ dvmReleaseRegisterMapLine(pMap, regVector);
+ }
+ }
+ /* else this is a break frame and there is nothing to gray, or
+ * this is a native method and the registers are just the "ins",
+ * copied from various registers in the caller's set.
+ */
+
+#if WITH_EXTRA_GC_CHECKS > 1
+ first = false;
+#endif
+
+ /* Don't fall into an infinite loop if things get corrupted.
+ */
+ assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
+ saveArea->prevFrame == NULL);
+ framePtr = saveArea->prevFrame;
+ }
+}
+
+static void scavengeThread(Thread *thread)
+{
+ assert(thread->status != THREAD_RUNNING ||
+ thread->isSuspended ||
+ thread == dvmThreadSelf());
+
+ // LOG_SCAV("scavengeThread(thread=%p)", thread);
+
+ // LOG_SCAV("Scavenging threadObj=%p", thread->threadObj);
+ scavengeReference(&thread->threadObj);
+
+ // LOG_SCAV("Scavenging exception=%p", thread->exception);
+ scavengeReference(&thread->exception);
+
+ scavengeThreadStack(thread);
+}
+
+static void scavengeThreadList(void)
+{
+ Thread *thread;
+
+ dvmLockThreadList(dvmThreadSelf());
+ thread = gDvm.threadList;
+ while (thread) {
+ scavengeThread(thread);
+ thread = thread->next;
+ }
+ dvmUnlockThreadList();
+}
+
+static void pinThreadStack(const Thread *thread)
+{
+ const u4 *framePtr;
+ const StackSaveArea *saveArea;
+ Method *method;
+ const char *shorty;
+ Object *obj;
+ int i;
+
+ saveArea = NULL;
+ framePtr = (const u4 *)thread->curFrame;
+ for (; framePtr != NULL; framePtr = saveArea->prevFrame) {
+ saveArea = SAVEAREA_FROM_FP(framePtr);
+ method = (Method *)saveArea->method;
+ if (method != NULL && dvmIsNativeMethod(method)) {
+ /*
+ * This is native method, pin its arguments.
+ *
+ * For purposes of graying references, we don't need to do
+ * anything here, because all of the native "ins" were copied
+ * from registers in the caller's stack frame and won't be
+ * changed (an interpreted method can freely use registers
+ * with parameters like any other register, but natives don't
+ * work that way).
+ *
+ * However, we need to ensure that references visible to
+ * native methods don't move around. We can do a precise scan
+ * of the arguments by examining the method signature.
+ */
+ LOG_PIN("+++ native scan %s.%s\n",
+ method->clazz->descriptor, method->name);
+ assert(method->registersSize == method->insSize);
+ if (!dvmIsStaticMethod(method)) {
+ /* grab the "this" pointer */
+ obj = (Object *)*framePtr++;
+ if (obj == NULL) {
+ /*
+ * This can happen for the "fake" entry frame inserted
+ * for threads created outside the VM. There's no actual
+ * call so there's no object. If we changed the fake
+ * entry method to be declared "static" then this
+ * situation should never occur.
+ */
+ } else {
+ assert(dvmIsValidObject(obj));
+ pinObject(obj);
+ }
+ }
+ shorty = method->shorty+1; // skip return value
+ for (i = method->registersSize - 1; i >= 0; i--, framePtr++) {
+ switch (*shorty++) {
+ case 'L':
+ obj = (Object *)*framePtr;
+ if (obj != NULL) {
+ assert(dvmIsValidObject(obj));
+ pinObject(obj);
+ }
+ break;
+ case 'D':
+ case 'J':
+ framePtr++;
+ break;
+ default:
+ /* 32-bit non-reference value */
+ obj = (Object *)*framePtr; // debug, remove
+ if (dvmIsValidObject(obj)) { // debug, remove
+ /* if we see a lot of these, our scan might be off */
+ LOG_PIN("+++ did NOT pin obj %p\n", obj);
+ }
+ break;
+ }
+ }
+ } else if (method != NULL && !dvmIsNativeMethod(method)) {
+ const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
+ const u1* regVector = NULL;
+
+ LOGI("conservative : %s.%s\n", method->clazz->descriptor, method->name);
+
+ if (pMap != NULL) {
+ int addr = saveArea->xtra.currentPc - method->insns;
+ regVector = dvmRegisterMapGetLine(pMap, addr);
+ }
+ if (regVector == NULL) {
+ /*
+ * No register info for this frame, conservatively pin.
+ */
+ for (i = 0; i < method->registersSize; ++i) {
+ u4 regValue = framePtr[i];
+ if (regValue != 0 && (regValue & 0x3) == 0 && dvmIsValidObject((Object *)regValue)) {
+ pinObject((Object *)regValue);
+ }
+ }
+ }
+ }
+ /*
+ * Don't fall into an infinite loop if things get corrupted.
+ */
+ assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
+ saveArea->prevFrame == NULL);
+ }
+}
+
+static void pinThread(const Thread *thread)
+{
+ assert(thread != NULL);
+ assert(thread->status != THREAD_RUNNING ||
+ thread->isSuspended ||
+ thread == dvmThreadSelf());
+ LOG_PIN("pinThread(thread=%p)", thread);
+
+ LOG_PIN("Pin native method arguments");
+ pinThreadStack(thread);
+
+ LOG_PIN("Pin internalLocalRefTable");
+ pinReferenceTable(&thread->internalLocalRefTable);
+
+ LOG_PIN("Pin jniLocalRefTable");
+ pinReferenceTable(&thread->jniLocalRefTable);
+
+ /* Can the check be pushed into the promote routine? */
+ if (thread->jniMonitorRefTable.table) {
+ LOG_PIN("Pin jniMonitorRefTable");
+ pinReferenceTable(&thread->jniMonitorRefTable);
+ }
+}
+
+static void pinThreadList(void)
+{
+ Thread *thread;
+
+ dvmLockThreadList(dvmThreadSelf());
+ thread = gDvm.threadList;
+ while (thread) {
+ pinThread(thread);
+ thread = thread->next;
+ }
+ dvmUnlockThreadList();
+}
+
+/*
+ * Heap block scavenging.
+ */
+
+/*
+ * Scavenge objects in the current block. Scavenging terminates when
+ * the pointer reaches the highest address in the block or when a run
+ * of zero words that continues to the highest address is reached.
+ */
+static void scavengeBlock(HeapSource *heapSource, size_t block)
+{
+ u1 *cursor;
+ u1 *end;
+ size_t size;
+
+ LOG_SCAV("scavengeBlock(heapSource=%p,block=%zu)", heapSource, block);
+
+ assert(heapSource != NULL);
+ assert(block < heapSource->totalBlocks);
+ assert(heapSource->blockSpace[block] == BLOCK_TO_SPACE);
+
+ cursor = blockToAddress(heapSource, block);
+ end = cursor + BLOCK_SIZE;
+ LOG_SCAV("scavengeBlock start=%p, end=%p", cursor, end);
+
+ /* Parse and scavenge the current block. */
+ size = 0;
+ while (cursor < end) {
+ u4 word = *(u4 *)cursor;
+ if (word != 0) {
+ scavengeObject((Object *)cursor);
+ size = objectSize((Object *)cursor);
+ size = alignUp(size, ALLOC_ALIGNMENT);
+ cursor += size;
+ } else {
+ /* Check for padding. */
+ while (*(u4 *)cursor == 0) {
+ cursor += 4;
+ if (cursor == end) break;
+ }
+ /* Punt if something went wrong. */
+ assert(cursor == end);
+ }
+ }
+}
+
+static size_t objectSize(const Object *obj)
+{
+ size_t size;
+
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ if (obj->clazz == gDvm.classJavaLangClass) {
+ size = dvmClassObjectSize((ClassObject *)obj);
+ } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+ size = dvmArrayObjectSize((ArrayObject *)obj);
+ } else {
+ assert(obj->clazz->objectSize != 0);
+ size = obj->clazz->objectSize;
+ }
+ if (LW_HASH_STATE(obj->lock) == LW_HASH_STATE_HASHED_AND_MOVED) {
+ size += sizeof(u4);
+ }
+ return size;
+}
+
+static void verifyBlock(HeapSource *heapSource, size_t block)
+{
+ u1 *cursor;
+ u1 *end;
+ size_t size;
+
+ // LOG_VER("verifyBlock(heapSource=%p,block=%zu)", heapSource, block);
+
+ assert(heapSource != NULL);
+ assert(block < heapSource->totalBlocks);
+ assert(heapSource->blockSpace[block] == BLOCK_TO_SPACE);
+
+ cursor = blockToAddress(heapSource, block);
+ end = cursor + BLOCK_SIZE;
+ // LOG_VER("verifyBlock start=%p, end=%p", cursor, end);
+
+ /* Parse and scavenge the current block. */
+ size = 0;
+ while (cursor < end) {
+ u4 word = *(u4 *)cursor;
+ if (word != 0) {
+ dvmVerifyObject((Object *)cursor);
+ size = objectSize((Object *)cursor);
+ size = alignUp(size, ALLOC_ALIGNMENT);
+ cursor += size;
+ } else {
+ /* Check for padding. */
+ while (*(unsigned long *)cursor == 0) {
+ cursor += 4;
+ if (cursor == end) break;
+ }
+ /* Punt if something went wrong. */
+ assert(cursor == end);
+ }
+ }
+}
+
+static void describeBlockQueue(const HeapSource *heapSource)
+{
+ size_t block, count;
+ char space;
+
+ block = heapSource->queueHead;
+ count = 0;
+ LOG_SCAV(">>> describeBlockQueue(heapSource=%p)", heapSource);
+ /* Count the number of blocks enqueued. */
+ while (block != QUEUE_TAIL) {
+ block = heapSource->blockQueue[block];
+ ++count;
+ }
+ LOG_SCAV("blockQueue %zu elements, enqueued %zu",
+ count, heapSource->queueSize);
+ block = heapSource->queueHead;
+ while (block != QUEUE_TAIL) {
+ space = heapSource->blockSpace[block];
+ LOG_SCAV("block=%zu@%p,space=%zu", block, blockToAddress(heapSource,block), space);
+ block = heapSource->blockQueue[block];
+ }
+
+ LOG_SCAV("<<< describeBlockQueue(heapSource=%p)", heapSource);
+}
+
+/*
+ * Blackens promoted objects.
+ */
+static void scavengeBlockQueue(void)
+{
+ HeapSource *heapSource;
+ size_t block;
+
+ LOG_SCAV(">>> scavengeBlockQueue()");
+ heapSource = gDvm.gcHeap->heapSource;
+ describeBlockQueue(heapSource);
+ while (heapSource->queueHead != QUEUE_TAIL) {
+ block = heapSource->queueHead;
+ LOG_SCAV("Dequeueing block %zu\n", block);
+ scavengeBlock(heapSource, block);
+ heapSource->queueHead = heapSource->blockQueue[block];
+ LOG_SCAV("New queue head is %zu\n", heapSource->queueHead);
+ }
+ LOG_SCAV("<<< scavengeBlockQueue()");
+}
+
+/*
+ * Scan the block list and verify all blocks that are marked as being
+ * in new space. This should be parametrized so we can invoke this
+ * routine outside of the context of a collection.
+ */
+static void verifyNewSpace(void)
+{
+ HeapSource *heapSource;
+ size_t i;
+ size_t c0, c1, c2, c7;
+
+ c0 = c1 = c2 = c7 = 0;
+ heapSource = gDvm.gcHeap->heapSource;
+ for (i = 0; i < heapSource->totalBlocks; ++i) {
+ switch (heapSource->blockSpace[i]) {
+ case BLOCK_FREE: ++c0; break;
+ case BLOCK_TO_SPACE: ++c1; break;
+ case BLOCK_FROM_SPACE: ++c2; break;
+ case BLOCK_CONTINUED: ++c7; break;
+ default: assert(!"reached");
+ }
+ }
+ LOG_VER("Block Demographics: "
+ "Free=%zu,ToSpace=%zu,FromSpace=%zu,Continued=%zu",
+ c0, c1, c2, c7);
+ for (i = 0; i < heapSource->totalBlocks; ++i) {
+ if (heapSource->blockSpace[i] != BLOCK_TO_SPACE) {
+ continue;
+ }
+ verifyBlock(heapSource, i);
+ }
+}
+
+static void scavengeGlobals(void)
+{
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangClass);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangClassArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangError);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangObject);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangObjectArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangRuntimeException);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangString);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangThread);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangVMThread);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangThreadGroup);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangThrowable);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangStackTraceElement);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangStackTraceElementArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangAnnotationAnnotationArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangAnnotationAnnotationArrayArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectAccessibleObject);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectConstructor);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectConstructorArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectField);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectFieldArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectMethod);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectMethodArray);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangReflectProxy);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangExceptionInInitializerError);
+ scavengeReference((Object **)(void *)&gDvm.classJavaLangRefReference);
+ scavengeReference((Object **)(void *)&gDvm.classJavaNioReadWriteDirectByteBuffer);
+ scavengeReference((Object **)(void *)&gDvm.classJavaSecurityAccessController);
+ scavengeReference((Object **)(void *)&gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory);
+ scavengeReference((Object **)(void *)&gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember);
+ scavengeReference((Object **)(void *)&gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray);
+ scavengeReference((Object **)(void *)&gDvm.classOrgApacheHarmonyNioInternalDirectBuffer);
+ scavengeReference((Object **)(void *)&gDvm.classArrayBoolean);
+ scavengeReference((Object **)(void *)&gDvm.classArrayChar);
+ scavengeReference((Object **)(void *)&gDvm.classArrayFloat);
+ scavengeReference((Object **)(void *)&gDvm.classArrayDouble);
+ scavengeReference((Object **)(void *)&gDvm.classArrayByte);
+ scavengeReference((Object **)(void *)&gDvm.classArrayShort);
+ scavengeReference((Object **)(void *)&gDvm.classArrayInt);
+ scavengeReference((Object **)(void *)&gDvm.classArrayLong);
+}
+
+void describeHeap(void)
+{
+ HeapSource *heapSource;
+
+ heapSource = gDvm.gcHeap->heapSource;
+ describeBlocks(heapSource);
+}
+
+/*
+ * The collection interface. Collection has a few distinct phases.
+ * The first is flipping AKA condemning AKA whitening the heap. The
+ * second is to promote all objects which are pointed to by pinned or
+ * ambiguous references. The third phase is tracing from the stacks,
+ * registers and various globals. Lastly, a verification of the heap
+ * is performed. The last phase should be optional.
+ */
+void dvmScavengeRoots(void) /* Needs a new name badly */
+{
+ GcHeap *gcHeap;
+
+ {
+ size_t alloc, unused, total;
+
+ room(&alloc, &unused, &total);
+ LOG_SCAV("BEFORE GC: %zu alloc, %zu free, %zu total.",
+ alloc, unused, total);
+ }
+
+ gcHeap = gDvm.gcHeap;
+ dvmHeapSourceFlip();
+
+ /*
+ * Promote blocks with stationary objects.
+ */
+ pinThreadList();
+ pinReferenceTable(&gDvm.jniGlobalRefTable);
+ pinReferenceTable(&gDvm.jniPinRefTable);
+ pinHashTableEntries(gDvm.loadedClasses);
+ pinHashTableEntries(gDvm.dbgRegistry);
+ pinPrimitiveClasses();
+ pinInternedStrings();
+
+ // describeBlocks(gcHeap->heapSource);
+
+ /*
+ * Create first, open new-space page right here.
+ */
+
+ /* Reset allocation to an unallocated block. */
+ gDvm.gcHeap->heapSource->allocPtr = allocateBlocks(gDvm.gcHeap->heapSource, 1);
+ gDvm.gcHeap->heapSource->allocLimit = gDvm.gcHeap->heapSource->allocPtr + BLOCK_SIZE;
+ /*
+ * Hack: promote the empty block allocated above. If the
+ * promotions that occurred above did not actually gray any
+ * objects, the block queue may be empty. We must force a
+ * promotion to be safe.
+ */
+ promoteBlockByAddr(gDvm.gcHeap->heapSource, gDvm.gcHeap->heapSource->allocPtr);
+
+ /*
+ * Scavenge blocks and relocate movable objects.
+ */
+
+ LOG_SCAV("Scavenging gDvm.threadList");
+ scavengeThreadList();
+
+ LOG_SCAV("Scavenging gDvm.gcHeap->referenceOperations");
+ scavengeLargeHeapRefTable(gcHeap->referenceOperations);
+
+ LOG_SCAV("Scavenging gDvm.gcHeap->pendingFinalizationRefs");
+ scavengeLargeHeapRefTable(gcHeap->pendingFinalizationRefs);
+
+ LOG_SCAV("Scavenging random global stuff");
+ scavengeReference(&gDvm.outOfMemoryObj);
+ scavengeReference(&gDvm.internalErrorObj);
+ scavengeReference(&gDvm.noClassDefFoundErrorObj);
+
+ // LOG_SCAV("Scavenging gDvm.internedString");
+ scavengeInternedStrings();
+
+ LOG_SCAV("Root scavenge has completed.");
+
+ scavengeBlockQueue();
+
+ LOG_SCAV("Re-snap global class pointers.");
+ scavengeGlobals();
+
+ LOG_SCAV("New space scavenge has completed.");
+
+ /*
+ * Process reference objects in strength order.
+ */
+
+ LOG_REF("Processing soft references...");
+ preserveSoftReferences(&gDvm.gcHeap->softReferences);
+ clearWhiteReferences(&gDvm.gcHeap->softReferences);
+
+ LOG_REF("Processing weak references...");
+ clearWhiteReferences(&gDvm.gcHeap->weakReferences);
+
+ LOG_REF("Finding finalizations...");
+ processFinalizableReferences();
+
+ LOG_REF("Processing f-reachable soft references...");
+ clearWhiteReferences(&gDvm.gcHeap->softReferences);
+
+ LOG_REF("Processing f-reachable weak references...");
+ clearWhiteReferences(&gDvm.gcHeap->weakReferences);
+
+ LOG_REF("Processing phantom references...");
+ clearWhiteReferences(&gDvm.gcHeap->phantomReferences);
+
+ /*
+ * Verify the stack and heap.
+ */
+ dvmVerifyRoots();
+ verifyNewSpace();
+
+ //describeBlocks(gcHeap->heapSource);
+
+ clearFromSpace(gcHeap->heapSource);
+
+ {
+ size_t alloc, rem, total;
+
+ room(&alloc, &rem, &total);
+ LOG_SCAV("AFTER GC: %zu alloc, %zu free, %zu total.", alloc, rem, total);
+ }
+}
+
+/*
+ * Interface compatibility routines.
+ */
+
+void dvmClearWhiteRefs(Object **list)
+{
+ /* do nothing */
+ assert(*list == NULL);
+}
+
+void dvmHandleSoftRefs(Object **list)
+{
+ /* do nothing */
+ assert(*list == NULL);
+}
+
+bool dvmHeapBeginMarkStep(GcMode mode)
+{
+ /* do nothing */
+ return true;
+}
+
+void dvmHeapFinishMarkStep(void)
+{
+ /* do nothing */
+}
+
+void dvmHeapMarkRootSet(void)
+{
+ /* do nothing */
+}
+
+void dvmHeapScanMarkedObjects(void)
+{
+ dvmScavengeRoots();
+}
+
+void dvmHeapScheduleFinalizations(void)
+{
+ /* do nothing */
+}
+
+void dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
+{
+ *numFreed = 0;
+ *sizeFreed = 0;
+ /* do nothing */
+}
+
+void dvmMarkObjectNonNull(const Object *obj)
+{
+ assert(!"implemented");
+}
+
+void dvmMarkDirtyObjects(void)
+{
+ assert(!"implemented");
+}
+
+void dvmHeapSourceThreadShutdown(void)
+{
+ /* do nothing */
+}
diff --git a/vm/alloc/DdmHeap.c b/vm/alloc/DdmHeap.c
index f21a875..4cb5cae 100644
--- a/vm/alloc/DdmHeap.c
+++ b/vm/alloc/DdmHeap.c
@@ -36,12 +36,12 @@
/*
* Chunk HPIF (client --> server)
- *
+ *
* Heap Info. General information about the heap,
* suitable for a summary display.
- *
+ *
* [u4]: number of heaps
- *
+ *
* For each heap:
* [u4]: heap ID
* [u8]: timestamp in ms since Unix epoch
@@ -273,9 +273,8 @@
*/
state = HPSG_STATE(SOLIDITY_FREE, 0);
} else {
- const DvmHeapChunk *hc = (const DvmHeapChunk *)userptr;
- const Object *obj = chunk2ptr(hc);
- /* If we're looking at the native heap, we'll just return
+ const Object *obj = userptr;
+ /* If we're looking at the native heap, we'll just return
* (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
*/
bool native = ctx->type == CHUNK_TYPE("NHSG");
@@ -291,9 +290,7 @@
* but hasn't been initialized yet.
*/
state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
- } else if (clazz == gDvm.unlinkedJavaLangClass ||
- clazz == gDvm.classJavaLangClass)
- {
+ } else if (clazz == gDvm.classJavaLangClass) {
state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
} else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
@@ -366,7 +363,7 @@
walkHeap(bool merge, bool native)
{
HeapChunkContext ctx;
-
+
memset(&ctx, 0, sizeof(ctx));
ctx.bufLen = HPSx_CHUNK_SIZE;
ctx.buf = (u1 *)malloc(ctx.bufLen);
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index dce5a82..1d8cfde 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -17,12 +17,15 @@
* Garbage-collecting memory allocator.
*/
#include "Dalvik.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/Verify.h"
#include "alloc/HeapTable.h"
#include "alloc/Heap.h"
#include "alloc/HeapInternal.h"
#include "alloc/DdmHeap.h"
#include "alloc/HeapSource.h"
#include "alloc/MarkSweep.h"
+#include "alloc/Visit.h"
#include "utils/threads.h" // need Android thread priorities
#define kInvalidPriority 10000
@@ -34,11 +37,9 @@
#include <limits.h>
#include <errno.h>
-#define kNonCollectableRefDefault 16
-#define kFinalizableRefDefault 128
-
static const char* GcReasonStr[] = {
[GC_FOR_MALLOC] = "GC_FOR_MALLOC",
+ [GC_CONCURRENT] = "GC_CONCURRENT",
[GC_EXPLICIT] = "GC_EXPLICIT",
[GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC",
[GC_HPROF_DUMP_HEAP] = "GC_HPROF_DUMP_HEAP"
@@ -65,8 +66,6 @@
gcHeap->heapWorkerCurrentObject = NULL;
gcHeap->heapWorkerCurrentMethod = NULL;
gcHeap->heapWorkerInterpStartTime = 0LL;
- gcHeap->softReferenceCollectionState = SR_COLLECT_NONE;
- gcHeap->softReferenceHeapSizeThreshold = gDvm.heapSizeStart;
gcHeap->ddmHpifWhen = 0;
gcHeap->ddmHpsgWhen = 0;
gcHeap->ddmHpsgWhat = 0;
@@ -76,20 +75,8 @@
gcHeap->hprofDumpOnGc = false;
gcHeap->hprofContext = NULL;
#endif
-
- /* This needs to be set before we call dvmHeapInitHeapRefTable().
- */
gDvm.gcHeap = gcHeap;
- /* Set up the table we'll use for ALLOC_NO_GC.
- */
- if (!dvmHeapInitHeapRefTable(&gcHeap->nonCollectableRefs,
- kNonCollectableRefDefault))
- {
- LOGE_HEAP("Can't allocate GC_NO_ALLOC table\n");
- goto fail;
- }
-
/* Set up the lists and lock we'll use for finalizable
* and reference objects.
*/
@@ -98,26 +85,21 @@
gcHeap->pendingFinalizationRefs = NULL;
gcHeap->referenceOperations = NULL;
+ if (!dvmCardTableStartup()) {
+ LOGE_HEAP("card table startup failed.");
+ return false;
+ }
+
/* Initialize the HeapWorker locks and other state
* that the GC uses.
*/
dvmInitializeHeapWorkerState();
return true;
-
-fail:
- gDvm.gcHeap = NULL;
- dvmHeapSourceShutdown(gcHeap);
- return false;
}
-bool dvmHeapStartupAfterZygote()
+bool dvmHeapStartupAfterZygote(void)
{
- /* Update our idea of the last GC start time so that we
- * don't use the last time that Zygote happened to GC.
- */
- gDvm.gcHeap->gcStartTime = dvmGetRelativeTimeUsec();
-
return dvmHeapSourceStartupAfterZygote();
}
@@ -125,37 +107,37 @@
{
//TODO: make sure we're locked
if (gDvm.gcHeap != NULL) {
- GcHeap *gcHeap;
-
- gcHeap = gDvm.gcHeap;
- gDvm.gcHeap = NULL;
-
- /* Tables are allocated on the native heap;
- * they need to be cleaned up explicitly.
- * The process may stick around, so we don't
- * want to leak any native memory.
+ dvmCardTableShutdown();
+ /* Tables are allocated on the native heap; they need to be
+ * cleaned up explicitly. The process may stick around, so we
+ * don't want to leak any native memory.
*/
- dvmHeapFreeHeapRefTable(&gcHeap->nonCollectableRefs);
+ dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs);
+ gDvm.gcHeap->finalizableRefs = NULL;
- dvmHeapFreeLargeTable(gcHeap->finalizableRefs);
- gcHeap->finalizableRefs = NULL;
+ dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs);
+ gDvm.gcHeap->pendingFinalizationRefs = NULL;
- dvmHeapFreeLargeTable(gcHeap->pendingFinalizationRefs);
- gcHeap->pendingFinalizationRefs = NULL;
+ dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
+ gDvm.gcHeap->referenceOperations = NULL;
- dvmHeapFreeLargeTable(gcHeap->referenceOperations);
- gcHeap->referenceOperations = NULL;
-
- /* Destroy the heap. Any outstanding pointers
- * will point to unmapped memory (unless/until
- * someone else maps it). This frees gcHeap
- * as a side-effect.
+ /* Destroy the heap. Any outstanding pointers will point to
+ * unmapped memory (unless/until someone else maps it). This
+ * frees gDvm.gcHeap as a side-effect.
*/
- dvmHeapSourceShutdown(gcHeap);
+ dvmHeapSourceShutdown(&gDvm.gcHeap);
}
}
/*
+ * Shutdown any threads internal to the heap.
+ */
+void dvmHeapThreadShutdown(void)
+{
+ dvmHeapSourceThreadShutdown();
+}
+
+/*
* We've been asked to allocate something we can't, e.g. an array so
* large that (length * elementWidth) is larger than 2^31.
*
@@ -180,25 +162,14 @@
*/
bool dvmLockHeap()
{
- if (pthread_mutex_trylock(&gDvm.gcHeapLock) != 0) {
+ if (dvmTryLockMutex(&gDvm.gcHeapLock) != 0) {
Thread *self;
ThreadStatus oldStatus;
- int cc;
self = dvmThreadSelf();
- if (self != NULL) {
- oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
- } else {
- LOGI("ODD: waiting on heap lock, no self\n");
- oldStatus = -1; // shut up gcc
- }
-
- cc = pthread_mutex_lock(&gDvm.gcHeapLock);
- assert(cc == 0);
-
- if (self != NULL) {
- dvmChangeStatus(self, oldStatus);
- }
+ oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ dvmLockMutex(&gDvm.gcHeapLock);
+ dvmChangeStatus(self, oldStatus);
}
return true;
@@ -219,35 +190,15 @@
Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op)
{
Object *obj;
- LargeHeapRefTable *table;
GcHeap *gcHeap = gDvm.gcHeap;
assert(op != NULL);
- obj = NULL;
-
dvmLockMutex(&gDvm.heapWorkerListLock);
- /* We must handle reference operations before finalizations.
- * If:
- * a) Someone subclasses WeakReference and overrides clear()
- * b) A reference of this type is the last reference to
- * a finalizable object
- * then we need to guarantee that the overridden clear() is called
- * on the reference before finalize() is called on the referent.
- * Both of these operations will always be scheduled at the same
- * time, so handling reference operations first will guarantee
- * the required order.
- */
obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
if (obj != NULL) {
- uintptr_t workBits;
-
- workBits = (uintptr_t)obj & WORKER_ENQUEUE;
- assert(workBits != 0);
- obj = (Object *)((uintptr_t)obj & ~WORKER_ENQUEUE);
-
- *op = workBits;
+ *op = WORKER_ENQUEUE;
} else {
obj = dvmHeapGetNextObjectFromLargeTable(
&gcHeap->pendingFinalizationRefs);
@@ -259,9 +210,6 @@
if (obj != NULL) {
/* Don't let the GC collect the object until the
* worker thread is done with it.
- *
- * This call is safe; it uses thread-local storage
- * and doesn't acquire any locks.
*/
dvmAddTrackedAlloc(obj, NULL);
}
@@ -271,50 +219,6 @@
return obj;
}
-/* Used for a heap size change hysteresis to avoid collecting
- * SoftReferences when the heap only grows by a small amount.
- */
-#define SOFT_REFERENCE_GROWTH_SLACK (128 * 1024)
-
-/* Whenever the effective heap size may have changed,
- * this function must be called.
- */
-void dvmHeapSizeChanged()
-{
- GcHeap *gcHeap = gDvm.gcHeap;
- size_t currentHeapSize;
-
- currentHeapSize = dvmHeapSourceGetIdealFootprint();
-
- /* See if the heap size has changed enough that we should care
- * about it.
- */
- if (currentHeapSize <= gcHeap->softReferenceHeapSizeThreshold -
- 4 * SOFT_REFERENCE_GROWTH_SLACK)
- {
- /* The heap has shrunk enough that we'll use this as a new
- * threshold. Since we're doing better on space, there's
- * no need to collect any SoftReferences.
- *
- * This is 4x the growth hysteresis because we don't want
- * to snap down so easily after a shrink. If we just cleared
- * up a bunch of SoftReferences, we don't want to disallow
- * any new ones from being created.
- * TODO: determine if the 4x is important, needed, or even good
- */
- gcHeap->softReferenceHeapSizeThreshold = currentHeapSize;
- gcHeap->softReferenceCollectionState = SR_COLLECT_NONE;
- } else if (currentHeapSize >= gcHeap->softReferenceHeapSizeThreshold +
- SOFT_REFERENCE_GROWTH_SLACK)
- {
- /* The heap has grown enough to warrant collecting SoftReferences.
- */
- gcHeap->softReferenceHeapSizeThreshold = currentHeapSize;
- gcHeap->softReferenceCollectionState = SR_COLLECT_SOME;
- }
-}
-
-
/* Do a full garbage collection, which may grow the
* heap as a side-effect if the live set is large.
*/
@@ -338,9 +242,9 @@
/* Try as hard as possible to allocate some memory.
*/
-static DvmHeapChunk *tryMalloc(size_t size)
+static void *tryMalloc(size_t size)
{
- DvmHeapChunk *hc;
+ void *ptr;
/* Don't try too hard if there's no way the allocation is
* going to succeed. We have to collect SoftReferences before
@@ -349,7 +253,7 @@
if (size >= gDvm.heapSizeMax) {
LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
"someone's allocating a huge buffer\n", size, size);
- hc = NULL;
+ ptr = NULL;
goto collect_soft_refs;
}
@@ -363,27 +267,42 @@
// DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
// (or, at least, there are only 0-5 objects swept each time)
- hc = dvmHeapSourceAlloc(size + sizeof(DvmHeapChunk));
- if (hc != NULL) {
- return hc;
+ ptr = dvmHeapSourceAlloc(size);
+ if (ptr != NULL) {
+ return ptr;
}
- /* The allocation failed. Free up some space by doing
- * a full garbage collection. This may grow the heap
- * if the live set is sufficiently large.
+ /*
+ * The allocation failed. If the GC is running, block until it
+ * completes and retry.
+ */
+ if (gDvm.gcHeap->gcRunning) {
+ /*
+ * The GC is concurrently tracing the heap. Release the heap
+ * lock, wait for the GC to complete, and retrying allocating.
+ */
+ dvmWaitForConcurrentGcToComplete();
+ ptr = dvmHeapSourceAlloc(size);
+ if (ptr != NULL) {
+ return ptr;
+ }
+ }
+ /*
+ * Another failure. Our thread was starved or there may be too
+ * many live objects. Try a foreground GC. This will have no
+ * effect if the concurrent GC is already running.
*/
gcForMalloc(false);
- hc = dvmHeapSourceAlloc(size + sizeof(DvmHeapChunk));
- if (hc != NULL) {
- return hc;
+ ptr = dvmHeapSourceAlloc(size);
+ if (ptr != NULL) {
+ return ptr;
}
/* Even that didn't work; this is an exceptional state.
* Try harder, growing the heap if necessary.
*/
- hc = dvmHeapSourceAllocAndGrow(size + sizeof(DvmHeapChunk));
- dvmHeapSizeChanged();
- if (hc != NULL) {
+ ptr = dvmHeapSourceAllocAndGrow(size);
+ if (ptr != NULL) {
size_t newHeapSize;
newHeapSize = dvmHeapSourceGetIdealFootprint();
@@ -393,7 +312,7 @@
LOGI_HEAP("Grow heap (frag case) to "
"%zu.%03zuMB for %zu-byte allocation\n",
FRACTIONAL_MB(newHeapSize), size);
- return hc;
+ return ptr;
}
/* Most allocations should have succeeded by now, so the heap
@@ -407,10 +326,9 @@
LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
size);
gcForMalloc(true);
- hc = dvmHeapSourceAllocAndGrow(size + sizeof(DvmHeapChunk));
- dvmHeapSizeChanged();
- if (hc != NULL) {
- return hc;
+ ptr = dvmHeapSourceAllocAndGrow(size);
+ if (ptr != NULL) {
+ return ptr;
}
//TODO: maybe wait for finalizers and try one last time
@@ -486,10 +404,6 @@
* In rare circumstances (JNI AttachCurrentThread) we can be called
* from a non-VM thread.
*
- * We implement ALLOC_NO_GC by maintaining an internal list of objects
- * that should not be collected. This requires no actual flag storage in
- * the object itself, which is good, but makes flag queries expensive.
- *
* Use ALLOC_DONT_TRACK when we either don't want to track an allocation
* (because it's being done for the interpreter "new" operation and will
* be part of the root set immediately) or we can't (because this allocation
@@ -502,17 +416,7 @@
void* dvmMalloc(size_t size, int flags)
{
GcHeap *gcHeap = gDvm.gcHeap;
- DvmHeapChunk *hc;
void *ptr;
- bool triedGc, triedGrowing;
-
-#if 0
- /* handy for spotting large allocations */
- if (size >= 100000) {
- LOGI("dvmMalloc(%d):\n", size);
- dvmDumpThread(dvmThreadSelf(), false);
- }
-#endif
#if defined(WITH_ALLOC_LIMITS)
/*
@@ -557,22 +461,16 @@
/* Try as hard as possible to allocate some memory.
*/
- hc = tryMalloc(size);
- if (hc != NULL) {
-alloc_succeeded:
+ ptr = tryMalloc(size);
+ if (ptr != NULL) {
/* We've got the memory.
*/
if ((flags & ALLOC_FINALIZABLE) != 0) {
/* This object is an instance of a class that
* overrides finalize(). Add it to the finalizable list.
- *
- * Note that until DVM_OBJECT_INIT() is called on this
- * object, its clazz will be NULL. Since the object is
- * in this table, it will be scanned as part of the root
- * set. scanObject() explicitly deals with the NULL clazz.
*/
if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
- (Object *)hc->data))
+ (Object *)ptr))
{
LOGE_HEAP("dvmMalloc(): no room for any more "
"finalizable objects\n");
@@ -580,27 +478,6 @@
}
}
- ptr = hc->data;
-
- /* The caller may not want us to collect this object.
- * If not, throw it in the nonCollectableRefs table, which
- * will be added to the root set when we GC.
- *
- * Note that until DVM_OBJECT_INIT() is called on this
- * object, its clazz will be NULL. Since the object is
- * in this table, it will be scanned as part of the root
- * set. scanObject() explicitly deals with the NULL clazz.
- */
- if ((flags & ALLOC_NO_GC) != 0) {
- if (!dvmHeapAddToHeapRefTable(&gcHeap->nonCollectableRefs, ptr)) {
- LOGE_HEAP("dvmMalloc(): no room for any more "
- "ALLOC_NO_GC objects: %zd\n",
- dvmHeapNumHeapRefTableEntries(
- &gcHeap->nonCollectableRefs));
- dvmAbort();
- }
- }
-
#ifdef WITH_PROFILER
if (gDvm.allocProf.enabled) {
Thread* self = dvmThreadSelf();
@@ -615,7 +492,6 @@
} else {
/* The allocation failed.
*/
- ptr = NULL;
#ifdef WITH_PROFILER
if (gDvm.allocProf.enabled) {
@@ -634,13 +510,10 @@
if (ptr != NULL) {
/*
- * If this block is immediately GCable, and they haven't asked us not
- * to track it, add it to the internal tracking list.
- *
- * If there's no "self" yet, we can't track it. Calls made before
- * the Thread exists should use ALLOC_NO_GC.
+ * If caller hasn't asked us not to track it, add it to the
+ * internal tracking list.
*/
- if ((flags & (ALLOC_DONT_TRACK | ALLOC_NO_GC)) == 0) {
+ if ((flags & ALLOC_DONT_TRACK) == 0) {
dvmAddTrackedAlloc(ptr, NULL);
}
} else {
@@ -658,12 +531,9 @@
*/
bool dvmIsValidObject(const Object* obj)
{
- const DvmHeapChunk *hc;
-
/* Don't bother if it's NULL or not 8-byte aligned.
*/
- hc = ptr2chunk(obj);
- if (obj != NULL && ((uintptr_t)hc & (8-1)) == 0) {
+ if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
/* Even if the heap isn't locked, this shouldn't return
* any false negatives. The only mutation that could
* be happening is allocation, which means that another
@@ -677,40 +547,37 @@
* Freeing will only happen during the sweep phase, which
* only happens while the heap is locked.
*/
- return dvmHeapSourceContains(hc);
+ return dvmHeapSourceContains(obj);
}
return false;
}
/*
- * Clear flags that were passed into dvmMalloc() et al.
- * e.g., ALLOC_NO_GC, ALLOC_DONT_TRACK.
+ * Returns true iff <obj> points to a word-aligned address within Heap
+ * address space.
*/
-void dvmClearAllocFlags(Object *obj, int mask)
+bool dvmIsValidObjectAddress(const void* ptr)
{
- if ((mask & ALLOC_NO_GC) != 0) {
- dvmLockHeap();
- if (dvmIsValidObject(obj)) {
- if (!dvmHeapRemoveFromHeapRefTable(&gDvm.gcHeap->nonCollectableRefs,
- obj))
- {
- LOGE_HEAP("dvmMalloc(): failed to remove ALLOC_NO_GC bit from "
- "object 0x%08x\n", (uintptr_t)obj);
- dvmAbort();
- }
-//TODO: shrink if the table is very empty
- }
- dvmUnlockHeap();
+ /* Don't bother if it's not 4-byte aligned.
+ */
+ if (((uintptr_t)ptr & (4-1)) == 0) {
+ return dvmHeapSourceContainsAddress(ptr);
}
-
- if ((mask & ALLOC_DONT_TRACK) != 0) {
- dvmReleaseTrackedAlloc(obj, NULL);
- }
+ return false;
}
size_t dvmObjectSizeInHeap(const Object *obj)
{
- return dvmHeapSourceChunkSize(ptr2chunk(obj)) - sizeof(DvmHeapChunk);
+ return dvmHeapSourceChunkSize(obj);
+}
+
+/*
+ * Scan every live object in the heap, holding the locks.
+ */
+static void verifyHeap(void)
+{
+ dvmVerifyRoots();
+ dvmVerifyBitmap(dvmHeapSourceGetLiveBits());
}
/*
@@ -727,31 +594,16 @@
* way to enforce this is to refuse to GC on an allocation made by the
* JDWP thread -- we have to expand the heap or fail.
*/
-void dvmCollectGarbageInternal(bool collectSoftReferences, enum GcReason reason)
+void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason)
{
GcHeap *gcHeap = gDvm.gcHeap;
- Object *softReferences;
- Object *weakReferences;
- Object *phantomReferences;
-
- u8 now;
- s8 timeSinceLastGc;
- s8 gcElapsedTime;
+ u4 suspendStart, totalTime;
+ u4 rootStart, rootEnd, rootTime, rootSuspendTime;
+ u4 dirtyStart, dirtyEnd, dirtyTime, dirtySuspendTime;
int numFreed;
size_t sizeFreed;
-
-#if DVM_TRACK_HEAP_MARKING
- /* Since weak and soft references are always cleared,
- * they don't require any marking.
- * (Soft are lumped into strong when they aren't cleared.)
- */
- size_t strongMarkCount = 0;
- size_t strongMarkSize = 0;
- size_t finalizeMarkCount = 0;
- size_t finalizeMarkSize = 0;
- size_t phantomMarkCount = 0;
- size_t phantomMarkSize = 0;
-#endif
+ GcMode gcMode;
+ int oldThreadPriority = kInvalidPriority;
/* The heap lock must be held.
*/
@@ -760,45 +612,45 @@
LOGW_HEAP("Attempted recursive GC\n");
return;
}
+
+ gcMode = (reason == GC_FOR_MALLOC) ? GC_PARTIAL : GC_FULL;
gcHeap->gcRunning = true;
- now = dvmGetRelativeTimeUsec();
- if (gcHeap->gcStartTime != 0) {
- timeSinceLastGc = (now - gcHeap->gcStartTime) / 1000;
- } else {
- timeSinceLastGc = 0;
- }
- gcHeap->gcStartTime = now;
- LOGV_HEAP("%s starting -- suspending threads\n", GcReasonStr[reason]);
-
+ suspendStart = dvmGetRelativeTimeMsec();
dvmSuspendAllThreads(SUSPEND_FOR_GC);
+ rootStart = dvmGetRelativeTimeMsec();
- /* Get the priority (the "nice" value) of the current thread. The
- * getpriority() call can legitimately return -1, so we have to
- * explicitly test errno.
+ /*
+ * If we are not marking concurrently raise the priority of the
+ * thread performing the garbage collection.
*/
- errno = 0;
- int oldThreadPriority = kInvalidPriority;
- int priorityResult = getpriority(PRIO_PROCESS, 0);
- if (errno != 0) {
- LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
- } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
- /* Current value is numerically greater than "normal", which
- * in backward UNIX terms means lower priority.
+ if (reason != GC_CONCURRENT) {
+ /* Get the priority (the "nice" value) of the current thread. The
+ * getpriority() call can legitimately return -1, so we have to
+ * explicitly test errno.
*/
+ errno = 0;
+ int priorityResult = getpriority(PRIO_PROCESS, 0);
+ if (errno != 0) {
+ LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
+ } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
+ /* Current value is numerically greater than "normal", which
+ * in backward UNIX terms means lower priority.
+ */
- if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
- set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
- }
+ if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
+ set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
+ }
- if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
- LOGI_HEAP("Unable to elevate priority from %d to %d\n",
- priorityResult, ANDROID_PRIORITY_NORMAL);
- } else {
- /* priority elevated; save value so we can restore it later */
- LOGD_HEAP("Elevating priority from %d to %d\n",
- priorityResult, ANDROID_PRIORITY_NORMAL);
- oldThreadPriority = priorityResult;
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
+ LOGI_HEAP("Unable to elevate priority from %d to %d\n",
+ priorityResult, ANDROID_PRIORITY_NORMAL);
+ } else {
+ /* priority elevated; save value so we can restore it later */
+ LOGD_HEAP("Elevating priority from %d to %d\n",
+ priorityResult, ANDROID_PRIORITY_NORMAL);
+ oldThreadPriority = priorityResult;
+ }
}
}
@@ -822,6 +674,11 @@
*/
dvmLockMutex(&gDvm.heapWorkerListLock);
+ if (gDvm.preVerify) {
+ LOGV_HEAP("Verifying heap before GC");
+ verifyHeap();
+ }
+
#ifdef WITH_PROFILER
dvmMethodTraceGCBegin();
#endif
@@ -857,7 +714,7 @@
gcHeap->hprofFileName = nameBuf;
}
gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName,
- gcHeap->hprofDirectToDdms);
+ gcHeap->hprofFd, gcHeap->hprofDirectToDdms);
if (gcHeap->hprofContext != NULL) {
hprofStartHeapDump(gcHeap->hprofContext);
}
@@ -866,21 +723,9 @@
}
#endif
- if (timeSinceLastGc < 10000) {
- LOGD_HEAP("GC! (%dms since last GC)\n",
- (int)timeSinceLastGc);
- } else {
- LOGD_HEAP("GC! (%d sec since last GC)\n",
- (int)(timeSinceLastGc / 1000));
- }
-#if DVM_TRACK_HEAP_MARKING
- gcHeap->markCount = 0;
- gcHeap->markSize = 0;
-#endif
-
/* Set up the marking context.
*/
- if (!dvmHeapBeginMarkStep()) {
+ if (!dvmHeapBeginMarkStep(gcMode)) {
LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting\n");
dvmAbort();
}
@@ -897,16 +742,17 @@
gcHeap->weakReferences = NULL;
gcHeap->phantomReferences = NULL;
- /* Make sure that we don't hard-mark the referents of Reference
- * objects by default.
- */
- gcHeap->markAllReferents = false;
-
- /* Don't mark SoftReferences if our caller wants us to collect them.
- * This has to be set before calling dvmHeapScanMarkedObjects().
- */
- if (collectSoftReferences) {
- gcHeap->softReferenceCollectionState = SR_COLLECT_ALL;
+ if (reason == GC_CONCURRENT) {
+ /*
+ * Resume threads while tracing from the roots. We unlock the
+ * heap to allow mutator threads to allocate from free space.
+ */
+ rootEnd = dvmGetRelativeTimeMsec();
+ dvmClearCardTable();
+ dvmUnlockHeap();
+ dvmResumeAllThreads(SUSPEND_FOR_GC);
+ rootSuspendTime = rootStart - suspendStart;
+ rootTime = rootEnd - rootStart;
}
/* Recursively mark any objects that marked objects point to strongly.
@@ -915,74 +761,63 @@
*/
LOGD_HEAP("Recursing...");
dvmHeapScanMarkedObjects();
-#if DVM_TRACK_HEAP_MARKING
- strongMarkCount = gcHeap->markCount;
- strongMarkSize = gcHeap->markSize;
- gcHeap->markCount = 0;
- gcHeap->markSize = 0;
-#endif
- /* Latch these so that the other calls to dvmHeapScanMarkedObjects() don't
- * mess with them.
- */
- softReferences = gcHeap->softReferences;
- weakReferences = gcHeap->weakReferences;
- phantomReferences = gcHeap->phantomReferences;
+ if (reason == GC_CONCURRENT) {
+ /*
+ * Re-acquire the heap lock and perform the final thread
+ * suspension.
+ */
+ dvmLockHeap();
+ suspendStart = dvmGetRelativeTimeMsec();
+ dvmSuspendAllThreads(SUSPEND_FOR_GC);
+ dirtyStart = dvmGetRelativeTimeMsec();
+ /*
+ * As no barrier intercepts root updates, we conservatively
+ * assume all roots may be gray and re-mark them.
+ */
+ dvmHeapReMarkRootSet();
+ /*
+ * Recursively mark gray objects pointed to by the roots or by
+ * heap objects dirtied during the concurrent mark.
+ */
+ dvmHeapReScanMarkedObjects();
+ }
/* All strongly-reachable objects have now been marked.
*/
- if (gcHeap->softReferenceCollectionState != SR_COLLECT_NONE) {
- LOGD_HEAP("Handling soft references...");
- dvmHeapHandleReferences(softReferences, REF_SOFT);
- // markCount always zero
+ LOGD_HEAP("Handling soft references...");
+ if (!clearSoftRefs) {
+ dvmHandleSoftRefs(&gcHeap->softReferences);
+ }
+ dvmClearWhiteRefs(&gcHeap->softReferences);
- /* Now that we've tried collecting SoftReferences,
- * fall back to not collecting them. If the heap
- * grows, we will start collecting again.
- */
- gcHeap->softReferenceCollectionState = SR_COLLECT_NONE;
- } // else dvmHeapScanMarkedObjects() already marked the soft-reachable set
LOGD_HEAP("Handling weak references...");
- dvmHeapHandleReferences(weakReferences, REF_WEAK);
- // markCount always zero
+ dvmClearWhiteRefs(&gcHeap->weakReferences);
/* Once all weak-reachable objects have been taken
* care of, any remaining unmarked objects can be finalized.
*/
LOGD_HEAP("Finding finalizations...");
dvmHeapScheduleFinalizations();
-#if DVM_TRACK_HEAP_MARKING
- finalizeMarkCount = gcHeap->markCount;
- finalizeMarkSize = gcHeap->markSize;
- gcHeap->markCount = 0;
- gcHeap->markSize = 0;
-#endif
+
+ LOGD_HEAP("Handling f-reachable soft references...");
+ dvmClearWhiteRefs(&gcHeap->softReferences);
+
+ LOGD_HEAP("Handling f-reachable weak references...");
+ dvmClearWhiteRefs(&gcHeap->weakReferences);
/* Any remaining objects that are not pending finalization
* could be phantom-reachable. This will mark any phantom-reachable
* objects, as well as enqueue their references.
*/
LOGD_HEAP("Handling phantom references...");
- dvmHeapHandleReferences(phantomReferences, REF_PHANTOM);
-#if DVM_TRACK_HEAP_MARKING
- phantomMarkCount = gcHeap->markCount;
- phantomMarkSize = gcHeap->markSize;
- gcHeap->markCount = 0;
- gcHeap->markSize = 0;
-#endif
-
-//TODO: take care of JNI weak global references
-
-#if DVM_TRACK_HEAP_MARKING
- LOGI_HEAP("Marked objects: %dB strong, %dB final, %dB phantom\n",
- strongMarkSize, finalizeMarkSize, phantomMarkSize);
-#endif
+ dvmClearWhiteRefs(&gcHeap->phantomReferences);
#ifdef WITH_DEADLOCK_PREDICTION
dvmDumpMonitorInfo("before sweep");
#endif
LOGD_HEAP("Sweeping...");
- dvmHeapSweepUnmarkedObjects(&numFreed, &sizeFreed);
+ dvmHeapSweepUnmarkedObjects(gcMode, &numFreed, &sizeFreed);
#ifdef WITH_DEADLOCK_PREDICTION
dvmDumpMonitorInfo("after sweep");
#endif
@@ -999,7 +834,6 @@
* it just lets the heap grow more when necessary.
*/
dvmHeapSourceGrowForUtilization();
- dvmHeapSizeChanged();
#if WITH_HPROF
if (gcHeap->hprofContext != NULL) {
@@ -1025,16 +859,20 @@
#ifdef WITH_PROFILER
dvmMethodTraceGCEnd();
#endif
- LOGV_HEAP("GC finished -- resuming threads\n");
+ LOGV_HEAP("GC finished");
+
+ if (gDvm.postVerify) {
+ LOGV_HEAP("Verifying heap after GC");
+ verifyHeap();
+ }
gcHeap->gcRunning = false;
+ LOGV_HEAP("Resuming threads");
dvmUnlockMutex(&gDvm.heapWorkerListLock);
dvmUnlockMutex(&gDvm.heapWorkerLock);
#if defined(WITH_JIT)
- extern void dvmCompilerPerformSafePointChecks(void);
-
/*
* Patching a chaining cell is very cheap as it only updates 4 words. It's
* the overhead of stopping all threads and synchronizing the I/D cache
@@ -1046,24 +884,53 @@
dvmCompilerPerformSafePointChecks();
#endif
- dvmResumeAllThreads(SUSPEND_FOR_GC);
- if (oldThreadPriority != kInvalidPriority) {
- if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
- LOGW_HEAP("Unable to reset priority to %d: %s\n",
- oldThreadPriority, strerror(errno));
- } else {
- LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
- }
+ dirtyEnd = dvmGetRelativeTimeMsec();
- if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
- set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
+ if (reason == GC_CONCURRENT) {
+ dirtySuspendTime = dirtyStart - suspendStart;
+ dirtyTime = dirtyEnd - dirtyStart;
+ }
+
+ dvmResumeAllThreads(SUSPEND_FOR_GC);
+
+ if (reason == GC_CONCURRENT) {
+ /*
+ * Wake-up any threads that blocked after a failed allocation
+ * request.
+ */
+ dvmBroadcastCond(&gDvm.gcHeapCond);
+ }
+
+ if (reason != GC_CONCURRENT) {
+ if (oldThreadPriority != kInvalidPriority) {
+ if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
+ LOGW_HEAP("Unable to reset priority to %d: %s\n",
+ oldThreadPriority, strerror(errno));
+ } else {
+ LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
+ }
+
+ if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
+ set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
+ }
}
}
- gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
- LOGD("%s freed %d objects / %zd bytes in %dms\n",
- GcReasonStr[reason], numFreed, sizeFreed, (int)gcElapsedTime);
- dvmLogGcStats(numFreed, sizeFreed, gcElapsedTime);
+ if (reason != GC_CONCURRENT) {
+ u4 suspendTime = rootStart - suspendStart;
+ u4 markSweepTime = dirtyEnd - rootStart;
+ totalTime = suspendTime + markSweepTime;
+ LOGD("%s freed %d objects / %zd bytes in (%ums) %ums",
+ GcReasonStr[reason], numFreed, sizeFreed,
+ suspendTime, markSweepTime);
+ } else {
+ totalTime = rootSuspendTime + rootTime + dirtySuspendTime + dirtyTime;
+ LOGD("%s freed %d objects / %zd bytes in (%ums) %ums (%ums) %ums",
+ GcReasonStr[reason], numFreed, sizeFreed,
+ rootSuspendTime, rootTime,
+ dirtySuspendTime, dirtyTime);
+ }
+ dvmLogGcStats(numFreed, sizeFreed, totalTime);
if (gcHeap->ddmHpifWhen != 0) {
LOGD_HEAP("Sending VM heap info to DDM\n");
dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
@@ -1078,15 +945,32 @@
}
}
+void dvmWaitForConcurrentGcToComplete(void)
+{
+ Thread *self = dvmThreadSelf();
+ ThreadStatus oldStatus;
+ assert(self != NULL);
+ oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ dvmWaitCond(&gDvm.gcHeapCond, &gDvm.gcHeapLock);
+ dvmChangeStatus(self, oldStatus);
+}
+
#if WITH_HPROF
/*
* Perform garbage collection, writing heap information to the specified file.
*
+ * If "fd" is >= 0, the output will be written to that file descriptor.
+ * Otherwise, "fileName" is used to create an output file.
+ *
* If "fileName" is NULL, a suitable name will be generated automatically.
+ * (TODO: remove this when the SIGUSR1 feature goes away)
+ *
+ * If "directToDdms" is set, the other arguments are ignored, and data is
+ * sent directly to DDMS.
*
* Returns 0 on success, or an error code on failure.
*/
-int hprofDumpHeap(const char* fileName, bool directToDdms)
+int hprofDumpHeap(const char* fileName, int fd, bool directToDdms)
{
int result;
@@ -1094,6 +978,7 @@
gDvm.gcHeap->hprofDumpOnGc = true;
gDvm.gcHeap->hprofFileName = fileName;
+ gDvm.gcHeap->hprofFd = fd;
gDvm.gcHeap->hprofDirectToDdms = directToDdms;
dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP);
result = gDvm.gcHeap->hprofResult;
diff --git a/vm/alloc/Heap.h b/vm/alloc/Heap.h
index 1451739..ea0510f 100644
--- a/vm/alloc/Heap.h
+++ b/vm/alloc/Heap.h
@@ -41,6 +41,12 @@
*/
void dvmHeapShutdown(void);
+/*
+ * Stops any threads internal to the garbage collector. Called before
+ * the heap itself is shutdown.
+ */
+void dvmHeapThreadShutdown(void);
+
#if 0 // needs to be in Alloc.h so debug code can find it.
/*
* Returns a number of bytes greater than or
@@ -52,21 +58,35 @@
size_t dvmObjectSizeInHeap(const Object *obj);
#endif
-enum GcReason {
+typedef enum {
+ /* GC all heaps. */
+ GC_FULL,
+ /* GC just the first heap. */
+ GC_PARTIAL
+} GcMode;
+
+typedef enum {
/* Not enough space for an "ordinary" Object to be allocated. */
GC_FOR_MALLOC,
+ /* Automatic GC triggered by exceeding a heap occupancy threshold. */
+ GC_CONCURRENT,
/* Explicit GC via Runtime.gc(), VMRuntime.gc(), or SIGUSR1. */
GC_EXPLICIT,
/* GC to try to reduce heap footprint to allow more non-GC'ed memory. */
GC_EXTERNAL_ALLOC,
/* GC to dump heap contents to a file, only used under WITH_HPROF */
GC_HPROF_DUMP_HEAP
-};
+} GcReason;
/*
* Run the garbage collector without doing any locking.
*/
-void dvmCollectGarbageInternal(bool collectSoftReferences,
- enum GcReason reason);
+void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason);
+
+/*
+ * Blocks the until the GC thread signals the completion of a
+ * concurrent GC.
+ */
+void dvmWaitForConcurrentGcToComplete(void);
#endif // _DALVIK_ALLOC_HEAP
diff --git a/vm/alloc/HeapBitmap.c b/vm/alloc/HeapBitmap.c
index 778fd87..03269ba 100644
--- a/vm/alloc/HeapBitmap.c
+++ b/vm/alloc/HeapBitmap.c
@@ -17,17 +17,7 @@
#include "Dalvik.h"
#include "HeapBitmap.h"
#include "clz.h"
-#include <limits.h> // for ULONG_MAX
-#include <sys/mman.h> // for madvise(), mmap()
-#include <cutils/ashmem.h>
-
-#define HB_ASHMEM_NAME "dalvik-heap-bitmap"
-
-#define ALIGN_UP_TO_PAGE_SIZE(p) \
- (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
-
-#define LIKELY(exp) (__builtin_expect((exp) != 0, true))
-#define UNLIKELY(exp) (__builtin_expect((exp) != 0, false))
+#include <sys/mman.h> /* for PROT_* */
/*
* Initialize a HeapBitmap so that it points to a bitmap large
@@ -40,80 +30,19 @@
{
void *bits;
size_t bitsLen;
- size_t allocLen;
- int fd;
- char nameBuf[ASHMEM_NAME_LEN] = HB_ASHMEM_NAME;
assert(hb != NULL);
-
+ assert(name != NULL);
bitsLen = HB_OFFSET_TO_INDEX(maxSize) * sizeof(*hb->bits);
- allocLen = ALIGN_UP_TO_PAGE_SIZE(bitsLen); // required by ashmem
-
- if (name != NULL) {
- snprintf(nameBuf, sizeof(nameBuf), HB_ASHMEM_NAME "/%s", name);
- }
- fd = ashmem_create_region(nameBuf, allocLen);
- if (fd < 0) {
- LOGE("Could not create %zu-byte ashmem region \"%s\" to cover "
- "%zu-byte heap (%d)\n",
- allocLen, nameBuf, maxSize, fd);
+ bits = dvmAllocRegion(bitsLen, PROT_READ | PROT_WRITE, name);
+ if (bits == NULL) {
+ LOGE("Could not mmap %zd-byte ashmem region '%s'", bitsLen, name);
return false;
}
-
- bits = mmap(NULL, bitsLen, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
- close(fd);
- if (bits == MAP_FAILED) {
- LOGE("Could not mmap %d-byte ashmem region \"%s\"\n",
- bitsLen, nameBuf);
- return false;
- }
-
- memset(hb, 0, sizeof(*hb));
hb->bits = bits;
- hb->bitsLen = bitsLen;
+ hb->bitsLen = hb->allocLen = bitsLen;
hb->base = (uintptr_t)base;
hb->max = hb->base - 1;
-
- return true;
-}
-
-/*
- * Initialize <hb> so that it covers the same extent as <templateBitmap>.
- */
-bool
-dvmHeapBitmapInitFromTemplate(HeapBitmap *hb, const HeapBitmap *templateBitmap,
- const char *name)
-{
- return dvmHeapBitmapInit(hb,
- (void *)templateBitmap->base, HB_MAX_OFFSET(templateBitmap), name);
-}
-
-/*
- * Initialize the bitmaps in <out> so that they cover the same extent as
- * the corresponding bitmaps in <templates>.
- */
-bool
-dvmHeapBitmapInitListFromTemplates(HeapBitmap out[], HeapBitmap templates[],
- size_t numBitmaps, const char *name)
-{
- size_t i;
- char fullName[PATH_MAX];
-
- fullName[sizeof(fullName)-1] = '\0';
- for (i = 0; i < numBitmaps; i++) {
- bool ok;
-
- /* If two ashmem regions have the same name, only one gets
- * the name when looking at the maps.
- */
- snprintf(fullName, sizeof(fullName)-1, "%s/%zd", name, i);
-
- ok = dvmHeapBitmapInitFromTemplate(&out[i], &templates[i], fullName);
- if (!ok) {
- dvmHeapBitmapDeleteList(out, i);
- return false;
- }
- }
return true;
}
@@ -126,27 +55,12 @@
assert(hb != NULL);
if (hb->bits != NULL) {
- // Re-calculate the size we passed to mmap().
- size_t allocLen = ALIGN_UP_TO_PAGE_SIZE(hb->bitsLen);
- munmap((char *)hb->bits, allocLen);
+ munmap((char *)hb->bits, hb->allocLen);
}
memset(hb, 0, sizeof(*hb));
}
/*
- * Clean up any resources associated with the bitmaps.
- */
-void
-dvmHeapBitmapDeleteList(HeapBitmap hbs[], size_t numBitmaps)
-{
- size_t i;
-
- for (i = 0; i < numBitmaps; i++) {
- dvmHeapBitmapDelete(&hbs[i]);
- }
-}
-
-/*
* Fill the bitmap with zeroes. Returns the bitmap's memory to
* the system as a side-effect.
*/
@@ -166,20 +80,22 @@
/*
* Walk through the bitmaps in increasing address order, and find the
- * object pointers that correspond to places where the bitmaps differ.
- * Call <callback> zero or more times with lists of these object pointers.
+ * object pointers that correspond to garbage objects. Call
+ * <callback> zero or more times with lists of these object pointers.
*
* The <finger> argument to the callback indicates the next-highest
* address that hasn't been visited yet; setting bits for objects whose
* addresses are less than <finger> are not guaranteed to be seen by
- * the current XorWalk. <finger> will be set to ULONG_MAX when the
+ * the current walk.
+ *
+ * The callback is permitted to increase the bitmap's max; the walk
+ * will use the updated max as a terminating condition,
+ *
+ * <finger> will be set to some value beyond the bitmap max when the
* end of the bitmap is reached.
*/
-bool
-dvmHeapBitmapXorWalk(const HeapBitmap *hb1, const HeapBitmap *hb2,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg)
+void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
+ BitmapCallback *callback, void *callbackArg)
{
static const size_t kPointerBufSize = 128;
void *pointerBuf[kPointerBufSize];
@@ -189,12 +105,8 @@
#define FLUSH_POINTERBUF(finger_) \
do { \
- if (!callback(pb - pointerBuf, (void **)pointerBuf, \
- (void *)(finger_), callbackArg)) \
- { \
- LOGW("dvmHeapBitmapXorWalk: callback failed\n"); \
- return false; \
- } \
+ (*callback)(pb - pointerBuf, (void **)pointerBuf, \
+ (void *)(finger_), callbackArg); \
pb = pointerBuf; \
} while (false)
@@ -224,45 +136,44 @@
} \
} while (false)
- assert(hb1 != NULL);
- assert(hb1->bits != NULL);
- assert(hb2 != NULL);
- assert(hb2->bits != NULL);
+ assert(liveHb != NULL);
+ assert(liveHb->bits != NULL);
+ assert(markHb != NULL);
+ assert(markHb->bits != NULL);
assert(callback != NULL);
- if (hb1->base != hb2->base) {
- LOGW("dvmHeapBitmapXorWalk: bitmaps cover different heaps "
- "(0x%08x != 0x%08x)\n",
- (uintptr_t)hb1->base, (uintptr_t)hb2->base);
- return false;
+ if (liveHb->base != markHb->base) {
+ LOGW("dvmHeapBitmapSweepWalk: bitmaps cover different heaps (%zd != %zd)",
+ liveHb->base, markHb->base);
+ return;
}
- if (hb1->bitsLen != hb2->bitsLen) {
- LOGW("dvmHeapBitmapXorWalk: size of bitmaps differ (%zd != %zd)\n",
- hb1->bitsLen, hb2->bitsLen);
- return false;
+ if (liveHb->bitsLen != markHb->bitsLen) {
+ LOGW("dvmHeapBitmapSweepWalk: size of bitmaps differ (%zd != %zd)",
+ liveHb->bitsLen, markHb->bitsLen);
+ return;
}
- if (hb1->max < hb1->base && hb2->max < hb2->base) {
+ if (liveHb->max < liveHb->base && markHb->max < markHb->base) {
/* Easy case; both are obviously empty.
*/
- return true;
+ return;
}
/* First, walk along the section of the bitmaps that may be the same.
*/
- if (hb1->max >= hb1->base && hb2->max >= hb2->base) {
- unsigned long int *p1, *p2;
+ if (liveHb->max >= liveHb->base && markHb->max >= markHb->base) {
+ unsigned long *live, *mark;
uintptr_t offset;
- offset = ((hb1->max < hb2->max) ? hb1->max : hb2->max) - hb1->base;
+ offset = ((liveHb->max < markHb->max) ? liveHb->max : markHb->max) - liveHb->base;
//TODO: keep track of which (and whether) one is longer for later
index = HB_OFFSET_TO_INDEX(offset);
- p1 = hb1->bits;
- p2 = hb2->bits;
+ live = liveHb->bits;
+ mark = markHb->bits;
for (i = 0; i <= index; i++) {
//TODO: unroll this. pile up a few in locals?
- unsigned long int diff = *p1++ ^ *p2++;
- DECODE_BITS(hb1, diff, false);
+ unsigned long garbage = live[i] & ~mark[i];
+ DECODE_BITS(liveHb, garbage, false);
//BUG: if the callback was called, either max could have changed.
}
/* The next index to look at.
@@ -278,9 +189,9 @@
* set bits.
*/
const HeapBitmap *longHb;
-unsigned long int *p;
+unsigned long *p;
//TODO: may be the same size, in which case this is wasted work
- longHb = (hb1->max > hb2->max) ? hb1 : hb2;
+ longHb = (liveHb->max > markHb->max) ? liveHb : markHb;
i = index;
index = HB_OFFSET_TO_INDEX(longHb->max - longHb->base);
p = longHb->bits + i;
@@ -291,87 +202,24 @@
}
if (pb > pointerBuf) {
- /* Set the finger to the end of the heap (rather than longHb->max)
- * so that the callback doesn't expect to be called again
- * if it happens to change the current max.
+ /* Set the finger to the end of the heap (rather than
+ * longHb->max) so that the callback doesn't expect to be
+ * called again if it happens to change the current max.
*/
- FLUSH_POINTERBUF(longHb->base + HB_MAX_OFFSET(longHb));
+ uintptr_t finalFinger = longHb->base + HB_MAX_OFFSET(longHb);
+ FLUSH_POINTERBUF(finalFinger);
+ assert(finalFinger > longHb->max);
}
-
- return true;
-
#undef FLUSH_POINTERBUF
#undef DECODE_BITS
}
/*
- * Fills outIndexList with indices so that for all i:
- *
- * hb[outIndexList[i]].base < hb[outIndexList[i+1]].base
+ * dvmHeapBitmapWalk is equivalent to dvmHeapBitmapSweepWalk with
+ * nothing marked.
*/
-static void
-createSortedBitmapIndexList(const HeapBitmap hbs[], size_t numBitmaps,
- size_t outIndexList[])
-{
- int i, j;
-
- /* numBitmaps is usually 2 or 3, so use a simple sort */
- for (i = 0; i < (int) numBitmaps; i++) {
- outIndexList[i] = i;
- for (j = 0; j < i; j++) {
- if (hbs[j].base > hbs[i].base) {
- int tmp = outIndexList[i];
- outIndexList[i] = outIndexList[j];
- outIndexList[j] = tmp;
- }
- }
- }
-}
-
-/*
- * Similar to dvmHeapBitmapXorWalk(), but compare multiple bitmaps.
- * Regardless of the order of the arrays, the bitmaps will be visited
- * in address order, so that finger will increase monotonically.
- */
-bool
-dvmHeapBitmapXorWalkLists(const HeapBitmap hbs1[], const HeapBitmap hbs2[],
- size_t numBitmaps,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg)
-{
- size_t indexList[numBitmaps];
- size_t i;
-
- /* Sort the bitmaps by address. Assume that the two lists contain
- * congruent bitmaps.
- */
- createSortedBitmapIndexList(hbs1, numBitmaps, indexList);
-
- /* Walk each pair of bitmaps, lowest address first.
- */
- for (i = 0; i < numBitmaps; i++) {
- bool ok;
-
- ok = dvmHeapBitmapXorWalk(&hbs1[indexList[i]], &hbs2[indexList[i]],
- callback, callbackArg);
- if (!ok) {
- return false;
- }
- }
-
- return true;
-}
-
-/*
- * Similar to dvmHeapBitmapXorWalk(), but visit the set bits
- * in a single bitmap.
- */
-bool
-dvmHeapBitmapWalk(const HeapBitmap *hb,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg)
+void dvmHeapBitmapWalk(const HeapBitmap *hb,
+ BitmapCallback *callback, void *callbackArg)
{
/* Create an empty bitmap with the same extent as <hb>.
* Don't actually allocate any memory.
@@ -380,37 +228,5 @@
emptyHb.max = emptyHb.base - 1; // empty
emptyHb.bits = (void *)1; // non-NULL but intentionally bad
- return dvmHeapBitmapXorWalk(hb, &emptyHb, callback, callbackArg);
-}
-
-/*
- * Similar to dvmHeapBitmapXorWalkList(), but visit the set bits
- * in a single list of bitmaps. Regardless of the order of the array,
- * the bitmaps will be visited in address order, so that finger will
- * increase monotonically.
- */
-bool dvmHeapBitmapWalkList(const HeapBitmap hbs[], size_t numBitmaps,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg)
-{
- size_t indexList[numBitmaps];
- size_t i;
-
- /* Sort the bitmaps by address.
- */
- createSortedBitmapIndexList(hbs, numBitmaps, indexList);
-
- /* Walk each bitmap, lowest address first.
- */
- for (i = 0; i < numBitmaps; i++) {
- bool ok;
-
- ok = dvmHeapBitmapWalk(&hbs[indexList[i]], callback, callbackArg);
- if (!ok) {
- return false;
- }
- }
-
- return true;
+ dvmHeapBitmapSweepWalk(hb, &emptyHb, callback, callbackArg);
}
diff --git a/vm/alloc/HeapBitmap.h b/vm/alloc/HeapBitmap.h
index b3e61c5..1f05c2b 100644
--- a/vm/alloc/HeapBitmap.h
+++ b/vm/alloc/HeapBitmap.h
@@ -17,10 +17,9 @@
#define _DALVIK_HEAP_BITMAP
#include <stdint.h>
-#include <assert.h>
#define HB_OBJECT_ALIGNMENT 8
-#define HB_BITS_PER_WORD (sizeof (unsigned long int) * 8)
+#define HB_BITS_PER_WORD (sizeof (unsigned long) * 8)
/* <offset> is the difference from .base to a pointer address.
* <index> is the index of .bits that contains the bit representing
@@ -31,6 +30,9 @@
#define HB_INDEX_TO_OFFSET(index_) \
((uintptr_t)(index_) * HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD)
+#define HB_OFFSET_TO_BYTE_INDEX(offset_) \
+ (HB_OFFSET_TO_INDEX(offset_) * sizeof(*((HeapBitmap *)0)->bits))
+
/* Pack the bits in backwards so they come out in address order
* when using CLZ.
*/
@@ -48,16 +50,23 @@
static inline p
-typedef struct {
+struct HeapBitmap {
/* The bitmap data, which points to an mmap()ed area of zeroed
* anonymous memory.
*/
- unsigned long int *bits;
+ unsigned long *bits;
- /* The size of the memory pointed to by bits, in bytes.
+ /* The size of the used memory pointed to by bits, in bytes. This
+ * value changes when the bitmap is shrunk.
*/
size_t bitsLen;
+ /* The real size of the memory pointed to by bits. This is the
+ * number of bytes we requested from the allocator and does not
+ * change.
+ */
+ size_t allocLen;
+
/* The base address, which corresponds to the first bit in
* the bitmap.
*/
@@ -68,8 +77,11 @@
* to a set bit. If there are no bits set, (max < base).
*/
uintptr_t max;
-} HeapBitmap;
+};
+typedef struct HeapBitmap HeapBitmap;
+typedef void BitmapCallback(size_t numPtrs, void **ptrs,
+ const void *finger, void *arg);
/*
* Initialize a HeapBitmap so that it points to a bitmap large
@@ -80,29 +92,11 @@
const char *name);
/*
- * Initialize <hb> so that it covers the same extent as <templateBitmap>.
- */
-bool dvmHeapBitmapInitFromTemplate(HeapBitmap *hb,
- const HeapBitmap *templateBitmap, const char *name);
-
-/*
- * Initialize the bitmaps in <out> so that they cover the same extent as
- * the corresponding bitmaps in <templates>.
- */
-bool dvmHeapBitmapInitListFromTemplates(HeapBitmap out[],
- HeapBitmap templates[], size_t numBitmaps, const char *name);
-
-/*
* Clean up any resources associated with the bitmap.
*/
void dvmHeapBitmapDelete(HeapBitmap *hb);
/*
- * Clean up any resources associated with the bitmaps.
- */
-void dvmHeapBitmapDeleteList(HeapBitmap hbs[], size_t numBitmaps);
-
-/*
* Fill the bitmap with zeroes. Returns the bitmap's memory to
* the system as a side-effect.
*/
@@ -110,66 +104,29 @@
/*
* Walk through the bitmaps in increasing address order, and find the
- * object pointers that correspond to places where the bitmaps differ.
- * Call <callback> zero or more times with lists of these object pointers.
+ * object pointers that correspond to garbage objects. Call
+ * <callback> zero or more times with lists of these object pointers.
*
* The <finger> argument to the callback indicates the next-highest
* address that hasn't been visited yet; setting bits for objects whose
* addresses are less than <finger> are not guaranteed to be seen by
- * the current XorWalk. <finger> will be set to ULONG_MAX when the
+ * the current walk.
+ *
+ * The callback is permitted to increase the bitmap's max; the walk
+ * will use the updated max as a terminating condition,
+ *
+ * <finger> will be set to some value beyond the bitmap max when the
* end of the bitmap is reached.
*/
-bool dvmHeapBitmapXorWalk(const HeapBitmap *hb1, const HeapBitmap *hb2,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg);
+void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
+ BitmapCallback *callback, void *callbackArg);
/*
- * Similar to dvmHeapBitmapXorWalk(), but compare multiple bitmaps.
- * Regardless of the order of the arrays, the bitmaps will be visited
- * in address order, so that finger will increase monotonically.
- */
-bool dvmHeapBitmapXorWalkLists(const HeapBitmap hbs1[], const HeapBitmap hbs2[],
- size_t numBitmaps,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg);
-
-/*
- * Similar to dvmHeapBitmapXorWalk(), but visit the set bits
+ * Similar to dvmHeapBitmapSweepWalk(), but visit the set bits
* in a single bitmap.
*/
-bool dvmHeapBitmapWalk(const HeapBitmap *hb,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg);
-
-/*
- * Similar to dvmHeapBitmapXorWalkList(), but visit the set bits
- * in a single list of bitmaps. Regardless of the order of the array,
- * the bitmaps will be visited in address order, so that finger will
- * increase monotonically.
- */
-bool dvmHeapBitmapWalkList(const HeapBitmap hbs[], size_t numBitmaps,
- bool (*callback)(size_t numPtrs, void **ptrs,
- const void *finger, void *arg),
- void *callbackArg);
-/*
- * Return true iff <obj> is within the range of pointers that
- * have had corresponding bits set in this bitmap.
- */
-HB_INLINE_PROTO(
- bool
- dvmHeapBitmapMayContainObject(const HeapBitmap *hb,
- const void *obj)
-)
-{
- const uintptr_t p = (const uintptr_t)obj;
-
- assert((p & (HB_OBJECT_ALIGNMENT - 1)) == 0);
-
- return p >= hb->base && p <= hb->max;
-}
+void dvmHeapBitmapWalk(const HeapBitmap *hb,
+ BitmapCallback *callback, void *callbackArg);
/*
* Return true iff <obj> is within the range of pointers that this
@@ -195,28 +152,26 @@
* Internal function; do not call directly.
*/
HB_INLINE_PROTO(
- unsigned long int
+ unsigned long
_heapBitmapModifyObjectBit(HeapBitmap *hb, const void *obj,
bool setBit, bool returnOld)
)
{
const uintptr_t offset = (uintptr_t)obj - hb->base;
const size_t index = HB_OFFSET_TO_INDEX(offset);
- const unsigned long int mask = HB_OFFSET_TO_MASK(offset);
+ const unsigned long mask = HB_OFFSET_TO_MASK(offset);
-#ifndef NDEBUG
assert(hb->bits != NULL);
assert((uintptr_t)obj >= hb->base);
assert(index < hb->bitsLen / sizeof(*hb->bits));
-#endif
if (setBit) {
if ((uintptr_t)obj > hb->max) {
hb->max = (uintptr_t)obj;
}
if (returnOld) {
- unsigned long int *p = hb->bits + index;
- const unsigned long int word = *p;
+ unsigned long *p = hb->bits + index;
+ const unsigned long word = *p;
*p |= mask;
return word & mask;
} else {
@@ -237,7 +192,7 @@
* set bits will be lost.
*/
HB_INLINE_PROTO(
- unsigned long int
+ unsigned long
dvmHeapBitmapSetAndReturnObjectBit(HeapBitmap *hb, const void *obj)
)
{
@@ -245,29 +200,6 @@
}
/*
- * Like dvmHeapBitmapSetAndReturnObjectBit(), but sets/returns the bit
- * in the appropriate bitmap. Results are undefined if <obj> is not
- * covered by any bitmap.
- */
-HB_INLINE_PROTO(
- unsigned long int
- dvmHeapBitmapSetAndReturnObjectBitInList(HeapBitmap hbs[],
- size_t numBitmaps, const void *obj)
-)
-{
- size_t i;
-
- for (i = 0; i < numBitmaps; i++) {
- if (dvmHeapBitmapCoversAddress(&hbs[i], obj)) {
- return dvmHeapBitmapSetAndReturnObjectBit(&hbs[i], obj);
- }
- }
-
- assert(!"object not covered by any bitmap");
- return false;
-}
-
-/*
* Sets the bit corresponding to <obj>, and widens the range of seen
* pointers if necessary. Does no range checking.
*/
@@ -298,7 +230,7 @@
* set bits will be lost.
*/
HB_INLINE_PROTO(
- unsigned long int
+ unsigned long
dvmHeapBitmapIsObjectBitSet(const HeapBitmap *hb, const void *obj)
)
{
@@ -314,27 +246,6 @@
}
}
-/*
- * Looks through the list of bitmaps and returns the current value of the
- * bit corresponding to <obj>, which may be covered by any of the bitmaps.
- * Does no range checking.
- */
-HB_INLINE_PROTO(
- long
- dvmHeapBitmapIsObjectBitSetInList(const HeapBitmap hbs[], size_t numBitmaps,
- const void *obj)
-)
-{
- size_t i;
-
- for (i = 0; i < numBitmaps; i++) {
- if (dvmHeapBitmapCoversAddress(&hbs[i], obj)) {
- return dvmHeapBitmapIsObjectBitSet(&hbs[i], obj);
- }
- }
- return false;
-}
-
#undef HB_INLINE_PROTO
#endif // _DALVIK_HEAP_BITMAP
diff --git a/vm/alloc/HeapDebug.c b/vm/alloc/HeapDebug.c
index 54b5cb6..cb8fb48 100644
--- a/vm/alloc/HeapDebug.c
+++ b/vm/alloc/HeapDebug.c
@@ -110,31 +110,29 @@
void dvmLogGcStats(size_t numFreed, size_t sizeFreed, size_t gcTimeMs)
{
- const GcHeap *gcHeap = gDvm.gcHeap;
size_t perHeapActualSize[HEAP_SOURCE_MAX_HEAP_COUNT],
perHeapAllowedSize[HEAP_SOURCE_MAX_HEAP_COUNT],
perHeapNumAllocated[HEAP_SOURCE_MAX_HEAP_COUNT],
perHeapSizeAllocated[HEAP_SOURCE_MAX_HEAP_COUNT];
unsigned char eventBuf[1 + (1 + sizeof(long long)) * 4];
size_t actualSize, allowedSize, numAllocated, sizeAllocated;
- size_t i;
size_t softLimit = dvmHeapSourceGetIdealFootprint();
size_t nHeaps = dvmHeapSourceGetNumHeaps();
/* Enough to quiet down gcc for unitialized variable check */
perHeapActualSize[0] = perHeapAllowedSize[0] = perHeapNumAllocated[0] =
perHeapSizeAllocated[0] = 0;
- actualSize = dvmHeapSourceGetValue(HS_FOOTPRINT, perHeapActualSize,
+ actualSize = dvmHeapSourceGetValue(HS_FOOTPRINT, perHeapActualSize,
HEAP_SOURCE_MAX_HEAP_COUNT);
- allowedSize = dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT,
+ allowedSize = dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT,
perHeapAllowedSize, HEAP_SOURCE_MAX_HEAP_COUNT);
numAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED,
perHeapNumAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
sizeAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED,
perHeapSizeAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
- /*
- * Construct the the first 64-bit value to write to the log.
+ /*
+ * Construct the the first 64-bit value to write to the log.
* Global information:
*
* [63 ] Must be zero
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index 9a5071f..0298f84 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -24,26 +24,9 @@
#include "HeapTable.h"
#include "MarkSweep.h"
-#define SCHEDULED_REFERENCE_MAGIC ((Object*)0x87654321)
-
-#define ptr2chunk(p) (((DvmHeapChunk *)(p)) - 1)
-#define chunk2ptr(p) ((void *)(((DvmHeapChunk *)(p)) + 1))
-
-typedef struct DvmHeapChunk {
-#if WITH_HPROF && WITH_HPROF_STACK
- u4 stackTraceSerialNumber;
-#endif
- u8 data[0];
-} DvmHeapChunk;
-
struct GcHeap {
HeapSource *heapSource;
- /* List of heap objects that the GC should never collect.
- * These should be included in the root set of objects.
- */
- HeapRefTable nonCollectableRefs;
-
/* List of heap objects that will require finalization when
* collected. I.e., instance objects
*
@@ -110,51 +93,14 @@
*/
GcMarkContext markContext;
- /* Set to dvmGetRelativeTimeUsec() whenever a GC begins.
- * The value is preserved between GCs, so it can be used
- * to determine the time between successive GCs.
- * Initialized to zero before the first GC.
- */
- u8 gcStartTime;
+ /* GC's card table */
+ u1* cardTableBase;
+ size_t cardTableLength;
/* Is the GC running? Used to avoid recursive calls to GC.
*/
bool gcRunning;
- /* Set at the end of a GC to indicate the collection policy
- * for SoftReferences during the following GC.
- */
- enum { SR_COLLECT_NONE, SR_COLLECT_SOME, SR_COLLECT_ALL }
- softReferenceCollectionState;
-
- /* The size of the heap is compared against this value
- * to determine when to start collecting SoftReferences.
- */
- size_t softReferenceHeapSizeThreshold;
-
- /* A value that will increment every time we see a SoftReference
- * whose referent isn't marked (during SR_COLLECT_SOME).
- * The absolute value is meaningless, and does not need to
- * be reset or initialized at any point.
- */
- int softReferenceColor;
-
- /* Indicates whether or not the object scanner should bother
- * keeping track of any references. If markAllReferents is
- * true, referents will be hard-marked. If false, normal
- * reference following is used.
- */
- bool markAllReferents;
-
-#if DVM_TRACK_HEAP_MARKING
- /* Every time an unmarked object becomes marked, markCount
- * is incremented and markSize increases by the size of
- * that object.
- */
- size_t markCount;
- size_t markSize;
-#endif
-
/*
* Debug control values
*/
@@ -168,6 +114,7 @@
#if WITH_HPROF
bool hprofDumpOnGc;
const char* hprofFileName;
+ int hprofFd;
hprof_context_t *hprofContext;
int hprofResult;
bool hprofDirectToDdms;
@@ -178,7 +125,6 @@
void dvmUnlockHeap(void);
void dvmLogGcStats(size_t numFreed, size_t sizeFreed, size_t gcTimeMs);
void dvmLogMadviseStats(size_t madvisedSizes[], size_t arrayLen);
-void dvmHeapSizeChanged(void);
/*
* Logging helpers
diff --git a/vm/alloc/HeapSource.c b/vm/alloc/HeapSource.c
index 384ec78..fd5d79f 100644
--- a/vm/alloc/HeapSource.c
+++ b/vm/alloc/HeapSource.c
@@ -42,6 +42,12 @@
#define HEAP_IDEAL_FREE (2 * 1024 * 1024)
#define HEAP_MIN_FREE (HEAP_IDEAL_FREE / 4)
+/*
+ * When the number of bytes allocated since the previous GC exceeds
+ * this threshold a concurrent garbage collection is triggered.
+ */
+#define OCCUPANCY_THRESHOLD (256 << 10)
+
#define HS_BOILERPLATE() \
do { \
assert(gDvm.gcHeap != NULL); \
@@ -99,10 +105,6 @@
*/
mspace msp;
- /* The bitmap that keeps track of where objects are in the heap.
- */
- HeapBitmap objectBitmap;
-
/* The largest size that this heap is allowed to grow to.
*/
size_t absoluteMaxSize;
@@ -113,9 +115,25 @@
*/
size_t bytesAllocated;
+ /*
+ * The number of bytes allocated after the previous garbage
+ * collection.
+ */
+ size_t prevBytesAllocated;
+
/* Number of objects currently allocated from this mspace.
*/
size_t objectsAllocated;
+
+ /*
+ * The lowest address of this heap, inclusive.
+ */
+ char *base;
+
+ /*
+ * The highest address of this heap, exclusive.
+ */
+ char *limit;
} Heap;
struct HeapSource {
@@ -165,6 +183,35 @@
/* True if zygote mode was active when the HeapSource was created.
*/
bool sawZygote;
+
+ /*
+ * The base address of the virtual memory reservation.
+ */
+ char *heapBase;
+
+ /*
+ * The length in bytes of the virtual memory reservation.
+ */
+ size_t heapLength;
+
+ /*
+ * The live object bitmap.
+ */
+ HeapBitmap liveBits;
+
+ /*
+ * The mark bitmap.
+ */
+ HeapBitmap markBits;
+
+ /*
+ * State for the GC daemon.
+ */
+ bool hasGcThread;
+ pthread_t gcThread;
+ bool gcThreadShutdown;
+ pthread_mutex_t gcThreadMutex;
+ pthread_cond_t gcThreadCond;
};
#define hs2heap(hs_) (&((hs_)->heaps[0]))
@@ -220,8 +267,8 @@
if (ptr != NULL) {
for (i = 0; i < numHeaps; i++) {
const Heap *const heap = &hs->heaps[i];
-
- if (dvmHeapBitmapMayContainObject(&heap->objectBitmap, ptr)) {
+
+ if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) {
return (Heap *)heap;
}
}
@@ -237,35 +284,39 @@
*
* These aren't exact, and should not be treated as such.
*/
-static inline void
-countAllocation(Heap *heap, const void *ptr, bool isObj)
+static void countAllocation(Heap *heap, const void *ptr, bool isObj)
{
+ HeapSource *hs;
+
assert(heap->bytesAllocated < mspace_footprint(heap->msp));
heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
HEAP_SOURCE_CHUNK_OVERHEAD;
if (isObj) {
heap->objectsAllocated++;
- dvmHeapBitmapSetObjectBit(&heap->objectBitmap, ptr);
+ hs = gDvm.gcHeap->heapSource;
+ dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr);
}
assert(heap->bytesAllocated < mspace_footprint(heap->msp));
}
-static inline void
-countFree(Heap *heap, const void *ptr, bool isObj)
+static void countFree(Heap *heap, const void *ptr, bool isObj)
{
+ HeapSource *hs;
size_t delta;
delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
assert(delta > 0);
if (delta < heap->bytesAllocated) {
heap->bytesAllocated -= delta;
+ heap->prevBytesAllocated = heap->bytesAllocated;
} else {
heap->bytesAllocated = 0;
}
if (isObj) {
- dvmHeapBitmapClearObjectBit(&heap->objectBitmap, ptr);
+ hs = gDvm.gcHeap->heapSource;
+ dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr);
if (heap->objectsAllocated > 0) {
heap->objectsAllocated--;
}
@@ -275,17 +326,9 @@
static HeapSource *gHs = NULL;
static mspace
-createMspace(size_t startSize, size_t absoluteMaxSize, size_t id)
+createMspace(void *base, size_t startSize, size_t absoluteMaxSize)
{
mspace msp;
- char name[PATH_MAX];
-
- /* If two ashmem regions have the same name, only one gets
- * the name when looking at the maps.
- */
- snprintf(name, sizeof(name)-1, "dalvik-heap%s/%zd",
- gDvm.zygote ? "/zygote" : "", id);
- name[sizeof(name)-1] = '\0';
/* Create an unlocked dlmalloc mspace to use as
* a small-object heap source.
@@ -297,8 +340,8 @@
*/
LOGV_HEAP("Creating VM heap of size %u\n", startSize);
errno = 0;
- msp = create_contiguous_mspace_with_name(startSize/2,
- absoluteMaxSize, /*locked=*/false, name);
+ msp = create_contiguous_mspace_with_base(startSize/2,
+ absoluteMaxSize, /*locked=*/false, base);
if (msp != NULL) {
/* Don't let the heap grow past the starting size without
* our intervention.
@@ -308,8 +351,8 @@
/* There's no guarantee that errno has meaning when the call
* fails, but it often does.
*/
- LOGE_HEAP("Can't create VM heap of size (%u,%u) (errno=%d)\n",
- startSize/2, absoluteMaxSize, errno);
+ LOGE_HEAP("Can't create VM heap of size (%u,%u): %s\n",
+ startSize/2, absoluteMaxSize, strerror(errno));
}
return msp;
@@ -319,6 +362,7 @@
addNewHeap(HeapSource *hs, mspace msp, size_t mspAbsoluteMaxSize)
{
Heap heap;
+ void *base;
if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
@@ -332,31 +376,30 @@
if (msp != NULL) {
heap.msp = msp;
heap.absoluteMaxSize = mspAbsoluteMaxSize;
+ heap.base = hs->heapBase;
+ heap.limit = hs->heapBase + heap.absoluteMaxSize;
} else {
size_t overhead;
- overhead = oldHeapOverhead(hs, true);
+ overhead = ALIGN_UP_TO_PAGE_SIZE(oldHeapOverhead(hs, true));
if (overhead + HEAP_MIN_FREE >= hs->absoluteMaxSize) {
LOGE_HEAP("No room to create any more heaps "
"(%zd overhead, %zd max)\n",
overhead, hs->absoluteMaxSize);
return false;
}
+ hs->heaps[0].absoluteMaxSize = overhead;
heap.absoluteMaxSize = hs->absoluteMaxSize - overhead;
- heap.msp = createMspace(HEAP_MIN_FREE, heap.absoluteMaxSize,
- hs->numHeaps);
+ base = contiguous_mspace_sbrk0(hs->heaps[0].msp);
+ hs->heaps[0].limit = base;
+ base = (void *)ALIGN_UP_TO_PAGE_SIZE(base);
+ heap.msp = createMspace(base, HEAP_MIN_FREE, heap.absoluteMaxSize);
+ heap.base = base;
+ heap.limit = heap.base + heap.absoluteMaxSize;
if (heap.msp == NULL) {
return false;
}
}
- if (!dvmHeapBitmapInit(&heap.objectBitmap,
- (void *)ALIGN_DOWN_TO_PAGE_SIZE(heap.msp),
- heap.absoluteMaxSize,
- "objects"))
- {
- LOGE_HEAP("Can't create objectBitmap\n");
- goto fail;
- }
/* Don't let the soon-to-be-old heap grow any further.
*/
@@ -373,12 +416,47 @@
hs->numHeaps++;
return true;
+}
-fail:
- if (msp == NULL) {
- destroy_contiguous_mspace(heap.msp);
+/*
+ * The garbage collection daemon. Initiates a concurrent collection
+ * when signaled.
+ */
+static void *gcDaemonThread(void* arg)
+{
+ dvmChangeStatus(NULL, THREAD_VMWAIT);
+ dvmLockMutex(&gHs->gcThreadMutex);
+ while (gHs->gcThreadShutdown != true) {
+ dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex);
+ dvmLockHeap();
+ dvmChangeStatus(NULL, THREAD_RUNNING);
+ dvmCollectGarbageInternal(false, GC_CONCURRENT);
+ dvmChangeStatus(NULL, THREAD_VMWAIT);
+ dvmUnlockHeap();
}
- return false;
+ dvmChangeStatus(NULL, THREAD_RUNNING);
+ return NULL;
+}
+
+static bool gcDaemonStartup(void)
+{
+ dvmInitMutex(&gHs->gcThreadMutex);
+ pthread_cond_init(&gHs->gcThreadCond, NULL);
+ gHs->gcThreadShutdown = false;
+ gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC",
+ gcDaemonThread, NULL);
+ return gHs->hasGcThread;
+}
+
+static void gcDaemonShutdown(void)
+{
+ if (gHs->hasGcThread) {
+ dvmLockMutex(&gHs->gcThreadMutex);
+ gHs->gcThreadShutdown = true;
+ dvmSignalCond(&gHs->gcThreadCond);
+ dvmUnlockMutex(&gHs->gcThreadMutex);
+ pthread_join(gHs->gcThread, NULL);
+ }
}
/*
@@ -391,8 +469,9 @@
{
GcHeap *gcHeap;
HeapSource *hs;
- Heap *heap;
mspace msp;
+ size_t length;
+ void *base;
assert(gHs == NULL);
@@ -402,12 +481,22 @@
return NULL;
}
+ /*
+ * Allocate a contiguous region of virtual memory to subdivided
+ * among the heaps managed by the garbage collector.
+ */
+ length = ALIGN_UP_TO_PAGE_SIZE(absoluteMaxSize);
+ base = dvmAllocRegion(length, PROT_NONE, "dalvik-heap");
+ if (base == NULL) {
+ return NULL;
+ }
+
/* Create an unlocked dlmalloc mspace to use as
* the small object heap source.
*/
- msp = createMspace(startSize, absoluteMaxSize, 0);
+ msp = createMspace(base, startSize, absoluteMaxSize);
if (msp == NULL) {
- return false;
+ goto fail;
}
/* Allocate a descriptor from the heap we just created.
@@ -434,11 +523,24 @@
hs->softLimit = INT_MAX; // no soft limit at first
hs->numHeaps = 0;
hs->sawZygote = gDvm.zygote;
+ hs->hasGcThread = false;
+ hs->heapBase = base;
+ hs->heapLength = length;
if (!addNewHeap(hs, msp, absoluteMaxSize)) {
LOGE_HEAP("Can't add initial heap\n");
goto fail;
}
+ if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) {
+ LOGE_HEAP("Can't create liveBits\n");
+ goto fail;
+ }
+ if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) {
+ LOGE_HEAP("Can't create markBits\n");
+ dvmHeapBitmapDelete(&hs->liveBits);
+ goto fail;
+ }
+ gcHeap->markContext.bitmap = &hs->markBits;
gcHeap->heapSource = hs;
countAllocation(hs2heap(hs), gcHeap, false);
@@ -448,31 +550,13 @@
return gcHeap;
fail:
- destroy_contiguous_mspace(msp);
+ munmap(base, length);
return NULL;
}
-/*
- * If the HeapSource was created while in zygote mode, this
- * will create a new heap for post-zygote allocations.
- * Having a separate heap should maximize the number of pages
- * that a given app_process shares with the zygote process.
- */
-bool
-dvmHeapSourceStartupAfterZygote()
+bool dvmHeapSourceStartupAfterZygote(void)
{
- HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
-
- HS_BOILERPLATE();
-
- assert(!gDvm.zygote);
-
- if (hs->sawZygote) {
- /* Create a new heap for post-zygote allocations.
- */
- return addNewHeap(hs, NULL, 0);
- }
- return true;
+ return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true;
}
/*
@@ -502,38 +586,47 @@
return true;
}
+void dvmHeapSourceThreadShutdown(void)
+{
+ if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) {
+ gcDaemonShutdown();
+ }
+}
+
/*
- * Tears down the heap source and frees any resources associated with it.
+ * Tears down the entire GcHeap structure and all of the substructures
+ * attached to it. This call has the side effect of setting the given
+ * gcHeap pointer and gHs to NULL.
*/
void
-dvmHeapSourceShutdown(GcHeap *gcHeap)
+dvmHeapSourceShutdown(GcHeap **gcHeap)
{
- if (gcHeap != NULL && gcHeap->heapSource != NULL) {
+ if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
HeapSource *hs;
- size_t numHeaps;
- size_t i;
- hs = gcHeap->heapSource;
+ hs = (*gcHeap)->heapSource;
+
+ assert((char *)*gcHeap >= hs->heapBase);
+ assert((char *)*gcHeap < hs->heapBase + hs->heapLength);
+
+ dvmHeapBitmapDelete(&hs->liveBits);
+ dvmHeapBitmapDelete(&hs->markBits);
+
+ munmap(hs->heapBase, hs->heapLength);
gHs = NULL;
-
- /* Cache numHeaps because hs will be invalid after the last
- * heap is freed.
- */
- numHeaps = hs->numHeaps;
-
- for (i = 0; i < numHeaps; i++) {
- Heap *heap = &hs->heaps[i];
-
- dvmHeapBitmapDelete(&heap->objectBitmap);
- destroy_contiguous_mspace(heap->msp);
- }
- /* The last heap is the original one, which contains the
- * HeapSource object itself.
- */
+ *gcHeap = NULL;
}
}
/*
+ * Gets the begining of the allocation for the HeapSource.
+ */
+void *dvmHeapSourceGetBase(void)
+{
+ return gHs->heapBase;
+}
+
+/*
* Returns the requested value. If the per-heap stats are requested, fill
* them as well.
*
@@ -589,59 +682,115 @@
return total;
}
-/*
- * Writes shallow copies of the currently-used bitmaps into outBitmaps,
- * returning the number of bitmaps written. Returns 0 if the array was
- * not long enough or if there are no heaps, either of which is an error.
- */
-size_t
-dvmHeapSourceGetObjectBitmaps(HeapBitmap outBitmaps[], size_t maxBitmaps)
-{
- HeapSource *hs = gHs;
+static void aliasBitmap(HeapBitmap *dst, HeapBitmap *src,
+ uintptr_t base, uintptr_t max) {
+ size_t offset;
- HS_BOILERPLATE();
-
- assert(hs->numHeaps != 0);
- if (maxBitmaps >= hs->numHeaps) {
- size_t i;
-
- for (i = 0; i < hs->numHeaps; i++) {
- outBitmaps[i] = hs->heaps[i].objectBitmap;
- }
- return i;
- }
- return 0;
+ dst->base = base;
+ dst->max = max;
+ dst->bitsLen = HB_OFFSET_TO_BYTE_INDEX(max - base) + sizeof(dst->bits);
+ /* The exclusive limit from bitsLen is greater than the inclusive max. */
+ assert(base + HB_MAX_OFFSET(dst) > max);
+ /* The exclusive limit is at most one word of bits beyond max. */
+ assert((base + HB_MAX_OFFSET(dst)) - max <=
+ HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD);
+ dst->allocLen = dst->bitsLen;
+ offset = base - src->base;
+ assert(HB_OFFSET_TO_MASK(offset) == 1 << 31);
+ dst->bits = &src->bits[HB_OFFSET_TO_INDEX(offset)];
}
/*
- * Replaces the object location HeapBitmaps with the elements of
- * <objectBitmaps>. The elements of <objectBitmaps> are overwritten
- * with shallow copies of the old bitmaps.
- *
- * Returns false if the number of bitmaps doesn't match the number
- * of heaps.
+ * Initializes a vector of object and mark bits to the object and mark
+ * bits of each heap. The bits are aliased to the heapsource
+ * object and mark bitmaps. This routine is used by the sweep code
+ * which needs to free each object in the correct heap.
*/
-bool
-dvmHeapSourceReplaceObjectBitmaps(HeapBitmap objectBitmaps[], size_t nBitmaps)
+void dvmHeapSourceGetObjectBitmaps(HeapBitmap liveBits[], HeapBitmap markBits[],
+ size_t numHeaps)
{
HeapSource *hs = gHs;
+ uintptr_t base, max;
size_t i;
HS_BOILERPLATE();
- if (nBitmaps != hs->numHeaps) {
- return false;
+ assert(numHeaps == hs->numHeaps);
+ for (i = 0; i < hs->numHeaps; ++i) {
+ base = (uintptr_t)hs->heaps[i].base;
+ /* Using liveBits.max will include all the markBits as well. */
+ assert(hs->liveBits.max >= hs->markBits.max);
+ /* -1 because limit is exclusive but max is inclusive. */
+ max = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->liveBits.max);
+ aliasBitmap(&liveBits[i], &hs->liveBits, base, max);
+ aliasBitmap(&markBits[i], &hs->markBits, base, max);
}
+}
- for (i = 0; i < hs->numHeaps; i++) {
- Heap *heap = &hs->heaps[i];
- HeapBitmap swap;
+/*
+ * Get the bitmap representing all live objects.
+ */
+HeapBitmap *dvmHeapSourceGetLiveBits(void)
+{
+ HS_BOILERPLATE();
- swap = heap->objectBitmap;
- heap->objectBitmap = objectBitmaps[i];
- objectBitmaps[i] = swap;
+ return &gHs->liveBits;
+}
+
+void dvmHeapSourceSwapBitmaps(void)
+{
+ HeapBitmap tmp;
+
+ tmp = gHs->liveBits;
+ gHs->liveBits = gHs->markBits;
+ gHs->markBits = tmp;
+}
+
+void dvmHeapSourceZeroMarkBitmap(void)
+{
+ HS_BOILERPLATE();
+
+ dvmHeapBitmapZero(&gHs->markBits);
+}
+
+void dvmMarkImmuneObjects(const char *immuneLimit)
+{
+ char *dst, *src;
+ size_t i, index, length;
+
+ /*
+ * Copy the contents of the live bit vector for immune object
+ * range into the mark bit vector.
+ */
+ /* The only values generated by dvmHeapSourceGetImmuneLimit() */
+ assert(immuneLimit == gHs->heaps[0].base ||
+ immuneLimit == NULL);
+ assert(gHs->liveBits.base == gHs->markBits.base);
+ assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen);
+ /* heap[0] is never immune */
+ assert(gHs->heaps[0].base >= immuneLimit);
+ assert(gHs->heaps[0].limit > immuneLimit);
+
+ for (i = 1; i < gHs->numHeaps; ++i) {
+ if (gHs->heaps[i].base < immuneLimit) {
+ assert(gHs->heaps[i].limit <= immuneLimit);
+ /* Compute the number of words to copy in the bitmap. */
+ index = HB_OFFSET_TO_INDEX(
+ (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base);
+ /* Compute the starting offset in the live and mark bits. */
+ src = (char *)(gHs->liveBits.bits + index);
+ dst = (char *)(gHs->markBits.bits + index);
+ /* Compute the number of bytes of the live bitmap to copy. */
+ length = HB_OFFSET_TO_BYTE_INDEX(
+ gHs->heaps[i].limit - gHs->heaps[i].base);
+ /* Do the copy. */
+ memcpy(dst, src, length);
+ /* Make sure max points to the address of the highest set bit. */
+ if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) {
+ gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit;
+ }
+ }
}
- return true;
}
/*
@@ -653,25 +802,41 @@
HeapSource *hs = gHs;
Heap *heap;
void *ptr;
+ size_t allocated;
HS_BOILERPLATE();
heap = hs2heap(hs);
-
- if (heap->bytesAllocated + n <= hs->softLimit) {
-// TODO: allocate large blocks (>64k?) as separate mmap regions so that
-// they don't increase the high-water mark when they're freed.
-// TODO: zero out large objects using madvise
- ptr = mspace_calloc(heap->msp, 1, n);
- if (ptr != NULL) {
- countAllocation(heap, ptr, true);
- }
- } else {
- /* This allocation would push us over the soft limit;
- * act as if the heap is full.
+ if (heap->bytesAllocated + n > hs->softLimit) {
+ /*
+ * This allocation would push us over the soft limit; act as
+ * if the heap is full.
*/
LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation\n",
- FRACTIONAL_MB(hs->softLimit), n);
- ptr = NULL;
+ FRACTIONAL_MB(hs->softLimit), n);
+ return NULL;
+ }
+ ptr = mspace_calloc(heap->msp, 1, n);
+ if (ptr == NULL) {
+ return NULL;
+ }
+ countAllocation(heap, ptr, true);
+ /*
+ * Check to see if a concurrent GC should be initiated.
+ */
+ if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
+ /*
+ * The garbage collector thread is already running or has yet
+ * to be started. Do nothing.
+ */
+ return ptr;
+ }
+ allocated = heap->bytesAllocated - heap->prevBytesAllocated;
+ if (allocated > OCCUPANCY_THRESHOLD) {
+ /*
+ * We have exceeded the occupancy threshold. Wake up the
+ * garbage collector.
+ */
+ dvmSignalCond(&gHs->gcThreadCond);
}
return ptr;
}
@@ -861,18 +1026,26 @@
}
/*
+ * Returns true iff <ptr> is in the heap source.
+ */
+bool
+dvmHeapSourceContainsAddress(const void *ptr)
+{
+ HS_BOILERPLATE();
+
+ return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
+}
+
+/*
* Returns true iff <ptr> was allocated from the heap source.
*/
bool
dvmHeapSourceContains(const void *ptr)
{
- Heap *heap;
-
HS_BOILERPLATE();
- heap = ptr2heap(gHs, ptr);
- if (heap != NULL) {
- return dvmHeapBitmapIsObjectBitSet(&heap->objectBitmap, ptr) != 0;
+ if (dvmHeapSourceContainsAddress(ptr)) {
+ return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
}
return false;
}
@@ -1067,8 +1240,6 @@
static void
snapIdealFootprint()
{
- HeapSource *hs = gHs;
-
HS_BOILERPLATE();
setIdealFootprint(getSoftFootprint(true));
@@ -1094,7 +1265,6 @@
void dvmSetTargetHeapUtilization(float newTarget)
{
HeapSource *hs = gHs;
- size_t newUtilization;
HS_BOILERPLATE();
@@ -1109,7 +1279,7 @@
hs->targetUtilization =
(size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
- LOGV("Set heap target utilization to %zd/%d (%f)\n",
+ LOGV("Set heap target utilization to %zd/%d (%f)\n",
hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
}
@@ -1168,8 +1338,7 @@
* targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
*/
static size_t
-getUtilizationTarget(const HeapSource *hs,
- size_t liveSize, size_t targetUtilization)
+getUtilizationTarget(size_t liveSize, size_t targetUtilization)
{
size_t targetSize;
@@ -1232,7 +1401,7 @@
currentHeapUsed += hs->externalBytesAllocated;
#endif
targetHeapSize =
- getUtilizationTarget(hs, currentHeapUsed, hs->targetUtilization);
+ getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
#if LET_EXTERNAL_INFLUENCE_UTILIZATION
currentHeapUsed -= hs->externalBytesAllocated;
targetHeapSize -= hs->externalBytesAllocated;
@@ -1317,7 +1486,7 @@
/* Return any whole free pages to the system.
*/
bytesTrimmed[i] = 0;
- mspace_walk_free_pages(heap->msp, releasePagesInRange,
+ mspace_walk_free_pages(heap->msp, releasePagesInRange,
&bytesTrimmed[i]);
heapBytes += bytesTrimmed[i];
}
@@ -1418,18 +1587,12 @@
* Tries to update the internal count of externally-allocated memory.
* If there's enough room for that memory, returns true. If not, returns
* false and does not update the count.
- *
+ *
* The caller must ensure externalAllocPossible(hs, n) == true.
*/
static bool
externalAlloc(HeapSource *hs, size_t n, bool grow)
{
- Heap *heap;
- size_t currentHeapSize;
- size_t newTotal;
- size_t max;
- bool grew;
-
assert(hs->externalLimit >= hs->externalBytesAllocated);
HSTRACE("externalAlloc(%zd%s)\n", n, grow ? ", grow" : "");
@@ -1459,7 +1622,7 @@
/* GROW */
hs->externalBytesAllocated += n;
- hs->externalLimit = getUtilizationTarget(hs,
+ hs->externalLimit = getUtilizationTarget(
hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
HSTRACE("EXTERNAL grow limit to %zd\n", hs->externalLimit);
return true;
@@ -1491,7 +1654,6 @@
dvmTrackExternalAllocation(size_t n)
{
HeapSource *hs = gHs;
- size_t overhead;
bool ret = false;
/* gHs caches an entry in gDvm.gcHeap; we need to hold the
@@ -1517,6 +1679,18 @@
goto out;
}
+ if (gDvm.gcHeap->gcRunning) {
+ /*
+ * The GC is concurrently tracing the heap. Release the heap
+ * lock, wait for the GC to complete, and try again.
+ */
+ dvmWaitForConcurrentGcToComplete();
+ if (externalAlloc(hs, n, false)) {
+ ret = true;
+ goto out;
+ }
+ }
+
/* The "allocation" failed. Free up some space by doing
* a full garbage collection. This may grow the heap source
* if the live set is sufficiently large.
@@ -1533,7 +1707,6 @@
*/
HSTRACE("EXTERNAL alloc %zd: frag\n", n);
ret = externalAlloc(hs, n, true);
- dvmHeapSizeChanged();
if (ret) {
goto out;
}
@@ -1544,7 +1717,6 @@
HSTRACE("EXTERNAL alloc %zd: GC 2\n", n);
gcForExternalAlloc(true); // collect SoftReferences
ret = externalAlloc(hs, n, true);
- dvmHeapSizeChanged();
if (!ret) {
LOGE_HEAP("Out of external memory on a %zu-byte allocation.\n", n);
}
@@ -1574,7 +1746,6 @@
dvmTrackExternalFree(size_t n)
{
HeapSource *hs = gHs;
- size_t newIdealSize;
size_t newExternalLimit;
size_t oldExternalBytesAllocated;
@@ -1611,7 +1782,7 @@
/* Shrink as quickly as we can.
*/
- newExternalLimit = getUtilizationTarget(hs,
+ newExternalLimit = getUtilizationTarget(
hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
if (newExternalLimit < oldExternalBytesAllocated) {
/* Make sure that the remaining free space is at least
@@ -1652,3 +1823,12 @@
return ret;
}
+
+void *dvmHeapSourceGetImmuneLimit(GcMode mode)
+{
+ if (mode == GC_PARTIAL) {
+ return hs2heap(gHs)->base;
+ } else {
+ return NULL;
+ }
+}
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
index 3909123..46f5cc1 100644
--- a/vm/alloc/HeapSource.h
+++ b/vm/alloc/HeapSource.h
@@ -16,6 +16,7 @@
#ifndef _DALVIK_HEAP_SOURCE
#define _DALVIK_HEAP_SOURCE
+#include "alloc/Heap.h"
#include "alloc/HeapInternal.h" // for GcHeap
/* dlmalloc uses one size_t per allocated chunk.
@@ -25,7 +26,7 @@
/* The largest number of separate heaps we can handle.
*/
-#define HEAP_SOURCE_MAX_HEAP_COUNT 3
+#define HEAP_SOURCE_MAX_HEAP_COUNT 2
/*
* Initializes the heap source; must be called before any other
@@ -50,28 +51,32 @@
bool dvmHeapSourceStartupBeforeFork(void);
/*
+ * Shutdown any threads internal to the heap source. This should be
+ * called before the heap source itself is shutdown.
+ */
+void dvmHeapSourceThreadShutdown(void);
+
+/*
* Tears down the heap source and frees any resources associated with it.
*/
-void dvmHeapSourceShutdown(GcHeap *gcHeap);
+void dvmHeapSourceShutdown(GcHeap **gcHeap);
/*
- * Writes shallow copies of the currently-used bitmaps into outBitmaps,
- * returning the number of bitmaps written. Returns 0 if the array was
- * not long enough or if there are no heaps, either of which is an error.
+ * Initializes a vector of object and mark bits to the object and mark
+ * bits of each heap.
*/
-size_t dvmHeapSourceGetObjectBitmaps(HeapBitmap outBitmaps[],
- size_t maxBitmaps);
+void dvmHeapSourceGetObjectBitmaps(HeapBitmap objBits[], HeapBitmap markBits[],
+ size_t numHeaps);
/*
- * Replaces the object location HeapBitmaps with the elements of
- * <objectBitmaps>. The elements of <objectBitmaps> are overwritten
- * with shallow copies of the old bitmaps.
- *
- * Returns false if the number of bitmaps doesn't match the number
- * of heaps.
+ * Get the bitmap representing all live objects.
*/
-bool dvmHeapSourceReplaceObjectBitmaps(HeapBitmap objectBitmaps[],
- size_t nBitmaps);
+HeapBitmap *dvmHeapSourceGetLiveBits(void);
+
+/*
+ * Gets the begining of the allocation for the HeapSource.
+ */
+void *dvmHeapSourceGetBase(void);
/*
* Returns the requested value. If the per-heap stats are requested, fill
@@ -85,7 +90,7 @@
HS_EXTERNAL_BYTES_ALLOCATED,
HS_EXTERNAL_LIMIT
};
-size_t dvmHeapSourceGetValue(enum HeapSourceValueSpec spec,
+size_t dvmHeapSourceGetValue(enum HeapSourceValueSpec spec,
size_t perHeapStats[], size_t arrayLen);
/*
@@ -118,6 +123,11 @@
bool dvmHeapSourceContains(const void *ptr);
/*
+ * Returns true iff <ptr> is within the address space managed by heap source.
+ */
+bool dvmHeapSourceContainsAddress(const void *ptr);
+
+/*
* Returns the value of the requested flag.
*/
enum HeapSourcePtrFlag {
@@ -170,4 +180,28 @@
*/
size_t dvmHeapSourceGetNumHeaps(void);
+/*
+ * Exchanges the mark and object bitmaps.
+ */
+void dvmHeapSourceSwapBitmaps(void);
+
+/*
+ * Zeroes the mark bitmap.
+ */
+void dvmHeapSourceZeroMarkBitmap(void);
+
+/*
+ * Marks all objects inside the immune region of the heap. Addresses
+ * at or above this pointer are threatened, addresses below this
+ * pointer are immune.
+ */
+void dvmMarkImmuneObjects(const char *immuneLimit);
+
+/*
+ * Returns a pointer that demarcates the threatened region of the
+ * heap. Addresses at or above this pointer are threatened, addresses
+ * below this pointer are immune.
+ */
+void *dvmHeapSourceGetImmuneLimit(GcMode mode);
+
#endif // _DALVIK_HEAP_SOURCE
diff --git a/vm/alloc/HeapTable.c b/vm/alloc/HeapTable.c
index b56de64..e9f2729 100644
--- a/vm/alloc/HeapTable.c
+++ b/vm/alloc/HeapTable.c
@@ -20,17 +20,8 @@
#include <limits.h> // for INT_MAX
-static void *heapTableRealloc(void *oldPtr, size_t newSize)
-{
- /* Don't just call realloc(), in case the native system
- * doesn't malloc() on realloc(NULL).
- */
- if (oldPtr != NULL) {
- return realloc(oldPtr, newSize);
- } else {
- return malloc(newSize);
- }
-}
+static const int kLargeHeapRefTableNElems = 1024;
+static const int kFinalizableRefDefault = 128;
void dvmHeapHeapTableFree(void *ptr)
{
@@ -38,15 +29,12 @@
}
#define heapRefTableIsFull(refs) \
- ({ \
- const HeapRefTable *HRTIF_refs = (refs); \
- dvmIsReferenceTableFull(refs); \
- })
+ dvmIsReferenceTableFull(refs)
-bool dvmHeapInitHeapRefTable(HeapRefTable *refs, size_t nelems)
+bool dvmHeapInitHeapRefTable(HeapRefTable *refs)
{
memset(refs, 0, sizeof(*refs));
- return dvmInitReferenceTable(refs, nelems, INT_MAX);
+ return dvmInitReferenceTable(refs, kFinalizableRefDefault, INT_MAX);
}
/* Frees the array inside the HeapRefTable, not the HeapRefTable itself.
@@ -60,7 +48,6 @@
* Large, non-contiguous reference tables
*/
-#define kLargeHeapRefTableNElems 1024
bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref)
{
LargeHeapRefTable *table;
@@ -101,13 +88,14 @@
/* Allocate a new table.
*/
- table = (LargeHeapRefTable *)heapTableRealloc(NULL,
- sizeof(LargeHeapRefTable));
+ table = calloc(1, sizeof(LargeHeapRefTable));
if (table == NULL) {
LOGE_HEAP("Can't allocate a new large ref table\n");
return false;
}
- if (!dvmHeapInitHeapRefTable(&table->refs, kLargeHeapRefTableNElems)) {
+ if (!dvmInitReferenceTable(&table->refs,
+ kLargeHeapRefTableNElems,
+ INT_MAX)) {
LOGE_HEAP("Can't initialize a new large ref table\n");
dvmHeapHeapTableFree(table);
return false;
@@ -135,8 +123,7 @@
/* Allocate a node.
*/
- table = (LargeHeapRefTable *)heapTableRealloc(NULL,
- sizeof(LargeHeapRefTable));
+ table = calloc(1, sizeof(LargeHeapRefTable));
if (table == NULL) {
LOGE_HEAP("Can't allocate a new large ref table\n");
return false;
@@ -173,7 +160,6 @@
obj = NULL;
table = *pTable;
if (table != NULL) {
- GcHeap *gcHeap = gDvm.gcHeap;
HeapRefTable *refs = &table->refs;
/* We should never have an empty table node in the list.
@@ -197,30 +183,16 @@
return obj;
}
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table, bool stripLowBits)
+void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table)
{
while (table != NULL) {
Object **ref, **lastRef;
ref = table->refs.table;
lastRef = table->refs.nextEntry;
- if (stripLowBits) {
- /* This case is used for marking reference objects that
- * are still waiting for the heap worker thread to get to
- * them. The referents pointed to by the references are
- * marked when a SCHEDULED_REFERENCE_MAGIC is encountered
- * during scanning.
- */
- while (ref < lastRef) {
- dvmMarkObjectNonNull((Object *)((uintptr_t)*ref++ & ~3));
- }
- } else {
- while (ref < lastRef) {
- dvmMarkObjectNonNull(*ref++);
- }
+ while (ref < lastRef) {
+ dvmMarkObjectNonNull(*ref++);
}
table = table->next;
}
}
-
-
diff --git a/vm/alloc/HeapTable.h b/vm/alloc/HeapTable.h
index 784e8fd..55851b9 100644
--- a/vm/alloc/HeapTable.h
+++ b/vm/alloc/HeapTable.h
@@ -27,12 +27,12 @@
HeapRefTable refs;
};
-bool dvmHeapInitHeapRefTable(HeapRefTable *refs, size_t nelems);
+bool dvmHeapInitHeapRefTable(HeapRefTable *refs);
void dvmHeapFreeHeapRefTable(HeapRefTable *refs);
void dvmHeapFreeLargeTable(LargeHeapRefTable *table);
void dvmHeapHeapTableFree(void *ptr);
bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref);
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table, bool stripLowBits);
+void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table);
bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP,
HeapRefTable *refs);
Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable);
@@ -41,10 +41,7 @@
dvmAddToReferenceTable((refs), (ptr))
#define dvmHeapNumHeapRefTableEntries(refs) \
- ({ \
- const HeapRefTable *NHRTE_refs = (refs); \
- dvmReferenceTableEntries(refs); \
- })
+ dvmReferenceTableEntries(refs)
#define dvmHeapRemoveFromHeapRefTable(refs, ptr) \
dvmRemoveFromReferenceTable((refs), (refs)->table, (ptr))
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
index d743ce5..42b8942 100644
--- a/vm/alloc/HeapWorker.c
+++ b/vm/alloc/HeapWorker.c
@@ -76,8 +76,7 @@
* so this should not get stuck.
*/
while (!gDvm.heapWorkerReady) {
- int cc = pthread_cond_wait(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
- assert(cc == 0);
+ dvmWaitCond(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
}
dvmUnlockMutex(&gDvm.heapWorkerLock);
@@ -128,11 +127,6 @@
u8 now = dvmGetRelativeTimeUsec();
u8 delta = now - heapWorkerInterpStartTime;
- u8 heapWorkerInterpCpuStartTime =
- gDvm.gcHeap->heapWorkerInterpCpuStartTime;
- u8 nowCpu = dvmGetOtherThreadCpuTimeUsec(gDvm.heapWorkerHandle);
- u8 deltaCpu = nowCpu - heapWorkerInterpCpuStartTime;
-
if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT &&
(gDvm.debuggerActive || gDvm.nativeDebuggerActive))
{
@@ -197,6 +191,26 @@
}
}
+/*
+ * Acquires a mutex, transitioning to the VMWAIT state if the mutex is
+ * held. This allows the thread to suspend while it waits for another
+ * thread to release the mutex.
+ */
+static void lockMutex(pthread_mutex_t *mu)
+{
+ Thread *self;
+ ThreadStatus oldStatus;
+
+ assert(mu != NULL);
+ if (dvmTryLockMutex(mu) != 0) {
+ self = dvmThreadSelf();
+ assert(self != NULL);
+ oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ dvmLockMutex(mu);
+ dvmChangeStatus(self, oldStatus);
+ }
+}
+
static void callMethod(Thread *self, Object *obj, Method *method)
{
JValue unused;
@@ -229,7 +243,10 @@
} else {
dvmCallMethod(self, method, obj, &unused);
}
- dvmLockMutex(&gDvm.heapWorkerLock);
+ /*
+ * Reacquire the heap worker lock in a suspend-friendly way.
+ */
+ lockMutex(&gDvm.heapWorkerLock);
gDvm.gcHeap->heapWorkerCurrentObject = NULL;
gDvm.gcHeap->heapWorkerCurrentMethod = NULL;
@@ -281,11 +298,14 @@
assert(method->clazz != gDvm.classJavaLangObject);
callMethod(self, obj, method);
} else {
- if (op & WORKER_ENQUEUE) {
- numReferencesEnqueued++;
- callMethod(self, obj,
- gDvm.methJavaLangRefReference_enqueueInternal);
- }
+ assert(op == WORKER_ENQUEUE);
+ assert(dvmGetFieldObject(
+ obj, gDvm.offJavaLangRefReference_queue) != NULL);
+ assert(dvmGetFieldObject(
+ obj, gDvm.offJavaLangRefReference_queueNext) == NULL);
+ numReferencesEnqueued++;
+ callMethod(self, obj,
+ gDvm.methJavaLangRefReference_enqueueInternal);
}
/* Let the GC collect the object.
@@ -303,20 +323,18 @@
static void* heapWorkerThreadStart(void* arg)
{
Thread *self = dvmThreadSelf();
- int cc;
UNUSED_PARAMETER(arg);
LOGV("HeapWorker thread started (threadid=%d)\n", self->threadId);
/* tell the main thread that we're ready */
- dvmLockMutex(&gDvm.heapWorkerLock);
+ lockMutex(&gDvm.heapWorkerLock);
gDvm.heapWorkerReady = true;
- cc = pthread_cond_signal(&gDvm.heapWorkerCond);
- assert(cc == 0);
+ dvmSignalCond(&gDvm.heapWorkerCond);
dvmUnlockMutex(&gDvm.heapWorkerLock);
- dvmLockMutex(&gDvm.heapWorkerLock);
+ lockMutex(&gDvm.heapWorkerLock);
while (!gDvm.haltHeapWorker) {
struct timespec trimtime;
bool timedwait = false;
@@ -325,8 +343,7 @@
dvmChangeStatus(NULL, THREAD_VMWAIT);
/* Signal anyone who wants to know when we're done. */
- cc = pthread_cond_broadcast(&gDvm.heapWorkerIdleCond);
- assert(cc == 0);
+ dvmBroadcastCond(&gDvm.heapWorkerIdleCond);
/* Trim the heap if we were asked to. */
trimtime = gDvm.gcHeap->heapWorkerNextTrim;
@@ -343,19 +360,28 @@
#endif
if (trimtime.tv_sec < now.tv_sec ||
- (trimtime.tv_sec == now.tv_sec &&
+ (trimtime.tv_sec == now.tv_sec &&
trimtime.tv_nsec <= now.tv_nsec))
{
size_t madvisedSizes[HEAP_SOURCE_MAX_HEAP_COUNT];
- /* The heap must be locked before the HeapWorker;
- * unroll and re-order the locks. dvmLockHeap()
- * will put us in VMWAIT if necessary. Once it
- * returns, there shouldn't be any contention on
- * heapWorkerLock.
+ /*
+ * Acquire the gcHeapLock. The requires releasing the
+ * heapWorkerLock before the gcHeapLock is acquired.
+ * It is possible that the gcHeapLock may be acquired
+ * during a concurrent GC in which case heapWorkerLock
+ * is held by the GC and we are unable to make forward
+ * progress. We avoid deadlock by releasing the
+ * gcHeapLock and then waiting to be signaled when the
+ * GC completes. There is no guarantee that the next
+ * time we are run will coincide with GC inactivity so
+ * the check and wait must be performed within a loop.
*/
dvmUnlockMutex(&gDvm.heapWorkerLock);
dvmLockHeap();
+ while (gDvm.gcHeap->gcRunning) {
+ dvmWaitForConcurrentGcToComplete();
+ }
dvmLockMutex(&gDvm.heapWorkerLock);
memset(madvisedSizes, 0, sizeof(madvisedSizes));
@@ -374,6 +400,7 @@
/* sleep until signaled */
if (timedwait) {
+ int cc __attribute__ ((__unused__));
#ifdef HAVE_TIMEDWAIT_MONOTONIC
cc = pthread_cond_timedwait_monotonic(&gDvm.heapWorkerCond,
&gDvm.heapWorkerLock, &trimtime);
@@ -381,17 +408,28 @@
cc = pthread_cond_timedwait(&gDvm.heapWorkerCond,
&gDvm.heapWorkerLock, &trimtime);
#endif
- assert(cc == 0 || cc == ETIMEDOUT || cc == EINTR);
+ assert(cc == 0 || cc == ETIMEDOUT);
} else {
- cc = pthread_cond_wait(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
- assert(cc == 0);
+ dvmWaitCond(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
}
- /* dvmChangeStatus() may block; don't hold heapWorkerLock.
+ /*
+ * Return to the running state before doing heap work. This
+ * will block if the GC has initiated a suspend. We release
+ * the heapWorkerLock beforehand for the GC to make progress
+ * and wait to be signaled after the GC completes. There is
+ * no guarantee that the next time we are run will coincide
+ * with GC inactivity so the check and wait must be performed
+ * within a loop.
*/
dvmUnlockMutex(&gDvm.heapWorkerLock);
dvmChangeStatus(NULL, THREAD_RUNNING);
+ dvmLockHeap();
+ while (gDvm.gcHeap->gcRunning) {
+ dvmWaitForConcurrentGcToComplete();
+ }
dvmLockMutex(&gDvm.heapWorkerLock);
+ dvmUnlockHeap();
LOGV("HeapWorker is awake\n");
/* Process any events in the queue.
@@ -410,14 +448,11 @@
*/
void dvmSignalHeapWorker(bool shouldLock)
{
- int cc;
-
if (shouldLock) {
dvmLockMutex(&gDvm.heapWorkerLock);
}
- cc = pthread_cond_signal(&gDvm.heapWorkerCond);
- assert(cc == 0);
+ dvmSignalCond(&gDvm.heapWorkerCond);
if (shouldLock) {
dvmUnlockMutex(&gDvm.heapWorkerLock);
@@ -429,8 +464,6 @@
*/
void dvmWaitForHeapWorkerIdle()
{
- int cc;
-
assert(gDvm.heapWorkerReady);
dvmChangeStatus(NULL, THREAD_VMWAIT);
@@ -443,8 +476,7 @@
// need to detect when this is called from the HeapWorker
// context and just give up.
dvmSignalHeapWorker(false);
- cc = pthread_cond_wait(&gDvm.heapWorkerIdleCond, &gDvm.heapWorkerLock);
- assert(cc == 0);
+ dvmWaitCond(&gDvm.heapWorkerIdleCond, &gDvm.heapWorkerLock);
dvmUnlockMutex(&gDvm.heapWorkerLock);
@@ -495,12 +527,11 @@
* context switch.
*/
} else {
- struct timeval now;
-
#ifdef HAVE_TIMEDWAIT_MONOTONIC
clock_gettime(CLOCK_MONOTONIC, &timeout);
timeout.tv_sec += timeoutSec;
#else
+ struct timeval now;
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec + timeoutSec;
timeout.tv_nsec = now.tv_usec * 1000;
diff --git a/vm/alloc/HeapWorker.h b/vm/alloc/HeapWorker.h
index 2734aef..45587ff 100644
--- a/vm/alloc/HeapWorker.h
+++ b/vm/alloc/HeapWorker.h
@@ -76,11 +76,7 @@
*/
typedef enum HeapWorkerOperation {
WORKER_FINALIZE = 0,
-
- /* Required: WORKER_ENQUEUE <= (4-1)
- * This value will be stuffed in the low bits of a pointer.
- */
- WORKER_ENQUEUE = (1<<0),
+ WORKER_ENQUEUE = 1,
} HeapWorkerOperation;
/*
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 78286cf..d35f3dc 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -20,24 +20,11 @@
#include "alloc/HeapInternal.h"
#include "alloc/HeapSource.h"
#include "alloc/MarkSweep.h"
+#include "alloc/Visit.h"
#include <limits.h> // for ULONG_MAX
#include <sys/mman.h> // for madvise(), mmap()
-#include <cutils/ashmem.h>
#include <errno.h>
-#define GC_DEBUG_PARANOID 2
-#define GC_DEBUG_BASIC 1
-#define GC_DEBUG_OFF 0
-#define GC_DEBUG(l) (GC_DEBUG_LEVEL >= (l))
-
-#if 1
-#define GC_DEBUG_LEVEL GC_DEBUG_PARANOID
-#else
-#define GC_DEBUG_LEVEL GC_DEBUG_OFF
-#endif
-
-#define VERBOSE_GC 0
-
#define GC_LOG_TAG LOG_TAG "-gc"
#if LOG_NDEBUG
@@ -48,25 +35,11 @@
#define LOGD_GC(...) LOG(LOG_DEBUG, GC_LOG_TAG, __VA_ARGS__)
#endif
-#if VERBOSE_GC
-#define LOGVV_GC(...) LOGV_GC(__VA_ARGS__)
-#else
-#define LOGVV_GC(...) ((void)0)
-#endif
-
#define LOGI_GC(...) LOG(LOG_INFO, GC_LOG_TAG, __VA_ARGS__)
#define LOGW_GC(...) LOG(LOG_WARN, GC_LOG_TAG, __VA_ARGS__)
#define LOGE_GC(...) LOG(LOG_ERROR, GC_LOG_TAG, __VA_ARGS__)
#define LOG_SCAN(...) LOGV_GC("SCAN: " __VA_ARGS__)
-#define LOG_MARK(...) LOGV_GC("MARK: " __VA_ARGS__)
-#define LOG_SWEEP(...) LOGV_GC("SWEEP: " __VA_ARGS__)
-#define LOG_REF(...) LOGV_GC("REF: " __VA_ARGS__)
-
-#define LOGV_SCAN(...) LOGVV_GC("SCAN: " __VA_ARGS__)
-#define LOGV_MARK(...) LOGVV_GC("MARK: " __VA_ARGS__)
-#define LOGV_SWEEP(...) LOGVV_GC("SWEEP: " __VA_ARGS__)
-#define LOGV_REF(...) LOGVV_GC("REF: " __VA_ARGS__)
#define ALIGN_UP_TO_PAGE_SIZE(p) \
(((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
@@ -74,19 +47,17 @@
/* Do not cast the result of this to a boolean; the only set bit
* may be > 1<<8.
*/
-static inline long isMarked(const DvmHeapChunk *hc, const GcMarkContext *ctx)
- __attribute__((always_inline));
-static inline long isMarked(const DvmHeapChunk *hc, const GcMarkContext *ctx)
+static inline long isMarked(const void *obj, const GcMarkContext *ctx)
{
- return dvmHeapBitmapIsObjectBitSetInList(ctx->bitmaps, ctx->numBitmaps, hc);
+ return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
}
static bool
createMarkStack(GcMarkStack *stack)
{
const Object **limit;
+ const char *name;
size_t size;
- int fd, err;
/* Create a stack big enough for the worst possible case,
* where the heap is perfectly full of the smallest object.
@@ -96,27 +67,15 @@
size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
(sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
size = ALIGN_UP_TO_PAGE_SIZE(size);
- fd = ashmem_create_region("dalvik-heap-markstack", size);
- if (fd < 0) {
- LOGE_GC("Could not create %d-byte ashmem mark stack: %s\n",
- size, strerror(errno));
+ name = "dalvik-mark-stack";
+ limit = dvmAllocRegion(size, PROT_READ | PROT_WRITE, name);
+ if (limit == NULL) {
+ LOGE_GC("Could not mmap %zd-byte ashmem region '%s'", size, name);
return false;
}
- limit = (const Object **)mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE, fd, 0);
- err = errno;
- close(fd);
- if (limit == MAP_FAILED) {
- LOGE_GC("Could not mmap %d-byte ashmem mark stack: %s\n",
- size, strerror(err));
- return false;
- }
-
- memset(stack, 0, sizeof(*stack));
stack->limit = limit;
stack->base = (const Object **)((uintptr_t)limit + size);
stack->top = stack->base;
-
return true;
}
@@ -134,68 +93,39 @@
} while (false)
bool
-dvmHeapBeginMarkStep()
+dvmHeapBeginMarkStep(GcMode mode)
{
GcMarkContext *mc = &gDvm.gcHeap->markContext;
- HeapBitmap objectBitmaps[HEAP_SOURCE_MAX_HEAP_COUNT];
- size_t numBitmaps;
if (!createMarkStack(&mc->stack)) {
return false;
}
-
- numBitmaps = dvmHeapSourceGetObjectBitmaps(objectBitmaps,
- HEAP_SOURCE_MAX_HEAP_COUNT);
- if (numBitmaps == 0) {
- return false;
- }
-
- /* Create mark bitmaps that cover the same ranges as the
- * current object bitmaps.
- */
- if (!dvmHeapBitmapInitListFromTemplates(mc->bitmaps, objectBitmaps,
- numBitmaps, "mark"))
- {
- return false;
- }
-
- mc->numBitmaps = numBitmaps;
mc->finger = NULL;
-
+ mc->immuneLimit = dvmHeapSourceGetImmuneLimit(mode);
return true;
}
-static long setAndReturnMarkBit(GcMarkContext *ctx, const DvmHeapChunk *hc)
- __attribute__((always_inline));
static long
-setAndReturnMarkBit(GcMarkContext *ctx, const DvmHeapChunk *hc)
+setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
{
- return dvmHeapBitmapSetAndReturnObjectBitInList(ctx->bitmaps,
- ctx->numBitmaps, hc);
+ return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
}
-static void _markObjectNonNullCommon(const Object *obj, GcMarkContext *ctx,
- bool checkFinger, bool forceStack)
- __attribute__((always_inline));
static void
-_markObjectNonNullCommon(const Object *obj, GcMarkContext *ctx,
- bool checkFinger, bool forceStack)
+markObjectNonNull(const Object *obj, GcMarkContext *ctx, bool checkFinger)
{
- DvmHeapChunk *hc;
-
+ assert(ctx != NULL);
assert(obj != NULL);
-
-#if GC_DEBUG(GC_DEBUG_PARANOID)
-//TODO: make sure we're locked
- assert(obj != (Object *)gDvm.unlinkedJavaLangClass);
assert(dvmIsValidObject(obj));
-#endif
- hc = ptr2chunk(obj);
- if (!setAndReturnMarkBit(ctx, hc)) {
+ if (obj < (Object *)ctx->immuneLimit) {
+ assert(isMarked(obj, ctx));
+ return;
+ }
+ if (!setAndReturnMarkBit(ctx, obj)) {
/* This object was not previously marked.
*/
- if (forceStack || (checkFinger && (void *)hc < ctx->finger)) {
+ if (checkFinger && (void *)obj < ctx->finger) {
/* This object will need to go on the mark stack.
*/
MARK_STACK_PUSH(ctx->stack, obj);
@@ -206,17 +136,6 @@
hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
}
#endif
-#if DVM_TRACK_HEAP_MARKING
- gDvm.gcHeap->markCount++;
- gDvm.gcHeap->markSize += dvmHeapSourceChunkSize((void *)hc) +
- HEAP_SOURCE_CHUNK_OVERHEAD;
-#endif
-
- /* obj->clazz can be NULL if we catch an object between
- * dvmMalloc() and DVM_OBJECT_INIT(). This is ok.
- */
- LOGV_MARK("0x%08x %s\n", (uint)obj,
- obj->clazz == NULL ? "<null class>" : obj->clazz->name);
}
}
@@ -226,20 +145,13 @@
* the finger won't be visited by the bitmap scan, so those objects
* need to be added to the mark stack.
*/
-static void
-markObjectNonNull(const Object *obj, GcMarkContext *ctx)
+static void markObject(const Object *obj, GcMarkContext *ctx)
{
- _markObjectNonNullCommon(obj, ctx, true, false);
+ if (obj != NULL) {
+ markObjectNonNull(obj, ctx, true);
+ }
}
-#define markObject(obj, ctx) \
- do { \
- Object *MO_obj_ = (Object *)(obj); \
- if (MO_obj_ != NULL) { \
- markObjectNonNull(MO_obj_, (ctx)); \
- } \
- } while (false)
-
/* If the object hasn't already been marked, mark it and
* schedule it to be scanned for references.
*
@@ -247,12 +159,13 @@
* be used in situations where a reference may be NULL.
*
* This function may only be called when marking the root
- * set. When recursing, use the internal markObject[NonNull]().
+ * set. When recursing, use the internal markObject().
*/
void
dvmMarkObjectNonNull(const Object *obj)
{
- _markObjectNonNullCommon(obj, &gDvm.gcHeap->markContext, false, false);
+ assert(obj != NULL);
+ markObjectNonNull(obj, &gDvm.gcHeap->markContext, false);
}
/* Mark the set of root objects.
@@ -283,14 +196,13 @@
*/
void dvmHeapMarkRootSet()
{
- HeapRefTable *refs;
- GcHeap *gcHeap;
- Object **op;
-
- gcHeap = gDvm.gcHeap;
+ GcHeap *gcHeap = gDvm.gcHeap;
HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_STICKY_CLASS, 0);
+ LOG_SCAN("immune objects");
+ dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
+
LOG_SCAN("root class loader\n");
dvmGcScanRootClassLoader();
LOG_SCAN("primitive classes\n");
@@ -317,12 +229,12 @@
HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
LOG_SCAN("pending reference operations\n");
- dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations, true);
+ dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
LOG_SCAN("pending finalizations\n");
- dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs, false);
+ dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
@@ -331,346 +243,294 @@
HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_VM_INTERNAL, 0);
- /* Mark all ALLOC_NO_GC objects.
- */
- LOG_SCAN("ALLOC_NO_GC objects\n");
- refs = &gcHeap->nonCollectableRefs;
- op = refs->table;
- while ((uintptr_t)op < (uintptr_t)refs->nextEntry) {
- dvmMarkObjectNonNull(*(op++));
- }
-
/* Mark any special objects we have sitting around.
*/
LOG_SCAN("special objects\n");
dvmMarkObjectNonNull(gDvm.outOfMemoryObj);
dvmMarkObjectNonNull(gDvm.internalErrorObj);
dvmMarkObjectNonNull(gDvm.noClassDefFoundErrorObj);
- dvmMarkObject(gDvm.jniWeakGlobalRefQueue);
//TODO: scan object references sitting in gDvm; use pointer begin & end
HPROF_CLEAR_GC_SCAN_STATE();
}
/*
- * Nothing past this point is allowed to use dvmMarkObject*().
- * Scanning/recursion must use markObject*(), which takes the
- * finger into account.
+ * Callback applied to root references. If the root location contains
+ * a white reference it is pushed on the mark stack and grayed.
*/
+static void markObjectVisitor(void *addr, void *arg)
+{
+ Object *obj;
+
+ assert(addr != NULL);
+ assert(arg != NULL);
+ obj = *(Object **)addr;
+ if (obj != NULL) {
+ markObjectNonNull(obj, arg, true);
+ }
+}
+
+/*
+ * Grays all references in the roots.
+ */
+void dvmHeapReMarkRootSet(void)
+{
+ GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+ assert(ctx->finger == (void *)ULONG_MAX);
+ dvmVisitRoots(markObjectVisitor, ctx);
+}
+
+/*
+ * Nothing past this point is allowed to use dvmMarkObject() or
+ * dvmMarkObjectNonNull(), which are for root-marking only.
+ * Scanning/recursion must use markObject(), which takes the finger
+ * into account.
+ */
+#undef dvmMarkObject
+#define dvmMarkObject __dont_use_dvmMarkObject__
#define dvmMarkObjectNonNull __dont_use_dvmMarkObjectNonNull__
-
-/* Mark all of a ClassObject's interfaces.
+/*
+ * Scans instance fields.
*/
-static void markInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
+static void scanInstanceFields(const Object *obj, GcMarkContext *ctx)
{
- ClassObject **interfaces;
- int interfaceCount;
- int i;
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ assert(ctx != NULL);
- /* Mark all interfaces.
- */
- interfaces = clazz->interfaces;
- interfaceCount = clazz->interfaceCount;
- for (i = 0; i < interfaceCount; i++) {
- markObjectNonNull((Object *)*interfaces, ctx);
- interfaces++;
- }
-}
-
-/* Mark all objects referred to by a ClassObject's static fields.
- */
-static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
-{
- StaticField *f;
- int i;
-
- //TODO: Optimize this with a bit vector or something
- f = clazz->sfields;
- for (i = 0; i < clazz->sfieldCount; i++) {
- char c = f->field.signature[0];
- if (c == '[' || c == 'L') {
- /* It's an array or class reference.
- */
- markObject((Object *)f->value.l, ctx);
- }
- f++;
- }
-}
-
-/* Mark all objects referred to by a DataObject's instance fields.
- */
-static void scanInstanceFields(const DataObject *obj, ClassObject *clazz,
- GcMarkContext *ctx)
-{
- if (clazz->refOffsets != CLASS_WALK_SUPER) {
- unsigned int refOffsets = clazz->refOffsets;
+ if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
+ unsigned int refOffsets = obj->clazz->refOffsets;
while (refOffsets != 0) {
const int rshift = CLZ(refOffsets);
refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
markObject(dvmGetFieldObject((Object*)obj,
- CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
+ CLASS_OFFSET_FROM_CLZ(rshift)), ctx);
}
} else {
- while (clazz != NULL) {
- InstField *f;
- int i;
-
- /* All of the fields that contain object references
- * are guaranteed to be at the beginning of the ifields list.
- */
- f = clazz->ifields;
- for (i = 0; i < clazz->ifieldRefCount; i++) {
- /* Mark the array or object reference.
- * May be NULL.
- *
- * Note that, per the comment on struct InstField,
- * f->byteOffset is the offset from the beginning of
- * obj, not the offset into obj->instanceData.
- */
- markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx);
- f++;
+ ClassObject *clazz;
+ int i;
+ for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
+ InstField *field = clazz->ifields;
+ for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
+ void *addr = BYTE_OFFSET((Object *)obj, field->byteOffset);
+ markObject(((JValue *)addr)->l, ctx);
}
-
- /* This will be NULL when we hit java.lang.Object
- */
- clazz = clazz->super;
}
}
}
-/* Mark all objects referred to by the array's contents.
+/*
+ * Scans the header, static field references, and interface
+ * pointers of a class object.
*/
-static void scanObjectArray(const ArrayObject *array, GcMarkContext *ctx)
+static void scanClassObject(const ClassObject *obj, GcMarkContext *ctx)
{
- Object **contents;
- u4 length;
- u4 i;
+ int i;
- contents = (Object **)array->contents;
- length = array->length;
+ assert(obj != NULL);
+ assert(obj->obj.clazz == gDvm.classJavaLangClass);
+ assert(ctx != NULL);
- for (i = 0; i < length; i++) {
- markObject(*contents, ctx); // may be NULL
- contents++;
+ markObject((Object *)obj->obj.clazz, ctx);
+ if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
+ markObject((Object *)obj->elementClass, ctx);
+ }
+ /* Do super and the interfaces contain Objects and not dex idx values? */
+ if (obj->status > CLASS_IDX) {
+ markObject((Object *)obj->super, ctx);
+ }
+ markObject(obj->classLoader, ctx);
+ /* Scan static field references. */
+ for (i = 0; i < obj->sfieldCount; ++i) {
+ char ch = obj->sfields[i].field.signature[0];
+ if (ch == '[' || ch == 'L') {
+ markObject(obj->sfields[i].value.l, ctx);
+ }
+ }
+ /* Scan the instance fields. */
+ scanInstanceFields((const Object *)obj, ctx);
+ /* Scan interface references. */
+ if (obj->status > CLASS_IDX) {
+ for (i = 0; i < obj->interfaceCount; ++i) {
+ markObject((Object *)obj->interfaces[i], ctx);
+ }
}
}
-/* Mark all objects referred to by the ClassObject.
+/*
+ * Scans the header of all array objects. If the array object is
+ * specialized to a reference type, scans the array data as well.
*/
-static void scanClassObject(const ClassObject *clazz, GcMarkContext *ctx)
+static void scanArrayObject(const ArrayObject *obj, GcMarkContext *ctx)
{
- LOGV_SCAN("---------> %s\n", clazz->name);
+ size_t i;
- if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
- /* We're an array; mark the class object of the contents
- * of the array.
- *
- * Note that we won't necessarily reach the array's element
- * class by scanning the array contents; the array may be
- * zero-length, or may only contain null objects.
- */
- markObjectNonNull((Object *)clazz->elementClass, ctx);
+ assert(obj != NULL);
+ assert(obj->obj.clazz != NULL);
+ assert(ctx != NULL);
+ /* Scan the class object reference. */
+ markObject((Object *)obj->obj.clazz, ctx);
+ if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISOBJECTARRAY)) {
+ /* Scan the array contents. */
+ Object **contents = (Object **)obj->contents;
+ for (i = 0; i < obj->length; ++i) {
+ markObject(contents[i], ctx);
+ }
}
-
- /* We scan these explicitly in case the only remaining
- * reference to a particular class object is via a data
- * object; we may not be guaranteed to reach all
- * live class objects via a classloader.
- */
- markObject((Object *)clazz->super, ctx); // may be NULL (java.lang.Object)
- markObject(clazz->classLoader, ctx); // may be NULL
-
- scanStaticFields(clazz, ctx);
- markInterfaces(clazz, ctx);
}
-/* Mark all objects that obj refers to.
- *
- * Called on every object in markList.
+/*
+ * Returns class flags relating to Reference subclasses.
+ */
+static int referenceClassFlags(const Object *obj)
+{
+ int flags = CLASS_ISREFERENCE |
+ CLASS_ISWEAKREFERENCE |
+ CLASS_ISPHANTOMREFERENCE;
+ return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
+}
+
+/*
+ * Returns true if the object derives from SoftReference.
+ */
+static bool isSoftReference(const Object *obj)
+{
+ return referenceClassFlags(obj) == CLASS_ISREFERENCE;
+}
+
+/*
+ * Returns true if the object derives from WeakReference.
+ */
+static bool isWeakReference(const Object *obj)
+{
+ return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
+}
+
+/*
+ * Returns true if the object derives from PhantomReference.
+ */
+static bool isPhantomReference(const Object *obj)
+{
+ return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
+}
+
+/*
+ * Adds a reference to the tail of a circular queue of references.
+ */
+static void enqueuePendingReference(Object *ref, Object **list)
+{
+ size_t offset;
+
+ assert(ref != NULL);
+ assert(list != NULL);
+ offset = gDvm.offJavaLangRefReference_pendingNext;
+ if (*list == NULL) {
+ dvmSetFieldObject(ref, offset, ref);
+ *list = ref;
+ } else {
+ Object *head = dvmGetFieldObject(*list, offset);
+ dvmSetFieldObject(ref, offset, head);
+ dvmSetFieldObject(*list, offset, ref);
+ }
+}
+
+/*
+ * Removes the reference at the head of a circular queue of
+ * references.
+ */
+static Object *dequeuePendingReference(Object **list)
+{
+ Object *ref, *head;
+ size_t offset;
+
+ assert(list != NULL);
+ assert(*list != NULL);
+ offset = gDvm.offJavaLangRefReference_pendingNext;
+ head = dvmGetFieldObject(*list, offset);
+ if (*list == head) {
+ ref = *list;
+ *list = NULL;
+ } else {
+ Object *next = dvmGetFieldObject(head, offset);
+ dvmSetFieldObject(*list, offset, next);
+ ref = head;
+ }
+ dvmSetFieldObject(ref, offset, NULL);
+ return ref;
+}
+
+/*
+ * Process the "referent" field in a java.lang.ref.Reference. If the
+ * referent has not yet been marked, put it on the appropriate list in
+ * the gcHeap for later processing.
+ */
+static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
+{
+ GcHeap *gcHeap = gDvm.gcHeap;
+ Object *pending, *referent;
+ size_t pendingNextOffset, referentOffset;
+
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
+ assert(ctx != NULL);
+ pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
+ referentOffset = gDvm.offJavaLangRefReference_referent;
+ pending = dvmGetFieldObject(obj, pendingNextOffset);
+ referent = dvmGetFieldObject(obj, referentOffset);
+ if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
+ Object **list = NULL;
+ if (isSoftReference(obj)) {
+ list = &gcHeap->softReferences;
+ } else if (isWeakReference(obj)) {
+ list = &gcHeap->weakReferences;
+ } else if (isPhantomReference(obj)) {
+ list = &gcHeap->phantomReferences;
+ }
+ assert(list != NULL);
+ enqueuePendingReference(obj, list);
+ }
+}
+
+/*
+ * Scans the header and field references of a data object.
+ */
+static void scanDataObject(DataObject *obj, GcMarkContext *ctx)
+{
+ assert(obj != NULL);
+ assert(obj->obj.clazz != NULL);
+ assert(ctx != NULL);
+ /* Scan the class object. */
+ markObject((Object *)obj->obj.clazz, ctx);
+ /* Scan the instance fields. */
+ scanInstanceFields((const Object *)obj, ctx);
+ if (IS_CLASS_FLAG_SET(obj->obj.clazz, CLASS_ISREFERENCE)) {
+ delayReferenceReferent((Object *)obj, ctx);
+ }
+}
+
+/*
+ * Scans an object reference. Determines the type of the reference
+ * and dispatches to a specialized scanning routine.
*/
static void scanObject(const Object *obj, GcMarkContext *ctx)
{
- ClassObject *clazz;
-
- assert(dvmIsValidObject(obj));
- LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->name);
-
+ assert(obj != NULL);
+ assert(ctx != NULL);
+ assert(obj->clazz != NULL);
#if WITH_HPROF
if (gDvm.gcHeap->hprofContext != NULL) {
hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
}
#endif
-
- /* Get and mark the class object for this particular instance.
- */
- clazz = obj->clazz;
- if (clazz == NULL) {
- /* This can happen if we catch an object between
- * dvmMalloc() and DVM_OBJECT_INIT(). The object
- * won't contain any references yet, so we can
- * just skip it.
- */
- return;
- } else if (clazz == gDvm.unlinkedJavaLangClass) {
- /* This class hasn't been linked yet. We're guaranteed
- * that the object doesn't contain any references that
- * aren't already tracked, so we can skip scanning it.
- *
- * NOTE: unlinkedJavaLangClass is not on the heap, so
- * it's very important that we don't try marking it.
- */
- return;
- }
-
- assert(dvmIsValidObject((Object *)clazz));
- markObjectNonNull((Object *)clazz, ctx);
-
- /* Mark any references in this object.
- */
- if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
- /* It's an array object.
- */
- if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
- /* It's an array of object references.
- */
- scanObjectArray((ArrayObject *)obj, ctx);
- }
- // else there's nothing else to scan
+ /* Dispatch a type-specific scan routine. */
+ if (obj->clazz == gDvm.classJavaLangClass) {
+ scanClassObject((ClassObject *)obj, ctx);
+ } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+ scanArrayObject((ArrayObject *)obj, ctx);
} else {
- /* It's a DataObject-compatible object.
- */
- scanInstanceFields((DataObject *)obj, clazz, ctx);
-
- if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
- GcHeap *gcHeap = gDvm.gcHeap;
- Object *referent;
-
- /* It's a subclass of java/lang/ref/Reference.
- * The fields in this class have been arranged
- * such that scanInstanceFields() did not actually
- * mark the "referent" field; we need to handle
- * it specially.
- *
- * If the referent already has a strong mark (isMarked(referent)),
- * we don't care about its reference status.
- */
- referent = dvmGetFieldObject(obj,
- gDvm.offJavaLangRefReference_referent);
- if (referent != NULL &&
- !isMarked(ptr2chunk(referent), &gcHeap->markContext))
- {
- u4 refFlags;
-
- if (gcHeap->markAllReferents) {
- LOG_REF("Hard-marking a reference\n");
-
- /* Don't bother with normal reference-following
- * behavior, just mark the referent. This should
- * only be used when following objects that just
- * became scheduled for finalization.
- */
- markObjectNonNull(referent, ctx);
- goto skip_reference;
- }
-
- /* See if this reference was handled by a previous GC.
- */
- if (dvmGetFieldObject(obj,
- gDvm.offJavaLangRefReference_vmData) ==
- SCHEDULED_REFERENCE_MAGIC)
- {
- LOG_REF("Skipping scheduled reference\n");
-
- /* Don't reschedule it, but make sure that its
- * referent doesn't get collected (in case it's
- * a PhantomReference and wasn't cleared automatically).
- */
- //TODO: Mark these after handling all new refs of
- // this strength, in case the new refs refer
- // to the same referent. Not a very common
- // case, though.
- markObjectNonNull(referent, ctx);
- goto skip_reference;
- }
-
- /* Find out what kind of reference is pointing
- * to referent.
- */
- refFlags = GET_CLASS_FLAG_GROUP(clazz,
- CLASS_ISREFERENCE |
- CLASS_ISWEAKREFERENCE |
- CLASS_ISPHANTOMREFERENCE);
-
- /* We use the vmData field of Reference objects
- * as a next pointer in a singly-linked list.
- * That way, we don't need to allocate any memory
- * while we're doing a GC.
- */
-#define ADD_REF_TO_LIST(list, ref) \
- do { \
- Object *ARTL_ref_ = (/*de-const*/Object *)(ref); \
- dvmSetFieldObject(ARTL_ref_, \
- gDvm.offJavaLangRefReference_vmData, list); \
- list = ARTL_ref_; \
- } while (false)
-
- /* At this stage, we just keep track of all of
- * the live references that we've seen. Later,
- * we'll walk through each of these lists and
- * deal with the referents.
- */
- if (refFlags == CLASS_ISREFERENCE) {
- /* It's a soft reference. Depending on the state,
- * we'll attempt to collect all of them, some of
- * them, or none of them.
- */
- if (gcHeap->softReferenceCollectionState ==
- SR_COLLECT_NONE)
- {
- sr_collect_none:
- markObjectNonNull(referent, ctx);
- } else if (gcHeap->softReferenceCollectionState ==
- SR_COLLECT_ALL)
- {
- sr_collect_all:
- ADD_REF_TO_LIST(gcHeap->softReferences, obj);
- } else {
- /* We'll only try to collect half of the
- * referents.
- */
- if (gcHeap->softReferenceColor++ & 1) {
- goto sr_collect_none;
- }
- goto sr_collect_all;
- }
- } else {
- /* It's a weak or phantom reference.
- * Clearing CLASS_ISREFERENCE will reveal which.
- */
- refFlags &= ~CLASS_ISREFERENCE;
- if (refFlags == CLASS_ISWEAKREFERENCE) {
- ADD_REF_TO_LIST(gcHeap->weakReferences, obj);
- } else if (refFlags == CLASS_ISPHANTOMREFERENCE) {
- ADD_REF_TO_LIST(gcHeap->phantomReferences, obj);
- } else {
- assert(!"Unknown reference type");
- }
- }
-#undef ADD_REF_TO_LIST
- }
- }
-
- skip_reference:
- /* If this is a class object, mark various other things that
- * its internals point to.
- *
- * All class objects are instances of java.lang.Class,
- * including the java.lang.Class class object.
- */
- if (clazz == gDvm.classJavaLangClass) {
- scanClassObject((ClassObject *)obj, ctx);
- }
+ scanDataObject((DataObject *)obj, ctx);
}
}
@@ -689,14 +549,115 @@
}
}
+static size_t objectSize(const Object *obj)
+{
+ assert(dvmIsValidObject(obj));
+ assert(dvmIsValidObject((Object *)obj->clazz));
+ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+ return dvmArrayObjectSize((ArrayObject *)obj);
+ } else if (obj->clazz == gDvm.classJavaLangClass) {
+ return dvmClassObjectSize((ClassObject *)obj);
+ } else {
+ return obj->clazz->objectSize;
+ }
+}
+
+/*
+ * Scans backward to the header of a marked object that spans the
+ * given address. Returns NULL if there is no spanning marked object.
+ */
+static Object *previousGrayObject(u1 *start, GcMarkContext *ctx)
+{
+ u1 *end = (u1 *)ctx->bitmap->base;
+ u1 *ptr;
+
+ assert(start >= end);
+ for (ptr = start; ptr >= end; ptr -= HB_OBJECT_ALIGNMENT) {
+ if (dvmIsValidObject((Object *)ptr))
+ break;
+ }
+ if (ptr < end || !isMarked(ptr, ctx)) {
+ return NULL;
+ } else {
+ Object *obj = (Object *)ptr;
+ size_t size = objectSize(obj);
+ if (ptr + size < start) {
+ return NULL;
+ }
+ return obj;
+ }
+}
+
+/*
+ * Scans forward to the header of the next marked object between start
+ * and limit. Returns NULL if no marked objects are in that region.
+ */
+static Object *nextGrayObject(u1 *base, u1 *limit, GcMarkContext *ctx)
+{
+ u1 *ptr;
+
+ assert(base < limit);
+ assert(limit - base <= GC_CARD_SIZE);
+ for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
+ if (isMarked(ptr, ctx))
+ return (Object *)ptr;
+ }
+ return NULL;
+}
+
+/*
+ * Scan the card table looking for objects that have been grayed by
+ * the mutator.
+ */
+static void scanGrayObjects(GcMarkContext *ctx)
+{
+ GcHeap *h = gDvm.gcHeap;
+ u1 *card, *baseCard, *limitCard;
+
+ baseCard = &h->cardTableBase[0];
+ limitCard = &h->cardTableBase[h->cardTableLength];
+ for (card = baseCard; card != limitCard; ++card) {
+ if (*card == GC_CARD_DIRTY) {
+ /*
+ * The card is dirty. Scan all of the objects that
+ * intersect with the card address.
+ */
+ u1 *addr = dvmAddrFromCard(card);
+ /*
+ * If the last object on the previous card terminates on
+ * the current card it is gray and must be scanned.
+ */
+ if (!dvmIsValidObject((Object *)addr)) {
+ Object *prev = previousGrayObject(addr, ctx);
+ if (prev != NULL) {
+ scanObject(prev, ctx);
+ }
+ }
+ /*
+ * Scan through all black objects that start on the
+ * current card.
+ */
+ u1 *limit = addr + GC_CARD_SIZE;
+ u1 *next = addr;
+ while (next < limit) {
+ Object *obj = nextGrayObject(next, limit, ctx);
+ if (obj == NULL)
+ break;
+ scanObject(obj, ctx);
+ next = (u1*)obj + HB_OBJECT_ALIGNMENT;
+ }
+ }
+ }
+}
+
#ifndef NDEBUG
static uintptr_t gLastFinger = 0;
#endif
-static bool
-scanBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
+static void scanBitmapCallback(size_t numPtrs, void **ptrs,
+ const void *finger, void *arg)
{
- GcMarkContext *ctx = (GcMarkContext *)arg;
+ GcMarkContext *ctx = arg;
size_t i;
#ifndef NDEBUG
@@ -706,20 +667,15 @@
ctx->finger = finger;
for (i = 0; i < numPtrs; i++) {
- /* The pointers we're getting back are DvmHeapChunks,
- * not Objects.
- */
- scanObject(chunk2ptr(*ptrs++), ctx);
+ scanObject(*ptrs++, ctx);
}
-
- return true;
}
/* Given bitmaps with the root set marked, find and mark all
* reachable objects. When this returns, the entire set of
* live objects will be marked and the mark stack will be empty.
*/
-void dvmHeapScanMarkedObjects()
+void dvmHeapScanMarkedObjects(void)
{
GcMarkContext *ctx = &gDvm.gcHeap->markContext;
@@ -731,8 +687,7 @@
#ifndef NDEBUG
gLastFinger = 0;
#endif
- dvmHeapBitmapWalkList(ctx->bitmaps, ctx->numBitmaps,
- scanBitmapCallback, ctx);
+ dvmHeapBitmapWalk(ctx->bitmap, scanBitmapCallback, ctx);
/* We've walked the mark bitmaps. Scan anything that's
* left on the mark stack.
@@ -742,202 +697,136 @@
LOG_SCAN("done with marked objects\n");
}
-/** Clear the referent field.
+void dvmHeapReScanMarkedObjects(void)
+{
+ GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+
+ /*
+ * The finger must have been set to the maximum value to ensure
+ * that gray objects will be pushed onto the mark stack.
+ */
+ assert(ctx->finger == (void *)ULONG_MAX);
+ scanGrayObjects(ctx);
+ processMarkStack(ctx);
+}
+
+/*
+ * Clear the referent field.
*/
static void clearReference(Object *reference)
{
- /* This is what the default implementation of Reference.clear()
- * does. We're required to clear all references to a given
- * referent atomically, so we can't pop in and out of interp
- * code each time.
- *
- * We don't ever actaully call overriding implementations of
- * Reference.clear().
- */
- dvmSetFieldObject(reference,
- gDvm.offJavaLangRefReference_referent, NULL);
+ size_t offset = gDvm.offJavaLangRefReference_referent;
+ dvmSetFieldObject(reference, offset, NULL);
}
-/** @return true if we need to schedule a call to enqueue().
+/*
+ * Returns true if the reference was registered with a reference queue
+ * and has not yet been enqueued.
*/
-static bool enqueueReference(Object *reference)
+static bool isEnqueuable(const Object *reference)
{
Object *queue = dvmGetFieldObject(reference,
gDvm.offJavaLangRefReference_queue);
Object *queueNext = dvmGetFieldObject(reference,
gDvm.offJavaLangRefReference_queueNext);
- if (queue == NULL || queueNext != NULL) {
- /* There is no queue, or the reference has already
- * been enqueued. The Reference.enqueue() method
- * will do nothing even if we call it.
- */
- return false;
- }
-
- /* We need to call enqueue(), but if we called it from
- * here we'd probably deadlock. Schedule a call.
- */
- return true;
+ return queue != NULL && queueNext == NULL;
}
-/* All objects for stronger reference levels have been
- * marked before this is called.
+/*
+ * Schedules a reference to be appended to its reference queue.
*/
-void dvmHeapHandleReferences(Object *refListHead, enum RefType refType)
+static void enqueueReference(Object *ref)
{
- Object *reference;
- GcMarkContext *markContext = &gDvm.gcHeap->markContext;
- const int offVmData = gDvm.offJavaLangRefReference_vmData;
- const int offReferent = gDvm.offJavaLangRefReference_referent;
- bool workRequired = false;
-
- reference = refListHead;
- while (reference != NULL) {
- Object *next;
- Object *referent;
-
- /* Pull the interesting fields out of the Reference object.
- */
- next = dvmGetFieldObject(reference, offVmData);
- referent = dvmGetFieldObject(reference, offReferent);
-
- //TODO: when handling REF_PHANTOM, unlink any references
- // that fail this initial if(). We need to re-walk
- // the list, and it would be nice to avoid the extra
- // work.
- if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) {
- bool schedEnqueue;
-
- /* This is the strongest reference that refers to referent.
- * Do the right thing.
- */
- switch (refType) {
- case REF_SOFT:
- case REF_WEAK:
- clearReference(reference);
- schedEnqueue = enqueueReference(reference);
- break;
- case REF_PHANTOM:
- /* PhantomReferences are not cleared automatically.
- * Until someone clears it (or the reference itself
- * is collected), the referent must remain alive.
- *
- * It's necessary to fully mark the referent because
- * it will still be present during the next GC, and
- * all objects that it points to must be valid.
- * (The referent will be marked outside of this loop,
- * after handing all references of this strength, in
- * case multiple references point to the same object.)
- *
- * One exception: JNI "weak global" references are handled
- * as a special case. They're identified by the queue.
- */
- if (gDvm.jniWeakGlobalRefQueue != NULL) {
- Object* queue = dvmGetFieldObject(reference,
- gDvm.offJavaLangRefReference_queue);
- if (queue == gDvm.jniWeakGlobalRefQueue) {
- LOGV("+++ WGR: clearing + not queueing %p:%p\n",
- reference, referent);
- clearReference(reference);
- schedEnqueue = false;
- break;
- }
- }
-
- /* A PhantomReference is only useful with a
- * queue, but since it's possible to create one
- * without a queue, we need to check.
- */
- schedEnqueue = enqueueReference(reference);
- break;
- default:
- assert(!"Bad reference type");
- schedEnqueue = false;
- break;
- }
-
- if (schedEnqueue) {
- uintptr_t workBits;
-
- /* Stuff the enqueue bit in the bottom of the pointer.
- * Assumes that objects are 8-byte aligned.
- *
- * Note that we are adding the *Reference* (which
- * is by definition already marked at this point) to
- * this list; we're not adding the referent (which
- * has already been cleared).
- */
- assert(((intptr_t)reference & 3) == 0);
- assert((WORKER_ENQUEUE & ~3) == 0);
- if (!dvmHeapAddRefToLargeTable(
- &gDvm.gcHeap->referenceOperations,
- (Object *)((uintptr_t)reference | WORKER_ENQUEUE)))
- {
- LOGE_HEAP("dvmMalloc(): no room for any more "
- "reference operations\n");
- dvmAbort();
- }
- workRequired = true;
- }
-
- if (refType != REF_PHANTOM) {
- /* Let later GCs know not to reschedule this reference.
- */
- dvmSetFieldObject(reference, offVmData,
- SCHEDULED_REFERENCE_MAGIC);
- } // else this is handled later for REF_PHANTOM
-
- } // else there was a stronger reference to the referent.
-
- reference = next;
+ assert(ref != NULL);
+ assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
+ assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
+ if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
+ LOGE_HEAP("enqueueReference(): no room for any more "
+ "reference operations\n");
+ dvmAbort();
}
+}
- /* Walk though the reference list again, and mark any non-clear/marked
- * referents. Only PhantomReferences can have non-clear referents
- * at this point.
- *
- * (Could skip this for JNI weak globals, since we know they've been
- * cleared.)
+/*
+ * Walks the reference list marking any references subject to the
+ * reference clearing policy. References with a black referent are
+ * removed from the list. References with white referents biased
+ * toward saving are blackened and also removed from the list.
+ */
+void dvmHandleSoftRefs(Object **list)
+{
+ GcMarkContext *markContext;
+ Object *ref, *referent;
+ Object *clear;
+ size_t referentOffset;
+ size_t counter;
+ bool marked;
+
+ markContext = &gDvm.gcHeap->markContext;
+ referentOffset = gDvm.offJavaLangRefReference_referent;
+ clear = NULL;
+ counter = 0;
+ while (*list != NULL) {
+ ref = dequeuePendingReference(list);
+ referent = dvmGetFieldObject(ref, referentOffset);
+ assert(referent != NULL);
+ marked = isMarked(referent, markContext);
+ if (!marked && ((++counter) & 1)) {
+ /* Referent is white and biased toward saving, mark it. */
+ markObject(referent, markContext);
+ marked = true;
+ }
+ if (!marked) {
+ /* Referent is white, queue it for clearing. */
+ enqueuePendingReference(ref, &clear);
+ }
+ }
+ *list = clear;
+ /*
+ * Restart the mark with the newly black references added to the
+ * root set.
*/
- if (refType == REF_PHANTOM) {
- bool scanRequired = false;
+ processMarkStack(markContext);
+}
- HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
- reference = refListHead;
- while (reference != NULL) {
- Object *next;
- Object *referent;
+/*
+ * Unlink the reference list clearing references objects with white
+ * referents. Cleared references registered to a reference queue are
+ * scheduled for appending by the heap worker thread.
+ */
+void dvmClearWhiteRefs(Object **list)
+{
+ GcMarkContext *markContext;
+ Object *ref, *referent;
+ size_t referentOffset;
+ bool doSignal;
- /* Pull the interesting fields out of the Reference object.
- */
- next = dvmGetFieldObject(reference, offVmData);
- referent = dvmGetFieldObject(reference, offReferent);
-
- if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) {
- markObjectNonNull(referent, markContext);
- scanRequired = true;
-
- /* Let later GCs know not to reschedule this reference.
- */
- dvmSetFieldObject(reference, offVmData,
- SCHEDULED_REFERENCE_MAGIC);
+ markContext = &gDvm.gcHeap->markContext;
+ referentOffset = gDvm.offJavaLangRefReference_referent;
+ doSignal = false;
+ while (*list != NULL) {
+ ref = dequeuePendingReference(list);
+ referent = dvmGetFieldObject(ref, referentOffset);
+ assert(referent != NULL);
+ if (!isMarked(referent, markContext)) {
+ /* Referent is white, clear it. */
+ clearReference(ref);
+ if (isEnqueuable(ref)) {
+ enqueueReference(ref);
+ doSignal = true;
}
-
- reference = next;
- }
- HPROF_CLEAR_GC_SCAN_STATE();
-
- if (scanRequired) {
- processMarkStack(markContext);
}
}
-
- if (workRequired) {
+ /*
+ * If we cleared a reference with a reference queue we must notify
+ * the heap worker to append the reference.
+ */
+ if (doSignal) {
dvmSignalHeapWorker(false);
}
+ assert(*list == NULL);
}
-
/* Find unreachable objects that need to be finalized,
* and schedule them for finalization.
*/
@@ -958,7 +847,7 @@
/* Create a table that the new pending refs will
* be added to.
*/
- if (!dvmHeapInitHeapRefTable(&newPendingRefs, 128)) {
+ if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
//TODO: mark all finalizable refs and hope that
// we can schedule them next time. Watch out,
// because we may be expecting to free up space
@@ -979,10 +868,7 @@
gapRef = ref = finRefs->refs.table;
lastRef = finRefs->refs.nextEntry;
while (ref < lastRef) {
- DvmHeapChunk *hc;
-
- hc = ptr2chunk(*ref);
- if (!isMarked(hc, markContext)) {
+ if (!isMarked(*ref, markContext)) {
if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
//TODO: add the current table and allocate
// a new, smaller one.
@@ -1042,27 +928,17 @@
assert(ref < lastRef);
HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
while (ref < lastRef) {
- markObjectNonNull(*ref, markContext);
+ assert(*ref != NULL);
+ markObject(*ref, markContext);
ref++;
}
HPROF_CLEAR_GC_SCAN_STATE();
-
- /* Set markAllReferents so that we don't collect referents whose
- * only references are in final-reachable objects.
- * TODO: eventually provide normal reference behavior by properly
- * marking these references.
- */
- gDvm.gcHeap->markAllReferents = true;
processMarkStack(markContext);
- gDvm.gcHeap->markAllReferents = false;
-
dvmSignalHeapWorker(false);
}
void dvmHeapFinishMarkStep()
{
- HeapBitmap *markBitmap;
- HeapBitmap objectBitmap;
GcMarkContext *markContext;
markContext = &gDvm.gcHeap->markContext;
@@ -1071,88 +947,30 @@
* HeapSource bitmaps that didn't appear in the mark bitmaps.
* The new state of the HeapSource is exactly the final
* mark bitmaps, so swap them in.
- *
- * The old bitmaps will be swapped into the context so that
- * we can clean them up.
*/
- dvmHeapSourceReplaceObjectBitmaps(markContext->bitmaps,
- markContext->numBitmaps);
+ dvmHeapSourceSwapBitmaps();
- /* Clean up the old HeapSource bitmaps and anything else associated
- * with the marking process.
+ /* The mark bits are now not needed.
*/
- dvmHeapBitmapDeleteList(markContext->bitmaps, markContext->numBitmaps);
+ dvmHeapSourceZeroMarkBitmap();
+
+ /* Clean up everything else associated with the marking process.
+ */
destroyMarkStack(&markContext->stack);
- memset(markContext, 0, sizeof(*markContext));
+ markContext->finger = NULL;
}
-#if WITH_HPROF && WITH_HPROF_UNREACHABLE
-static bool
-hprofUnreachableBitmapCallback(size_t numPtrs, void **ptrs,
- const void *finger, void *arg)
-{
- hprof_context_t *hctx = (hprof_context_t *)arg;
- size_t i;
-
- for (i = 0; i < numPtrs; i++) {
- Object *obj;
-
- /* The pointers we're getting back are DvmHeapChunks, not
- * Objects.
- */
- obj = (Object *)chunk2ptr(*ptrs++);
-
- hprofMarkRootObject(hctx, obj, 0);
- hprofDumpHeapObject(hctx, obj);
- }
-
- return true;
-}
-
-static void
-hprofDumpUnmarkedObjects(const HeapBitmap markBitmaps[],
- const HeapBitmap objectBitmaps[], size_t numBitmaps)
-{
- hprof_context_t *hctx = gDvm.gcHeap->hprofContext;
- if (hctx == NULL) {
- return;
- }
-
- LOGI("hprof: dumping unreachable objects\n");
-
- HPROF_SET_GC_SCAN_STATE(HPROF_UNREACHABLE, 0);
-
- dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
- hprofUnreachableBitmapCallback, hctx);
-
- HPROF_CLEAR_GC_SCAN_STATE();
-}
-#endif
-
-static bool
-sweepBitmapCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
+static void sweepBitmapCallback(size_t numPtrs, void **ptrs,
+ const void *finger, void *arg)
{
const ClassObject *const classJavaLangClass = gDvm.classJavaLangClass;
size_t i;
- void **origPtrs = ptrs;
for (i = 0; i < numPtrs; i++) {
- DvmHeapChunk *hc;
Object *obj;
- /* The pointers we're getting back are DvmHeapChunks, not
- * Objects.
- */
- hc = (DvmHeapChunk *)*ptrs++;
- obj = (Object *)chunk2ptr(hc);
-
- /* NOTE: Dereferencing clazz is dangerous. If obj was the last
- * one to reference its class object, the class object could be
- * on the sweep list, and could already have been swept, leaving
- * us with a stale pointer.
- */
- LOGV_SWEEP("FREE: 0x%08x %s\n", (uint)obj, obj->clazz->name);
+ obj = (Object *)ptrs[i];
/* This assumes that java.lang.Class will never go away.
* If it can, and we were the last reference to it, it
@@ -1161,31 +979,15 @@
* value.
*/
if (obj->clazz == classJavaLangClass) {
- LOGV_SWEEP("---------------> %s\n", ((ClassObject *)obj)->name);
/* dvmFreeClassInnards() may have already been called,
* but it's safe to call on the same ClassObject twice.
*/
dvmFreeClassInnards((ClassObject *)obj);
}
-
-#if 0
- /* Overwrite the to-be-freed object to make stale references
- * more obvious.
- */
- {
- int chunklen;
- ClassObject *clazz = obj->clazz;
- chunklen = dvmHeapSourceChunkSize(hc);
- memset(hc, 0xa5, chunklen);
- obj->clazz = (ClassObject *)((uintptr_t)clazz ^ 0xffffffff);
- }
-#endif
}
// TODO: dvmHeapSourceFreeList has a loop, just like the above
// does. Consider collapsing the two loops to save overhead.
- dvmHeapSourceFreeList(numPtrs, origPtrs);
-
- return true;
+ dvmHeapSourceFreeList(numPtrs, ptrs);
}
/* Returns true if the given object is unmarked. Ignores the low bits
@@ -1193,7 +995,7 @@
*/
static int isUnmarkedObject(void *object)
{
- return !isMarked(ptr2chunk((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
+ return !isMarked((void *)((uintptr_t)object & ~(HB_OBJECT_ALIGNMENT-1)),
&gDvm.gcHeap->markContext);
}
@@ -1201,14 +1003,14 @@
* marked and free them.
*/
void
-dvmHeapSweepUnmarkedObjects(int *numFreed, size_t *sizeFreed)
+dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
{
- const HeapBitmap *markBitmaps;
- const GcMarkContext *markContext;
- HeapBitmap objectBitmaps[HEAP_SOURCE_MAX_HEAP_COUNT];
+ HeapBitmap markBits[HEAP_SOURCE_MAX_HEAP_COUNT];
+ HeapBitmap liveBits[HEAP_SOURCE_MAX_HEAP_COUNT];
size_t origObjectsAllocated;
size_t origBytesAllocated;
- size_t numBitmaps;
+ size_t numBitmaps, numSweepBitmaps;
+ size_t i;
/* All reachable objects have been marked.
* Detach any unreachable interned strings before
@@ -1221,26 +1023,20 @@
origObjectsAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
origBytesAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
- markContext = &gDvm.gcHeap->markContext;
- markBitmaps = markContext->bitmaps;
- numBitmaps = dvmHeapSourceGetObjectBitmaps(objectBitmaps,
- HEAP_SOURCE_MAX_HEAP_COUNT);
-#ifndef NDEBUG
- if (numBitmaps != markContext->numBitmaps) {
- LOGE("heap bitmap count mismatch: %zd != %zd\n",
- numBitmaps, markContext->numBitmaps);
- dvmAbort();
- }
-#endif
-
-#if WITH_HPROF && WITH_HPROF_UNREACHABLE
- hprofDumpUnmarkedObjects(markBitmaps, objectBitmaps, numBitmaps);
-#endif
-
dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
- dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
- sweepBitmapCallback, NULL);
+ numBitmaps = dvmHeapSourceGetNumHeaps();
+ dvmHeapSourceGetObjectBitmaps(liveBits, markBits, numBitmaps);
+ if (mode == GC_PARTIAL) {
+ numSweepBitmaps = 1;
+ assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == liveBits[0].base);
+ } else {
+ numSweepBitmaps = numBitmaps;
+ }
+ for (i = 0; i < numSweepBitmaps; i++) {
+ dvmHeapBitmapSweepWalk(&liveBits[i], &markBits[i],
+ sweepBitmapCallback, NULL);
+ }
*numFreed = origObjectsAllocated -
dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0);
diff --git a/vm/alloc/MarkSweep.h b/vm/alloc/MarkSweep.h
index b087b40..0fc5933 100644
--- a/vm/alloc/MarkSweep.h
+++ b/vm/alloc/MarkSweep.h
@@ -38,26 +38,22 @@
/* This is declared publicly so that it can be included in gDvm.gcHeap.
*/
typedef struct {
- HeapBitmap bitmaps[HEAP_SOURCE_MAX_HEAP_COUNT];
- size_t numBitmaps;
+ HeapBitmap *bitmap;
GcMarkStack stack;
+ const char *immuneLimit;
const void *finger; // only used while scanning/recursing.
} GcMarkContext;
-enum RefType {
- REF_SOFT,
- REF_WEAK,
- REF_PHANTOM,
- REF_WEAKGLOBAL
-};
-
-bool dvmHeapBeginMarkStep(void);
+bool dvmHeapBeginMarkStep(GcMode mode);
void dvmHeapMarkRootSet(void);
+void dvmHeapReMarkRootSet(void);
void dvmHeapScanMarkedObjects(void);
-void dvmHeapHandleReferences(Object *refListHead, enum RefType refType);
+void dvmHeapReScanMarkedObjects(void);
+void dvmHandleSoftRefs(Object **list);
+void dvmClearWhiteRefs(Object **list);
void dvmHeapScheduleFinalizations(void);
void dvmHeapFinishMarkStep(void);
-void dvmHeapSweepUnmarkedObjects(int *numFreed, size_t *sizeFreed);
+void dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed);
#endif // _DALVIK_ALLOC_MARK_SWEEP
diff --git a/vm/alloc/Verify.c b/vm/alloc/Verify.c
new file mode 100644
index 0000000..47d28d8
--- /dev/null
+++ b/vm/alloc/Verify.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/Verify.h"
+#include "alloc/Visit.h"
+
+/*
+ * Checks that the given reference points to a valid object.
+ */
+static void verifyReference(void *addr, void *arg)
+{
+ const Object *obj;
+ bool isValid;
+
+ assert(addr != NULL);
+ obj = *(const Object **)addr;
+ if (obj == NULL) {
+ isValid = true;
+ } else {
+ isValid = dvmIsValidObject(obj);
+ }
+ if (!isValid) {
+ LOGE("Verify of object %p @ %p failed", obj, addr);
+ dvmAbort();
+ }
+}
+
+static void visitorCallback(void *addr, void *arg)
+{
+ verifyReference(addr, arg);
+}
+
+/*
+ * Verifies an object reference.
+ */
+void dvmVerifyObject(const Object *obj)
+{
+ dvmVisitObject(visitorCallback, (Object *)obj, NULL);
+}
+
+/*
+ * Helper function to call dvmVerifyObject from a bitmap walker.
+ */
+static void verifyBitmapCallback(size_t numPtrs, void **ptrs,
+ const void *finger, void *arg)
+{
+ size_t i;
+
+ for (i = 0; i < numPtrs; i++) {
+ dvmVerifyObject(ptrs[i]);
+ }
+}
+
+/*
+ * Verifies the object references in a heap bitmap. Assumes the VM is
+ * suspended.
+ */
+void dvmVerifyBitmap(const HeapBitmap *bitmap)
+{
+ /* TODO: check that locks are held and the VM is suspended. */
+ dvmHeapBitmapWalk(bitmap, verifyBitmapCallback, NULL);
+}
+
+/*
+ * Verifies references in the roots.
+ */
+void dvmVerifyRoots(void)
+{
+ dvmVisitRoots(verifyReference, NULL);
+}
diff --git a/vm/alloc/Verify.h b/vm/alloc/Verify.h
new file mode 100644
index 0000000..56d8958
--- /dev/null
+++ b/vm/alloc/Verify.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DALVIK_ALLOC_VERIFY
+#define _DALVIK_ALLOC_VERIFY
+
+/*
+ * Verifies an object reference.
+ */
+void dvmVerifyObject(const Object *obj);
+
+/*
+ * Verifies the object references in a heap bitmap. Assumes the VM is
+ * suspended.
+ */
+void dvmVerifyBitmap(const HeapBitmap *bitmap);
+
+/*
+ * Verifies the contents of various global roots.
+ */
+void dvmVerifyRoots(void);
+
+#endif /* _DALVIK_ALLOC_VERIFY */
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c
new file mode 100644
index 0000000..9a799f2
--- /dev/null
+++ b/vm/alloc/Visit.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "alloc/clz.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/Visit.h"
+#include "alloc/VisitInlines.h"
+
+/*
+ * Visits all of the reference locations in an object.
+ */
+void dvmVisitObject(Visitor *visitor, Object *obj, void *arg)
+{
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ visitObject(visitor, obj, arg);
+}
+
+/*
+ * Applies a verification function to all present values in the hash table.
+ */
+static void visitHashTable(Visitor *visitor, HashTable *table, void *arg)
+{
+ int i;
+
+ assert(visitor != NULL);
+ assert(table != NULL);
+ dvmHashTableLock(table);
+ for (i = 0; i < table->tableSize; ++i) {
+ HashEntry *entry = &table->pEntries[i];
+ if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
+ (*visitor)(&entry->data, arg);
+ }
+ }
+ dvmHashTableUnlock(table);
+}
+
+/*
+ * Visits all entries in the reference table.
+ */
+static void visitReferenceTable(Visitor *visitor, const ReferenceTable *table,
+ void *arg)
+{
+ Object **entry;
+
+ assert(visitor != NULL);
+ assert(table != NULL);
+ for (entry = table->table; entry < table->nextEntry; ++entry) {
+ assert(entry != NULL);
+ (*visitor)(entry, arg);
+ }
+}
+
+/*
+ * Visits a large heap reference table. These objects are list heads.
+ * As such, it is valid for table to be NULL.
+ */
+static void visitLargeHeapRefTable(Visitor *visitor, LargeHeapRefTable *table,
+ void *arg)
+{
+ assert(visitor != NULL);
+ for (; table != NULL; table = table->next) {
+ visitReferenceTable(visitor, &table->refs, arg);
+ }
+}
+
+/*
+ * Visits all stack slots. TODO: visit native methods.
+ */
+static void visitThreadStack(Visitor *visitor, Thread *thread, void *arg)
+{
+ const StackSaveArea *saveArea;
+ u4 *framePtr;
+
+ assert(visitor != NULL);
+ assert(thread != NULL);
+ framePtr = (u4 *)thread->curFrame;
+ for (; framePtr != NULL; framePtr = saveArea->prevFrame) {
+ Method *method;
+ saveArea = SAVEAREA_FROM_FP(framePtr);
+ method = (Method *)saveArea->method;
+ if (method != NULL && !dvmIsNativeMethod(method)) {
+ const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
+ const u1* regVector = NULL;
+ size_t i;
+
+ if (pMap != NULL) {
+ /* found map, get registers for this address */
+ int addr = saveArea->xtra.currentPc - method->insns;
+ regVector = dvmRegisterMapGetLine(pMap, addr);
+ }
+ if (regVector == NULL) {
+ /*
+ * Either there was no register map or there is no
+ * info for the current PC. Perform a conservative
+ * scan.
+ */
+ for (i = 0; i < method->registersSize; ++i) {
+ if (dvmIsValidObject((Object *)framePtr[i])) {
+ (*visitor)(&framePtr[i], arg);
+ }
+ }
+ } else {
+ /*
+ * Precise scan. v0 is at the lowest address on the
+ * interpreted stack, and is the first bit in the
+ * register vector, so we can walk through the
+ * register map and memory in the same direction.
+ *
+ * A '1' bit indicates a live reference.
+ */
+ u2 bits = 1 << 1;
+ for (i = 0; i < method->registersSize; ++i) {
+ bits >>= 1;
+ if (bits == 1) {
+ /* set bit 9 so we can tell when we're empty */
+ bits = *regVector++ | 0x0100;
+ }
+ if ((bits & 0x1) != 0) {
+ /*
+ * Register is marked as live, it's a valid root.
+ */
+ (*visitor)(&framePtr[i], arg);
+ }
+ }
+ dvmReleaseRegisterMapLine(pMap, regVector);
+ }
+ }
+ /*
+ * Don't fall into an infinite loop if things get corrupted.
+ */
+ assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
+ saveArea->prevFrame == NULL);
+ }
+}
+
+/*
+ * Visits all roots associated with a thread.
+ */
+static void visitThread(Visitor *visitor, Thread *thread, void *arg)
+{
+ assert(visitor != NULL);
+ assert(thread != NULL);
+ assert(thread->status != THREAD_RUNNING ||
+ thread->isSuspended ||
+ thread == dvmThreadSelf());
+ (*visitor)(&thread->threadObj, arg);
+ (*visitor)(&thread->exception, arg);
+ visitReferenceTable(visitor, &thread->internalLocalRefTable, arg);
+ visitReferenceTable(visitor, &thread->jniLocalRefTable, arg);
+ if (thread->jniMonitorRefTable.table) {
+ visitReferenceTable(visitor, &thread->jniMonitorRefTable, arg);
+ }
+ visitThreadStack(visitor, thread, arg);
+}
+
+/*
+ * Visits all threads on the thread list.
+ */
+static void visitThreads(Visitor *visitor, void *arg)
+{
+ Thread *thread;
+
+ assert(visitor != NULL);
+ dvmLockThreadList(dvmThreadSelf());
+ thread = gDvm.threadList;
+ while (thread) {
+ visitThread(visitor, thread, arg);
+ thread = thread->next;
+ }
+ dvmUnlockThreadList();
+}
+
+/*
+ * Visits roots. TODO: visit all roots.
+ */
+void dvmVisitRoots(Visitor *visitor, void *arg)
+{
+ assert(visitor != NULL);
+ visitHashTable(visitor, gDvm.loadedClasses, arg);
+ visitHashTable(visitor, gDvm.dbgRegistry, arg);
+ visitHashTable(visitor, gDvm.internedStrings, arg);
+ visitHashTable(visitor, gDvm.literalStrings, arg);
+ visitReferenceTable(visitor, &gDvm.jniGlobalRefTable, arg);
+ visitReferenceTable(visitor, &gDvm.jniPinRefTable, arg);
+ visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, arg);
+ visitLargeHeapRefTable(visitor, gDvm.gcHeap->pendingFinalizationRefs, arg);
+ visitThreads(visitor, arg);
+ (*visitor)(&gDvm.outOfMemoryObj, arg);
+ (*visitor)(&gDvm.internalErrorObj, arg);
+ (*visitor)(&gDvm.noClassDefFoundErrorObj, arg);
+ /* TODO: visit cached global references. */
+}
diff --git a/vm/alloc/Visit.h b/vm/alloc/Visit.h
new file mode 100644
index 0000000..488c721
--- /dev/null
+++ b/vm/alloc/Visit.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DALVIK_ALLOC_VISIT
+#define _DALVIK_ALLOC_VISIT
+
+#include "Dalvik.h"
+
+/*
+ * Callback invoked with the address of a reference and a user
+ * supplied context argument.
+ */
+typedef void Visitor(void *addr, void *arg);
+
+/*
+ * Visits references in an object.
+ */
+void dvmVisitObject(Visitor *visitor, Object *obj, void *arg);
+
+/*
+ * Visits references in the root set.
+ */
+void dvmVisitRoots(Visitor *visitor, void *arg);
+
+#endif /* _DALVIK_ALLOC_VISIT */
diff --git a/vm/alloc/VisitInlines.h b/vm/alloc/VisitInlines.h
new file mode 100644
index 0000000..84a456a
--- /dev/null
+++ b/vm/alloc/VisitInlines.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DALVIK_ALLOC_VISITINLINES
+#define _DALVIK_ALLOC_VISITINLINES
+
+/*
+ * Visits the instance fields of a class or data object.
+ */
+static void visitFields(Visitor *visitor, Object *obj, void *arg)
+{
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
+ size_t refOffsets = obj->clazz->refOffsets;
+ while (refOffsets != 0) {
+ size_t rshift = CLZ(refOffsets);
+ size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
+ Object **ref = BYTE_OFFSET(obj, offset);
+ (*visitor)(ref, arg);
+ refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
+ }
+ } else {
+ ClassObject *clazz;
+ for (clazz = obj->clazz; clazz != NULL; clazz = clazz->super) {
+ InstField *field = clazz->ifields;
+ int i;
+ for (i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
+ size_t offset = field->byteOffset;
+ Object **ref = BYTE_OFFSET(obj, offset);
+ (*visitor)(ref, arg);
+ }
+ }
+ }
+}
+
+/*
+ * Visits the static fields of a class object.
+ */
+static void visitStaticFields(Visitor *visitor, ClassObject *clazz,
+ void *arg)
+{
+ int i;
+
+ assert(visitor != NULL);
+ assert(clazz != NULL);
+ for (i = 0; i < clazz->sfieldCount; ++i) {
+ char ch = clazz->sfields[i].field.signature[0];
+ if (ch == '[' || ch == 'L') {
+ (*visitor)(&clazz->sfields[i].value.l, arg);
+ }
+ }
+}
+
+/*
+ * Visit the interfaces of a class object.
+ */
+static void visitInterfaces(Visitor *visitor, ClassObject *clazz,
+ void *arg)
+{
+ int i;
+
+ assert(visitor != NULL);
+ assert(clazz != NULL);
+ for (i = 0; i < clazz->interfaceCount; ++i) {
+ (*visitor)(&clazz->interfaces[i], arg);
+ }
+}
+
+/*
+ * Visits all the references stored in a class object instance.
+ */
+static void visitClassObject(Visitor *visitor, Object *obj, void *arg)
+{
+ ClassObject *classObj;
+ ClassStatus status;
+
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ assert(!strcmp(obj->clazz->descriptor, "Ljava/lang/Class;"));
+ classObj = (ClassObject *)obj;
+ (*visitor)(&obj->clazz, arg);
+ if (IS_CLASS_FLAG_SET(classObj, CLASS_ISARRAY)) {
+ (*visitor)(&classObj->elementClass, arg);
+ }
+ status = classObj->status;
+ if (status > CLASS_IDX) {
+ (*visitor)(&classObj->super, arg);
+ }
+ (*visitor)(&classObj->classLoader, arg);
+ visitFields(visitor, obj, arg);
+ visitStaticFields(visitor, classObj, arg);
+ if (status > CLASS_IDX) {
+ visitInterfaces(visitor, classObj, arg);
+ }
+}
+
+/*
+ * Visits the class object and, if the array is typed as an object
+ * array, all of the array elements.
+ */
+static void visitArrayObject(Visitor *visitor, Object *obj, void *arg)
+{
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ (*visitor)(&obj->clazz, arg);
+ if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
+ ArrayObject *array = (ArrayObject *)obj;
+ Object **contents = (Object **)array->contents;
+ size_t i;
+ for (i = 0; i < array->length; ++i) {
+ (*visitor)(&contents[i], arg);
+ }
+ }
+}
+
+/*
+ * Visits the class object and reference typed instance fields of a
+ * data object.
+ */
+static void visitDataObject(Visitor *visitor, Object *obj, void *arg)
+{
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ (*visitor)(&obj->clazz, arg);
+ visitFields(visitor, obj, arg);
+}
+
+/*
+ * Like visitDataObject, but visits the hidden referent field that
+ * belongings to the subclasses of java.lang.Reference.
+ */
+static void visitReferenceObject(Visitor *visitor, Object *obj, void *arg)
+{
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ visitDataObject(visitor, obj, arg);
+ size_t offset = gDvm.offJavaLangRefReference_referent;
+ Object **ref = BYTE_OFFSET(obj, offset);
+ (*visitor)(ref, arg);
+}
+
+/*
+ * Visits all of the reference stored in an object.
+ */
+static void visitObject(Visitor *visitor, Object *obj, void *arg)
+{
+ assert(visitor != NULL);
+ assert(obj != NULL);
+ assert(obj->clazz != NULL);
+ if (obj->clazz == gDvm.classJavaLangClass) {
+ visitClassObject(visitor, obj, arg);
+ } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+ visitArrayObject(visitor, obj, arg);
+ } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
+ visitReferenceObject(visitor, obj, arg);
+ } else {
+ visitDataObject(visitor, obj, arg);
+ }
+}
+
+#endif /* _DALVIK_ALLOC_VISITINLINES */
diff --git a/vm/alloc/WriteBarrier.h b/vm/alloc/WriteBarrier.h
new file mode 100644
index 0000000..34b3b19
--- /dev/null
+++ b/vm/alloc/WriteBarrier.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Note writes to the heap. These functions must be called if a field
+ * of an Object in the heap changes, and before any GC safe-point. The
+ * call is not needed if NULL is stored in the field.
+ */
+
+/*
+ * The address within the Object has been written, and perhaps changed.
+ */
+INLINE void dvmWriteBarrierField(const Object *obj, void *addr)
+{
+ dvmMarkCard(obj);
+}
+
+/*
+ * All of the Object may have changed.
+ */
+INLINE void dvmWriteBarrierObject(const Object *obj)
+{
+ dvmMarkCard(obj);
+}
+
+/*
+ * Some or perhaps all of the array indexes in the Array, greater than
+ * or equal to start and strictly less than end, have been written,
+ * and perhaps changed.
+ */
+INLINE void dvmWriteBarrierArray(const ArrayObject *obj,
+ size_t start, size_t end)
+{
+ dvmMarkCard((Object *)obj);
+}
diff --git a/vm/alloc/clz.c b/vm/alloc/clz.c
index 2ec873e..3488975 100644
--- a/vm/alloc/clz.c
+++ b/vm/alloc/clz.c
@@ -47,4 +47,3 @@
return e;
#endif
}
-
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 942ac60..3c7be11 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -29,6 +29,7 @@
*/
#include "Dalvik.h"
#include "analysis/CodeVerify.h"
+#include "analysis/Optimize.h"
#include "analysis/RegisterMap.h"
#include "libdex/DexCatch.h"
#include "libdex/InstrUtils.h"
@@ -113,16 +114,18 @@
/* fwd */
+#ifndef NDEBUG
static void checkMergeTab(void);
+#endif
static bool isInitMethod(const Method* meth);
static RegType getInvocationThis(const RegType* insnRegs,\
const int insnRegCount, const DecodedInstruction* pDecInsn,
VerifyError* pFailure);
static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,\
u4 vsrc, RegType checkType, VerifyError* pFailure);
-static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,\
+static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,\
RegisterTable* regTable, UninitInstanceMap* uninitMap);
-static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,\
+static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
RegisterTable* regTable, RegType* workRegs, int insnIdx,
UninitInstanceMap* uninitMap, int* pStartGuess);
static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
@@ -539,10 +542,12 @@
/*
* Is this method a class initializer?
*/
+#if 0
static bool isClassInitMethod(const Method* meth)
{
return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
}
+#endif
/*
* Look up a class reference given as a simple string descriptor.
@@ -1337,8 +1342,6 @@
static inline RegType getRegisterType(const RegType* insnRegs,
const int insnRegCount, u4 vsrc, VerifyError* pFailure)
{
- RegType type;
-
if (vsrc >= (u4) insnRegCount) {
*pFailure = VERIFY_ERROR_GENERIC;
return kRegTypeUnknown;
@@ -2921,6 +2924,10 @@
* Replace an instruction with "throw-verification-error". This allows us to
* defer error reporting until the code path is first used.
*
+ * This is expected to be called during "just in time" verification, not
+ * from within dexopt. (Verification failures in dexopt will result in
+ * postponement of verification to first use of the class.)
+ *
* The throw-verification-error instruction requires two code units. Some
* of the replaced instructions require three; the third code unit will
* receive a "nop". The instruction's length will be left unchanged
@@ -2929,12 +2936,9 @@
* The verifier explicitly locks out breakpoint activity, so there should
* be no clashes with the debugger.
*
- * IMPORTANT: this may replace meth->insns with a pointer to a new copy of
- * the instructions.
- *
* Returns "true" on success.
*/
-static bool replaceFailingInstruction(Method* meth, InsnFlags* insnFlags,
+static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
int insnIdx, VerifyError failure)
{
VerifyErrorRefType refType;
@@ -2942,7 +2946,8 @@
u2 oldInsn = *oldInsns;
bool result = false;
- //dvmMakeCodeReadWrite(meth);
+ if (gDvm.optimizing)
+ LOGD("Weird: RFI during dexopt?");
//LOGD(" was 0x%04x\n", oldInsn);
u2* newInsns = (u2*) meth->insns + insnIdx;
@@ -3040,7 +3045,6 @@
result = true;
bail:
- //dvmMakeCodeReadOnly(meth);
return result;
}
@@ -3054,15 +3058,12 @@
/*
* Entry point for the detailed code-flow analysis.
*/
-bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
- UninitInstanceMap* uninitMap)
+bool dvmVerifyCodeFlow(VerifierData* vdata)
{
bool result = false;
- const int insnsSize = dvmGetMethodInsnsSize(meth);
- const u2* insns = meth->insns;
+ const Method* meth = vdata->method;
+ const int insnsSize = vdata->insnsSize;
const bool generateRegisterMap = gDvm.generateRegisterMaps;
- int i, offset;
- bool isConditional;
RegisterTable regTable;
memset(®Table, 0, sizeof(regTable));
@@ -3092,7 +3093,7 @@
gDvm.classJavaLangObject =
dvmFindSystemClassNoInit("Ljava/lang/Object;");
- if (meth->registersSize * insnsSize > 2*1024*1024) {
+ if (meth->registersSize * insnsSize > 4*1024*1024) {
/* should probably base this on actual memory requirements */
LOG_VFY_METH(meth,
"VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
@@ -3105,37 +3106,32 @@
* also going to create the register map, we need to retain the
* register lists for a larger set of addresses.
*/
- if (!initRegisterTable(meth, insnFlags, ®Table,
+ if (!initRegisterTable(meth, vdata->insnFlags, ®Table,
generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
goto bail;
+ vdata->addrRegs = NULL; /* don't set this until we need it */
+
/*
* Initialize the types of the registers that correspond to the
* method arguments. We can determine this from the method signature.
*/
- if (!setTypesFromSignature(meth, regTable.addrRegs[0], uninitMap))
+ if (!setTypesFromSignature(meth, regTable.addrRegs[0], vdata->uninitMap))
goto bail;
/*
* Run the verifier.
*/
- if (!doCodeVerification(meth, insnFlags, ®Table, uninitMap))
+ if (!doCodeVerification(meth, vdata->insnFlags, ®Table, vdata->uninitMap))
goto bail;
/*
* Generate a register map.
*/
if (generateRegisterMap) {
- RegisterMap* pMap;
- VerifierData vd;
+ vdata->addrRegs = regTable.addrRegs;
- vd.method = meth;
- vd.insnsSize = insnsSize;
- vd.insnRegCount = meth->registersSize;
- vd.insnFlags = insnFlags;
- vd.addrRegs = regTable.addrRegs;
-
- pMap = dvmGenerateRegisterMapV(&vd);
+ RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
if (pMap != NULL) {
/*
* Tuck it into the Method struct. It will either get used
@@ -3208,15 +3204,14 @@
* instruction if a register contains an uninitialized instance created
* by that same instrutcion.
*/
-static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,
+static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
RegisterTable* regTable, UninitInstanceMap* uninitMap)
{
const int insnsSize = dvmGetMethodInsnsSize(meth);
- const u2* insns = meth->insns;
RegType workRegs[meth->registersSize + kExtraRegs];
bool result = false;
bool debugVerbose = false;
- int insnIdx, startGuess, prevAddr;
+ int insnIdx, startGuess;
/*
* Begin by marking the first instruction as "changed".
@@ -3443,7 +3438,7 @@
* This may alter meth->insns if we need to replace an instruction with
* throw-verification-error.
*/
-static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,
+static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
RegisterTable* regTable, RegType* workRegs, int insnIdx,
UninitInstanceMap* uninitMap, int* pStartGuess)
{
@@ -3462,19 +3457,17 @@
* and switch statements.
* (3) Exception handlers. Applies to any instruction that can
* throw an exception that is handled by an encompassing "try"
- * block. (We simplify this to be any instruction that can
- * throw any exception.)
+ * block.
*
* We can also return, in which case there is no successor instruction
* from this point.
*
- * The behavior can be determined from the InstrFlags.
+ * The behavior can be determined from the InstructionFlags.
*/
const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
RegType entryRegs[meth->registersSize + kExtraRegs];
ClassObject* resClass;
- const char* className;
int branchTarget = 0;
const int insnRegCount = meth->registersSize;
RegType tmpType;
@@ -4016,7 +4009,6 @@
case OP_IF_NE:
{
RegType type1, type2;
- bool tmpResult;
type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
&failure);
@@ -4426,6 +4418,7 @@
break;
case OP_IGET:
+ case OP_IGET_VOLATILE:
tmpType = kRegTypeInteger;
goto iget_1nr_common;
case OP_IGET_BOOLEAN:
@@ -4442,7 +4435,6 @@
goto iget_1nr_common;
iget_1nr_common:
{
- ClassObject* fieldClass;
InstField* instField;
RegType objType, fieldType;
@@ -4472,9 +4464,9 @@
}
break;
case OP_IGET_WIDE:
+ case OP_IGET_WIDE_VOLATILE:
{
RegType dstType;
- ClassObject* fieldClass;
InstField* instField;
RegType objType;
@@ -4509,6 +4501,7 @@
}
break;
case OP_IGET_OBJECT:
+ case OP_IGET_OBJECT_VOLATILE:
{
ClassObject* fieldClass;
InstField* instField;
@@ -4538,6 +4531,7 @@
}
break;
case OP_IPUT:
+ case OP_IPUT_VOLATILE:
tmpType = kRegTypeInteger;
goto iput_1nr_common;
case OP_IPUT_BOOLEAN:
@@ -4555,7 +4549,6 @@
iput_1nr_common:
{
RegType srcType, fieldType, objType;
- ClassObject* fieldClass;
InstField* instField;
srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
@@ -4602,6 +4595,7 @@
}
break;
case OP_IPUT_WIDE:
+ case OP_IPUT_WIDE_VOLATILE:
tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
if (VERIFY_OK(failure)) {
RegType typeHi =
@@ -4610,7 +4604,6 @@
checkWidePair(tmpType, typeHi, &failure);
}
if (VERIFY_OK(failure)) {
- ClassObject* fieldClass;
InstField* instField;
RegType objType;
@@ -4642,6 +4635,7 @@
}
break;
case OP_IPUT_OBJECT:
+ case OP_IPUT_OBJECT_VOLATILE:
{
ClassObject* fieldClass;
ClassObject* valueClass;
@@ -4703,6 +4697,7 @@
break;
case OP_SGET:
+ case OP_SGET_VOLATILE:
tmpType = kRegTypeInteger;
goto sget_1nr_common;
case OP_SGET_BOOLEAN:
@@ -4748,6 +4743,7 @@
}
break;
case OP_SGET_WIDE:
+ case OP_SGET_WIDE_VOLATILE:
{
StaticField* staticField;
RegType dstType;
@@ -4778,6 +4774,7 @@
}
break;
case OP_SGET_OBJECT:
+ case OP_SGET_OBJECT_VOLATILE:
{
StaticField* staticField;
ClassObject* fieldClass;
@@ -4802,6 +4799,7 @@
}
break;
case OP_SPUT:
+ case OP_SPUT_VOLATILE:
tmpType = kRegTypeInteger;
goto sput_1nr_common;
case OP_SPUT_BOOLEAN:
@@ -4864,6 +4862,7 @@
}
break;
case OP_SPUT_WIDE:
+ case OP_SPUT_WIDE_VOLATILE:
tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
if (VERIFY_OK(failure)) {
RegType typeHi =
@@ -4897,6 +4896,7 @@
}
break;
case OP_SPUT_OBJECT:
+ case OP_SPUT_OBJECT_VOLATILE:
{
ClassObject* fieldClass;
ClassObject* valueClass;
@@ -5047,7 +5047,6 @@
* do this for all registers that have the same object
* instance in them, not just the "this" register.
*/
- int uidx = regTypeToUninitIndex(thisType);
markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
thisType, &failure);
if (!VERIFY_OK(failure))
@@ -5437,20 +5436,8 @@
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
- case OP_UNUSED_E3:
- case OP_UNUSED_E4:
- case OP_UNUSED_E5:
- case OP_UNUSED_E6:
- case OP_UNUSED_E7:
- case OP_UNUSED_E8:
- case OP_UNUSED_E9:
- case OP_UNUSED_EA:
- case OP_UNUSED_EB:
case OP_BREAKPOINT:
case OP_UNUSED_F1:
- case OP_UNUSED_FC:
- case OP_UNUSED_FD:
- case OP_UNUSED_FE:
case OP_UNUSED_FF:
failure = VERIFY_ERROR_GENERIC;
break;
@@ -5488,7 +5475,8 @@
/*
* If we didn't just set the result register, clear it out. This
* ensures that you can only use "move-result" immediately after the
- * result is set.
+ * result is set. (We could check this statically, but it's not
+ * expensive and it makes our debugging output cleaner.)
*/
if (!justSetResult) {
int reg = RESULT_REGISTER(insnRegCount);
@@ -5608,7 +5596,6 @@
*/
if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
{
- DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
const DexCode* pCode = dvmGetMethodCode(meth);
DexCatchIterator iterator;
@@ -5767,4 +5754,3 @@
NULL, logLocalsCb, &addr);
}
}
-
diff --git a/vm/analysis/CodeVerify.h b/vm/analysis/CodeVerify.h
index 1b93655..a7ddc95 100644
--- a/vm/analysis/CodeVerify.h
+++ b/vm/analysis/CodeVerify.h
@@ -106,7 +106,65 @@
*/
typedef u4 RegType;
-/* table with merge logic for primitive types */
+/*
+ * Table that maps uninitialized instances to classes, based on the
+ * address of the new-instance instruction.
+ */
+typedef struct UninitInstanceMap {
+ int numEntries;
+ struct {
+ int addr; /* code offset, or -1 for method arg ("this") */
+ ClassObject* clazz; /* class created at this address */
+ } map[1];
+} UninitInstanceMap;
+#define kUninitThisArgAddr (-1)
+#define kUninitThisArgSlot 0
+
+/*
+ * Various bits of data generated by the verifier, wrapped up in a package
+ * for ease of use by the register map generator.
+ */
+typedef struct VerifierData {
+ /*
+ * The method we're working on.
+ */
+ const Method* method;
+
+ /*
+ * Number of code units of instructions in the method. A cache of the
+ * value calculated by dvmGetMethodInsnsSize().
+ */
+ u4 insnsSize;
+
+ /*
+ * Number of registers we track for each instruction. This is equal
+ * to the method's declared "registersSize". (Does not include the
+ * pending return value.)
+ */
+ u4 insnRegCount;
+
+ /*
+ * Instruction widths and flags, one entry per code unit.
+ */
+ InsnFlags* insnFlags;
+
+ /*
+ * Uninitialized instance map, used for tracking the movement of
+ * objects that have been allocated but not initialized.
+ */
+ UninitInstanceMap* uninitMap;
+
+ /*
+ * Array of SRegType arrays, one entry per code unit. We only need
+ * entries for code units that hold the start of an "interesting"
+ * instruction. For register map generation, we're only interested
+ * in GC points.
+ */
+ RegType** addrRegs;
+} VerifierData;
+
+
+/* table with static merge logic for primitive types */
extern const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX];
@@ -209,20 +267,6 @@
/*
- * Table that maps uninitialized instances to classes, based on the
- * address of the new-instance instruction.
- */
-typedef struct UninitInstanceMap {
- int numEntries;
- struct {
- int addr; /* code offset, or -1 for method arg ("this") */
- ClassObject* clazz; /* class created at this address */
- } map[1];
-} UninitInstanceMap;
-#define kUninitThisArgAddr (-1)
-#define kUninitThisArgSlot 0
-
-/*
* Create a new UninitInstanceMap.
*/
UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
@@ -239,7 +283,7 @@
* different class is already associated with the address (shouldn't
* happen either).
*/
-//int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
+//int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
// ClassObject* clazz);
/*
@@ -259,7 +303,6 @@
* Verify bytecode in "meth". "insnFlags" should be populated with
* instruction widths and "in try" flags.
*/
-bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
- UninitInstanceMap* uninitMap);
+bool dvmVerifyCodeFlow(VerifierData* vdata);
#endif /*_DALVIK_CODEVERIFY*/
diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c
deleted file mode 100644
index a5b8b6f..0000000
--- a/vm/analysis/DexOptimize.c
+++ /dev/null
@@ -1,2383 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Convert the output from "dx" into a locally-optimized DEX file.
- *
- * TODO: the format of the optimized header is currently "whatever we
- * happen to write", since the VM that writes it is by definition the same
- * as the VM that reads it. Still, it should be better documented and
- * more rigorously structured.
- */
-#include "Dalvik.h"
-#include "libdex/InstrUtils.h"
-#include "libdex/OptInvocation.h"
-#include "analysis/RegisterMap.h"
-
-#include <zlib.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <errno.h>
-
-/*
- * Virtual/direct calls to "method" are replaced with an execute-inline
- * instruction with index "idx".
- */
-typedef struct InlineSub {
- Method* method;
- int inlineIdx;
-} InlineSub;
-
-
-/* fwd */
-static int writeDependencies(int fd, u4 modWhen, u4 crc);
-static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
- const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
-static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
- int err);
-static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
-
-static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,\
- u4* pHeaderFlags, DexClassLookup** ppClassLookup);
-static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
-static bool loadAllClasses(DvmDex* pDvmDex);
-static void optimizeLoadedClasses(DexFile* pDexFile);
-static void optimizeClass(ClassObject* clazz, const InlineSub* inlineSubs);
-static bool optimizeMethod(Method* method, const InlineSub* inlineSubs);
-static void rewriteInstField(Method* method, u2* insns, OpCode newOpc);
-static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc);
-static bool rewriteEmptyDirectInvoke(Method* method, u2* insns);
-static bool rewriteExecuteInline(Method* method, u2* insns,
- MethodType methodType, const InlineSub* inlineSubs);
-static bool rewriteExecuteInlineRange(Method* method, u2* insns,
- MethodType methodType, const InlineSub* inlineSubs);
-
-
-/*
- * Return the fd of an open file in the DEX file cache area. If the cache
- * file doesn't exist or is out of date, this will remove the old entry,
- * create a new one (writing only the file header), and return with the
- * "new file" flag set.
- *
- * It's possible to execute from an unoptimized DEX file directly,
- * assuming the byte ordering and structure alignment is correct, but
- * disadvantageous because some significant optimizations are not possible.
- * It's not generally possible to do the same from an uncompressed Jar
- * file entry, because we have to guarantee 32-bit alignment in the
- * memory-mapped file.
- *
- * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
- * and "crc32" come from the Zip directory entry. For a stand-alone DEX
- * file, it's the modification date of the file and the Adler32 from the
- * DEX header (which immediately follows the magic). If these don't
- * match what's stored in the opt header, we reject the file immediately.
- *
- * On success, the file descriptor will be positioned just past the "opt"
- * file header, and will be locked with flock. "*pCachedName" will point
- * to newly-allocated storage.
- */
-int dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
- u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
-{
- int fd, cc;
- struct stat fdStat, fileStat;
- bool readOnly = false;
-
- *pNewFile = false;
-
-retry:
- /*
- * Try to open the cache file. If we've been asked to,
- * create it if it doesn't exist.
- */
- fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
- if (fd < 0) {
- fd = open(cacheFileName, O_RDONLY, 0);
- if (fd < 0) {
- if (createIfMissing) {
- LOGE("Can't open dex cache '%s': %s\n",
- cacheFileName, strerror(errno));
- }
- return fd;
- }
- readOnly = true;
- }
-
- /*
- * Grab an exclusive lock on the cache file. If somebody else is
- * working on it, we'll block here until they complete. Because
- * we're waiting on an external resource, we go into VMWAIT mode.
- */
- int oldStatus;
- LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)\n",
- cacheFileName, fd, isBootstrap);
- oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
- cc = flock(fd, LOCK_EX | LOCK_NB);
- if (cc != 0) {
- LOGD("DexOpt: sleeping on flock(%s)\n", cacheFileName);
- cc = flock(fd, LOCK_EX);
- }
- dvmChangeStatus(NULL, oldStatus);
- if (cc != 0) {
- LOGE("Can't lock dex cache '%s': %d\n", cacheFileName, cc);
- close(fd);
- return -1;
- }
- LOGV("DexOpt: locked cache file\n");
-
- /*
- * Check to see if the fd we opened and locked matches the file in
- * the filesystem. If they don't, then somebody else unlinked ours
- * and created a new file, and we need to use that one instead. (If
- * we caught them between the unlink and the create, we'll get an
- * ENOENT from the file stat.)
- */
- cc = fstat(fd, &fdStat);
- if (cc != 0) {
- LOGE("Can't stat open file '%s'\n", cacheFileName);
- LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
- goto close_fail;
- }
- cc = stat(cacheFileName, &fileStat);
- if (cc != 0 ||
- fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
- {
- LOGD("DexOpt: our open cache file is stale; sleeping and retrying\n");
- LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
- flock(fd, LOCK_UN);
- close(fd);
- usleep(250 * 1000); /* if something is hosed, don't peg machine */
- goto retry;
- }
-
- /*
- * We have the correct file open and locked. If the file size is zero,
- * then it was just created by us, and we want to fill in some fields
- * in the "opt" header and set "*pNewFile". Otherwise, we want to
- * verify that the fields in the header match our expectations, and
- * reset the file if they don't.
- */
- if (fdStat.st_size == 0) {
- if (readOnly) {
- LOGW("DexOpt: file has zero length and isn't writable\n");
- goto close_fail;
- }
- cc = dexOptCreateEmptyHeader(fd);
- if (cc != 0)
- goto close_fail;
- *pNewFile = true;
- LOGV("DexOpt: successfully initialized new cache file\n");
- } else {
- bool expectVerify, expectOpt;
-
- if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
- expectVerify = false;
- else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
- expectVerify = !isBootstrap;
- else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
- expectVerify = true;
-
- if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
- expectOpt = false;
- else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
- expectOpt = expectVerify;
- else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
- expectOpt = true;
-
- LOGV("checking deps, expecting vfy=%d opt=%d\n",
- expectVerify, expectOpt);
-
- if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
- expectVerify, expectOpt))
- {
- if (readOnly) {
- /*
- * We could unlink and rewrite the file if we own it or
- * the "sticky" bit isn't set on the directory. However,
- * we're not able to truncate it, which spoils things. So,
- * give up now.
- */
- if (createIfMissing) {
- LOGW("Cached DEX '%s' (%s) is stale and not writable\n",
- fileName, cacheFileName);
- }
- goto close_fail;
- }
-
- /*
- * If we truncate the existing file before unlinking it, any
- * process that has it mapped will fail when it tries to touch
- * the pages.
- *
- * This is very important. The zygote process will have the
- * boot DEX files (core, framework, etc.) mapped early. If
- * (say) core.dex gets updated, and somebody launches an app
- * that uses App.dex, then App.dex gets reoptimized because it's
- * dependent upon the boot classes. However, dexopt will be
- * using the *new* core.dex to do the optimizations, while the
- * app will actually be running against the *old* core.dex
- * because it starts from zygote.
- *
- * Even without zygote, it's still possible for a class loader
- * to pull in an APK that was optimized against an older set
- * of DEX files. We must ensure that everything fails when a
- * boot DEX gets updated, and for general "why aren't my
- * changes doing anything" purposes its best if we just make
- * everything crash when a DEX they're using gets updated.
- */
- LOGD("Stale deps in cache file; removing and retrying\n");
- if (ftruncate(fd, 0) != 0) {
- LOGW("Warning: unable to truncate cache file '%s': %s\n",
- cacheFileName, strerror(errno));
- /* keep going */
- }
- if (unlink(cacheFileName) != 0) {
- LOGW("Warning: unable to remove cache file '%s': %d %s\n",
- cacheFileName, errno, strerror(errno));
- /* keep going; permission failure should probably be fatal */
- }
- LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
- flock(fd, LOCK_UN);
- close(fd);
- goto retry;
- } else {
- LOGV("DexOpt: good deps in cache file\n");
- }
- }
-
- assert(fd >= 0);
- return fd;
-
-close_fail:
- flock(fd, LOCK_UN);
- close(fd);
- return -1;
-}
-
-/*
- * Unlock the file descriptor.
- *
- * Returns "true" on success.
- */
-bool dvmUnlockCachedDexFile(int fd)
-{
- LOGVV("DexOpt: unlocking cache file fd=%d\n", fd);
- return (flock(fd, LOCK_UN) == 0);
-}
-
-
-/*
- * Given a descriptor for a file with DEX data in it, produce an
- * optimized version.
- *
- * The file pointed to by "fd" is expected to be a locked shared resource
- * (or private); we make no efforts to enforce multi-process correctness
- * here.
- *
- * "fileName" is only used for debug output. "modWhen" and "crc" are stored
- * in the dependency set.
- *
- * The "isBootstrap" flag determines how the optimizer and verifier handle
- * package-scope access checks. When optimizing, we only load the bootstrap
- * class DEX files and the target DEX, so the flag determines whether the
- * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
- * This only really matters if the target DEX contains classes that claim to
- * be in the same package as bootstrap classes.
- *
- * The optimizer will need to load every class in the target DEX file.
- * This is generally undesirable, so we start a subprocess to do the
- * work and wait for it to complete.
- *
- * Returns "true" on success. All data will have been written to "fd".
- */
-bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
- const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
-{
- const char* lastPart = strrchr(fileName, '/');
- if (lastPart != NULL)
- lastPart++;
- else
- lastPart = fileName;
-
- /*
- * For basic optimizations (byte-swapping and structure aligning) we
- * don't need to fork(). It looks like fork+exec is causing problems
- * with gdb on our bewildered Linux distro, so in some situations we
- * want to avoid this.
- *
- * For optimization and/or verification, we need to load all the classes.
- *
- * We don't check gDvm.generateRegisterMaps, since that is dependent
- * upon the verifier state.
- */
- if (gDvm.classVerifyMode == VERIFY_MODE_NONE &&
- (gDvm.dexOptMode == OPTIMIZE_MODE_NONE ||
- gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED))
- {
- LOGD("DexOpt: --- BEGIN (quick) '%s' ---\n", lastPart);
- return dvmContinueOptimization(fd, dexOffset, dexLength,
- fileName, modWhen, crc, isBootstrap);
- }
-
-
- LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---\n", lastPart, isBootstrap);
-
- pid_t pid;
-
- /*
- * This could happen if something in our bootclasspath, which we thought
- * was all optimized, got rejected.
- */
- if (gDvm.optimizing) {
- LOGW("Rejecting recursive optimization attempt on '%s'\n", fileName);
- return false;
- }
-
- pid = fork();
- if (pid == 0) {
- static const int kUseValgrind = 0;
- static const char* kDexOptBin = "/bin/dexopt";
- static const char* kValgrinder = "/usr/bin/valgrind";
- static const int kFixedArgCount = 10;
- static const int kValgrindArgCount = 5;
- static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8dig
- int bcpSize = dvmGetBootPathSize();
- int argc = kFixedArgCount + bcpSize
- + (kValgrindArgCount * kUseValgrind);
- char* argv[argc+1]; // last entry is NULL
- char values[argc][kMaxIntLen];
- char* execFile;
- char* androidRoot;
- int flags;
-
- /* change process groups, so we don't clash with ProcessManager */
- setpgid(0, 0);
-
- /* full path to optimizer */
- androidRoot = getenv("ANDROID_ROOT");
- if (androidRoot == NULL) {
- LOGW("ANDROID_ROOT not set, defaulting to /system\n");
- androidRoot = "/system";
- }
- execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
- strcpy(execFile, androidRoot);
- strcat(execFile, kDexOptBin);
-
- /*
- * Create arg vector.
- */
- int curArg = 0;
-
- if (kUseValgrind) {
- /* probably shouldn't ship the hard-coded path */
- argv[curArg++] = (char*)kValgrinder;
- argv[curArg++] = "--tool=memcheck";
- argv[curArg++] = "--leak-check=yes"; // check for leaks too
- argv[curArg++] = "--leak-resolution=med"; // increase from 2 to 4
- argv[curArg++] = "--num-callers=16"; // default is 12
- assert(curArg == kValgrindArgCount);
- }
- argv[curArg++] = execFile;
-
- argv[curArg++] = "--dex";
-
- sprintf(values[2], "%d", DALVIK_VM_BUILD);
- argv[curArg++] = values[2];
-
- sprintf(values[3], "%d", fd);
- argv[curArg++] = values[3];
-
- sprintf(values[4], "%d", (int) dexOffset);
- argv[curArg++] = values[4];
-
- sprintf(values[5], "%d", (int) dexLength);
- argv[curArg++] = values[5];
-
- argv[curArg++] = (char*)fileName;
-
- sprintf(values[7], "%d", (int) modWhen);
- argv[curArg++] = values[7];
-
- sprintf(values[8], "%d", (int) crc);
- argv[curArg++] = values[8];
-
- flags = 0;
- if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
- flags |= DEXOPT_OPT_ENABLED;
- if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
- flags |= DEXOPT_OPT_ALL;
- }
- if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
- flags |= DEXOPT_VERIFY_ENABLED;
- if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
- flags |= DEXOPT_VERIFY_ALL;
- }
- if (isBootstrap)
- flags |= DEXOPT_IS_BOOTSTRAP;
- if (gDvm.generateRegisterMaps)
- flags |= DEXOPT_GEN_REGISTER_MAP;
- sprintf(values[9], "%d", flags);
- argv[curArg++] = values[9];
-
- assert(((!kUseValgrind && curArg == kFixedArgCount) ||
- ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
-
- ClassPathEntry* cpe;
- for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
- argv[curArg++] = cpe->fileName;
- }
- assert(curArg == argc);
-
- argv[curArg] = NULL;
-
- if (kUseValgrind)
- execv(kValgrinder, argv);
- else
- execv(execFile, argv);
-
- LOGE("execv '%s'%s failed: %s\n", execFile,
- kUseValgrind ? " [valgrind]" : "", strerror(errno));
- exit(1);
- } else {
- LOGV("DexOpt: waiting for verify+opt, pid=%d\n", (int) pid);
- int status;
- pid_t gotPid;
- int oldStatus;
-
- /*
- * Wait for the optimization process to finish. We go into VMWAIT
- * mode here so GC suspension won't have to wait for us.
- */
- oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
- while (true) {
- gotPid = waitpid(pid, &status, 0);
- if (gotPid == -1 && errno == EINTR) {
- LOGD("waitpid interrupted, retrying\n");
- } else {
- break;
- }
- }
- dvmChangeStatus(NULL, oldStatus);
- if (gotPid != pid) {
- LOGE("waitpid failed: wanted %d, got %d: %s\n",
- (int) pid, (int) gotPid, strerror(errno));
- return false;
- }
-
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- LOGD("DexOpt: --- END '%s' (success) ---\n", lastPart);
- return true;
- } else {
- LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed\n",
- lastPart, status);
- return false;
- }
- }
-}
-
-/*
- * Do the actual optimization. This is called directly for "minimal"
- * optimization, or from a newly-created process for "full" optimization.
- *
- * For best use of disk/memory, we want to extract once and perform
- * optimizations in place. If the file has to expand or contract
- * to match local structure padding/alignment expectations, we want
- * to do the rewrite as part of the extract, rather than extracting
- * into a temp file and slurping it back out. (The structure alignment
- * is currently correct for all platforms, and this isn't expected to
- * change, so we should be okay with having it already extracted.)
- *
- * Returns "true" on success.
- */
-bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
- const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
-{
- DexClassLookup* pClassLookup = NULL;
- IndexMapSet* pIndexMapSet = NULL;
- RegisterMapBuilder* pRegMapBuilder = NULL;
- bool doVerify, doOpt;
- u4 headerFlags = 0;
-
- if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
- doVerify = false;
- else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
- doVerify = !isBootstrap;
- else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
- doVerify = true;
-
- if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
- doOpt = false;
- else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
- doOpt = doVerify;
- else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
- doOpt = true;
-
- LOGV("Continuing optimization (%s, isb=%d, vfy=%d, opt=%d)\n",
- fileName, isBootstrap, doVerify, doOpt);
-
- assert(dexOffset >= 0);
-
- /* quick test so we don't blow up on empty file */
- if (dexLength < (int) sizeof(DexHeader)) {
- LOGE("too small to be DEX\n");
- return false;
- }
- if (dexOffset < (int) sizeof(DexOptHeader)) {
- LOGE("not enough room for opt header\n");
- return false;
- }
-
- bool result = false;
-
- /*
- * Drop this into a global so we don't have to pass it around. We could
- * also add a field to DexFile, but since it only pertains to DEX
- * creation that probably doesn't make sense.
- */
- gDvm.optimizingBootstrapClass = isBootstrap;
-
- {
- /*
- * Map the entire file (so we don't have to worry about page
- * alignment). The expectation is that the output file contains
- * our DEX data plus room for a small header.
- */
- bool success;
- void* mapAddr;
- mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (mapAddr == MAP_FAILED) {
- LOGE("unable to mmap DEX cache: %s\n", strerror(errno));
- goto bail;
- }
-
- /*
- * Rewrite the file. Byte reordering, structure realigning,
- * class verification, and bytecode optimization are all performed
- * here.
- *
- * In theory the file could change size and bits could shift around.
- * In practice this would be annoying to deal with, so the file
- * layout is designed so that it can always be rewritten in place.
- *
- * This sets "headerFlags" and creates the class lookup table as
- * part of doing the processing.
- */
- success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
- doVerify, doOpt, &headerFlags, &pClassLookup);
-
- if (success) {
- DvmDex* pDvmDex = NULL;
- u1* dexAddr = ((u1*) mapAddr) + dexOffset;
-
- if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
- LOGE("Unable to create DexFile\n");
- success = false;
- } else {
- /*
- * If configured to do so, scan the instructions, looking
- * for ways to reduce the size of the resolved-constant table.
- * This is done post-optimization, across the instructions
- * in all methods in all classes (even the ones that failed
- * to load).
- */
- pIndexMapSet = dvmRewriteConstants(pDvmDex);
-
- /*
- * If configured to do so, generate a full set of register
- * maps for all verified classes.
- */
- if (gDvm.generateRegisterMaps) {
- pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
- if (pRegMapBuilder == NULL) {
- LOGE("Failed generating register maps\n");
- success = false;
- }
- }
-
- DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
- updateChecksum(dexAddr, dexLength, pHeader);
-
- dvmDexFileFree(pDvmDex);
- }
- }
-
- /* unmap the read-write version, forcing writes to disk */
- if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
- LOGW("msync failed: %s\n", strerror(errno));
- // weird, but keep going
- }
-#if 1
- /*
- * This causes clean shutdown to fail, because we have loaded classes
- * that point into it. For the optimizer this isn't a problem,
- * because it's more efficient for the process to simply exit.
- * Exclude this code when doing clean shutdown for valgrind.
- */
- if (munmap(mapAddr, dexOffset + dexLength) != 0) {
- LOGE("munmap failed: %s\n", strerror(errno));
- goto bail;
- }
-#endif
-
- if (!success)
- goto bail;
- }
-
- /* get start offset, and adjust deps start for 64-bit alignment */
- off_t depsOffset, auxOffset, endOffset, adjOffset;
- int depsLength, auxLength;
- u4 optChecksum;
-
- depsOffset = lseek(fd, 0, SEEK_END);
- if (depsOffset < 0) {
- LOGE("lseek to EOF failed: %s\n", strerror(errno));
- goto bail;
- }
- adjOffset = (depsOffset + 7) & ~(0x07);
- if (adjOffset != depsOffset) {
- LOGV("Adjusting deps start from %d to %d\n",
- (int) depsOffset, (int) adjOffset);
- depsOffset = adjOffset;
- lseek(fd, depsOffset, SEEK_SET);
- }
-
- /*
- * Append the dependency list.
- */
- if (writeDependencies(fd, modWhen, crc) != 0) {
- LOGW("Failed writing dependencies\n");
- goto bail;
- }
-
- /* compute deps length, then adjust aux start for 64-bit alignment */
- auxOffset = lseek(fd, 0, SEEK_END);
- depsLength = auxOffset - depsOffset;
-
- adjOffset = (auxOffset + 7) & ~(0x07);
- if (adjOffset != auxOffset) {
- LOGV("Adjusting aux start from %d to %d\n",
- (int) auxOffset, (int) adjOffset);
- auxOffset = adjOffset;
- lseek(fd, auxOffset, SEEK_SET);
- }
-
- /*
- * Append any auxillary pre-computed data structures.
- */
- if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
- LOGW("Failed writing aux data\n");
- goto bail;
- }
-
- endOffset = lseek(fd, 0, SEEK_END);
- auxLength = endOffset - auxOffset;
-
- /* compute checksum from start of deps to end of aux area */
- if (!computeFileChecksum(fd, depsOffset,
- (auxOffset+auxLength) - depsOffset, &optChecksum))
- {
- goto bail;
- }
-
- /*
- * Output the "opt" header with all values filled in and a correct
- * magic number.
- */
- DexOptHeader optHdr;
- memset(&optHdr, 0xff, sizeof(optHdr));
- memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
- memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
- optHdr.dexOffset = (u4) dexOffset;
- optHdr.dexLength = (u4) dexLength;
- optHdr.depsOffset = (u4) depsOffset;
- optHdr.depsLength = (u4) depsLength;
- optHdr.auxOffset = (u4) auxOffset;
- optHdr.auxLength = (u4) auxLength;
-
- optHdr.flags = headerFlags;
- optHdr.checksum = optChecksum;
-
- ssize_t actual;
- lseek(fd, 0, SEEK_SET);
- actual = write(fd, &optHdr, sizeof(optHdr));
- if (actual != sizeof(optHdr)) {
- logFailedWrite(sizeof(optHdr), actual, "opt header", errno);
- goto bail;
- }
-
- LOGV("Successfully wrote DEX header\n");
- result = true;
-
- //dvmRegisterMapDumpStats();
-
-bail:
- dvmFreeIndexMapSet(pIndexMapSet);
- dvmFreeRegisterMapBuilder(pRegMapBuilder);
- free(pClassLookup);
- return result;
-}
-
-
-/*
- * Get the cache file name from a ClassPathEntry.
- */
-static const char* getCacheFileName(const ClassPathEntry* cpe)
-{
- switch (cpe->kind) {
- case kCpeJar:
- return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
- case kCpeDex:
- return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
- default:
- LOGE("DexOpt: unexpected cpe kind %d\n", cpe->kind);
- dvmAbort();
- return NULL;
- }
-}
-
-/*
- * Get the SHA-1 signature.
- */
-static const u1* getSignature(const ClassPathEntry* cpe)
-{
- DvmDex* pDvmDex;
-
- switch (cpe->kind) {
- case kCpeJar:
- pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
- break;
- case kCpeDex:
- pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
- break;
- default:
- LOGE("unexpected cpe kind %d\n", cpe->kind);
- dvmAbort();
- pDvmDex = NULL; // make gcc happy
- }
-
- assert(pDvmDex != NULL);
- return pDvmDex->pDexFile->pHeader->signature;
-}
-
-
-/*
- * Dependency layout:
- * 4b Source file modification time, in seconds since 1970 UTC
- * 4b CRC-32 from Zip entry, or Adler32 from source DEX header
- * 4b Dalvik VM build number
- * 4b Number of dependency entries that follow
- * Dependency entries:
- * 4b Name length (including terminating null)
- * var Full path of cache entry (null terminated)
- * 20b SHA-1 signature from source DEX file
- *
- * If this changes, update DEX_OPT_MAGIC_VERS.
- */
-static const size_t kMinDepSize = 4 * 4;
-static const size_t kMaxDepSize = 4 * 4 + 1024; // sanity check
-
-/*
- * Read the "opt" header, verify it, then read the dependencies section
- * and verify that data as well.
- *
- * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
- * match up with what is stored in the header. If they don't, we reject
- * the file so that it can be recreated from the updated original. If
- * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
- *
- * On successful return, the file will be seeked immediately past the
- * "opt" header.
- */
-bool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
- u4 crc, bool expectVerify, bool expectOpt)
-{
- DexOptHeader optHdr;
- u1* depData = NULL;
- const u1* magic;
- off_t posn;
- int result = false;
- ssize_t actual;
-
- /*
- * Start at the start. The "opt" header, when present, will always be
- * the first thing in the file.
- */
- if (lseek(fd, 0, SEEK_SET) != 0) {
- LOGE("DexOpt: failed to seek to start of file: %s\n", strerror(errno));
- goto bail;
- }
-
- /*
- * Read and do trivial verification on the opt header. The header is
- * always in host byte order.
- */
- if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
- LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
- goto bail;
- }
-
- magic = optHdr.magic;
- if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
- /* not a DEX file, or previous attempt was interrupted */
- LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
- magic[0], magic[1], magic[2], magic[3]);
- goto bail;
- }
- if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
- LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)\n",
- magic[4], magic[5], magic[6], magic[7]);
- goto bail;
- }
- if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
- LOGW("DexOpt: weird deps length %d, bailing\n", optHdr.depsLength);
- goto bail;
- }
-
- /*
- * Do the header flags match up with what we want?
- *
- * This is useful because it allows us to automatically regenerate
- * a file when settings change (e.g. verification is now mandatory),
- * but can cause difficulties if the bootstrap classes we depend upon
- * were handled differently than the current options specify. We get
- * upset because they're not verified or optimized, but we're not able
- * to regenerate them because the installer won't let us.
- *
- * (This is also of limited value when !sourceAvail.)
- *
- * So, for now, we essentially ignore "expectVerify" and "expectOpt"
- * by limiting the match mask.
- *
- * The only thing we really can't handle is incorrect byte-ordering.
- */
- const u4 matchMask = DEX_OPT_FLAG_BIG;
- u4 expectedFlags = 0;
-#if __BYTE_ORDER != __LITTLE_ENDIAN
- expectedFlags |= DEX_OPT_FLAG_BIG;
-#endif
- if (expectVerify)
- expectedFlags |= DEX_FLAG_VERIFIED;
- if (expectOpt)
- expectedFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
- if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
- LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)\n",
- expectedFlags, optHdr.flags, matchMask);
- goto bail;
- }
-
- posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
- if (posn < 0) {
- LOGW("DexOpt: seek to deps failed: %s\n", strerror(errno));
- goto bail;
- }
-
- /*
- * Read all of the dependency stuff into memory.
- */
- depData = (u1*) malloc(optHdr.depsLength);
- if (depData == NULL) {
- LOGW("DexOpt: unable to allocate %d bytes for deps\n",
- optHdr.depsLength);
- goto bail;
- }
- actual = read(fd, depData, optHdr.depsLength);
- if (actual != (ssize_t) optHdr.depsLength) {
- LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
- (int) actual, optHdr.depsLength, strerror(errno));
- goto bail;
- }
-
- /*
- * Verify simple items.
- */
- const u1* ptr;
- u4 val;
-
- ptr = depData;
- val = read4LE(&ptr);
- if (sourceAvail && val != modWhen) {
- LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)\n",
- val, modWhen);
- goto bail;
- }
- val = read4LE(&ptr);
- if (sourceAvail && val != crc) {
- LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)\n", val, crc);
- goto bail;
- }
- val = read4LE(&ptr);
- if (val != DALVIK_VM_BUILD) {
- LOGD("DexOpt: VM build version mismatch (%d vs %d)\n",
- val, DALVIK_VM_BUILD);
- goto bail;
- }
-
- /*
- * Verify dependencies on other cached DEX files. It must match
- * exactly with what is currently defined in the bootclasspath.
- */
- ClassPathEntry* cpe;
- u4 numDeps;
-
- numDeps = read4LE(&ptr);
- LOGV("+++ DexOpt: numDeps = %d\n", numDeps);
- for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
- const char* cacheFileName = getCacheFileName(cpe);
- const u1* signature = getSignature(cpe);
- size_t len = strlen(cacheFileName) +1;
- u4 storedStrLen;
-
- if (numDeps == 0) {
- /* more entries in bootclasspath than in deps list */
- LOGI("DexOpt: not all deps represented\n");
- goto bail;
- }
-
- storedStrLen = read4LE(&ptr);
- if (len != storedStrLen ||
- strcmp(cacheFileName, (const char*) ptr) != 0)
- {
- LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'\n",
- cacheFileName, ptr);
- goto bail;
- }
-
- ptr += storedStrLen;
-
- if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
- LOGI("DexOpt: mismatch dep signature for '%s'\n", cacheFileName);
- goto bail;
- }
- ptr += kSHA1DigestLen;
-
- LOGV("DexOpt: dep match on '%s'\n", cacheFileName);
-
- numDeps--;
- }
-
- if (numDeps != 0) {
- /* more entries in deps list than in classpath */
- LOGI("DexOpt: Some deps went away\n");
- goto bail;
- }
-
- // consumed all data and no more?
- if (ptr != depData + optHdr.depsLength) {
- LOGW("DexOpt: Spurious dep data? %d vs %d\n",
- (int) (ptr - depData), optHdr.depsLength);
- assert(false);
- }
-
- result = true;
-
-bail:
- free(depData);
- return result;
-}
-
-/*
- * Write the dependency info to "fd" at the current file position.
- */
-static int writeDependencies(int fd, u4 modWhen, u4 crc)
-{
- u1* buf = NULL;
- ssize_t actual;
- int result = -1;
- ssize_t bufLen;
- ClassPathEntry* cpe;
- int i, numDeps;
-
- /*
- * Count up the number of completed entries in the bootclasspath.
- */
- numDeps = 0;
- bufLen = 0;
- for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
- const char* cacheFileName = getCacheFileName(cpe);
- LOGV("+++ DexOpt: found dep '%s'\n", cacheFileName);
-
- numDeps++;
- bufLen += strlen(cacheFileName) +1;
- }
-
- bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
-
- buf = malloc(bufLen);
-
- set4LE(buf+0, modWhen);
- set4LE(buf+4, crc);
- set4LE(buf+8, DALVIK_VM_BUILD);
- set4LE(buf+12, numDeps);
-
- // TODO: do we want to add dvmGetInlineOpsTableLength() here? Won't
- // help us if somebody replaces an existing entry, but it'd catch
- // additions/removals.
-
- u1* ptr = buf + 4*4;
- for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
- const char* cacheFileName = getCacheFileName(cpe);
- const u1* signature = getSignature(cpe);
- int len = strlen(cacheFileName) +1;
-
- if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
- LOGE("DexOpt: overran buffer\n");
- dvmAbort();
- }
-
- set4LE(ptr, len);
- ptr += 4;
- memcpy(ptr, cacheFileName, len);
- ptr += len;
- memcpy(ptr, signature, kSHA1DigestLen);
- ptr += kSHA1DigestLen;
- }
-
- assert(ptr == buf + bufLen);
-
- actual = write(fd, buf, bufLen);
- if (actual != bufLen) {
- result = (errno != 0) ? errno : -1;
- logFailedWrite(bufLen, actual, "dep info", errno);
- } else {
- result = 0;
- }
-
- free(buf);
- return result;
-}
-
-
-/*
- * Write a block of data in "chunk" format.
- *
- * The chunk header fields are always in "native" byte order. If "size"
- * is not a multiple of 8 bytes, the data area is padded out.
- */
-static bool writeChunk(int fd, u4 type, const void* data, size_t size)
-{
- ssize_t actual;
- union { /* save a syscall by grouping these together */
- char raw[8];
- struct {
- u4 type;
- u4 size;
- } ts;
- } header;
-
- assert(sizeof(header) == 8);
-
- LOGV("Writing chunk, type=%.4s size=%d\n", (char*) &type, size);
-
- header.ts.type = type;
- header.ts.size = (u4) size;
- actual = write(fd, &header, sizeof(header));
- if (actual != sizeof(header)) {
- logFailedWrite(size, actual, "aux chunk header write", errno);
- return false;
- }
-
- if (size > 0) {
- actual = write(fd, data, size);
- if (actual != (ssize_t) size) {
- logFailedWrite(size, actual, "aux chunk write", errno);
- return false;
- }
- }
-
- /* if necessary, pad to 64-bit alignment */
- if ((size & 7) != 0) {
- int padSize = 8 - (size & 7);
- LOGV("size was %d, inserting %d pad bytes\n", size, padSize);
- lseek(fd, padSize, SEEK_CUR);
- }
-
- assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
-
- return true;
-}
-
-/*
- * Write aux data.
- *
- * We have different pieces, some of which may be optional. To make the
- * most effective use of space, we use a "chunk" format, with a 4-byte
- * type and a 4-byte length. We guarantee 64-bit alignment for the data,
- * so it can be used directly when the file is mapped for reading.
- */
-static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
- const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
-{
- /* pre-computed class lookup hash table */
- if (!writeChunk(fd, (u4) kDexChunkClassLookup,
- pClassLookup, pClassLookup->size))
- {
- return false;
- }
-
- /* remapped constants (optional) */
- if (pIndexMapSet != NULL) {
- if (!writeChunk(fd, pIndexMapSet->chunkType,
- pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
- {
- return false;
- }
- }
-
- /* register maps (optional) */
- if (pRegMapBuilder != NULL) {
- if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
- pRegMapBuilder->data, pRegMapBuilder->size))
- {
- return false;
- }
- }
-
- /* write the end marker */
- if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
- return false;
- }
-
- return true;
-}
-
-/*
- * Log a failed write.
- */
-static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
- int err)
-{
- LOGE("Write failed: %s (%d of %d): %s\n",
- msg, (int)actual, (int)expected, strerror(err));
-}
-
-/*
- * Compute a checksum on a piece of an open file.
- *
- * File will be positioned at end of checksummed area.
- *
- * Returns "true" on success.
- */
-static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
-{
- unsigned char readBuf[8192];
- ssize_t actual;
- uLong adler;
-
- if (lseek(fd, start, SEEK_SET) != start) {
- LOGE("Unable to seek to start of checksum area (%ld): %s\n",
- (long) start, strerror(errno));
- return false;
- }
-
- adler = adler32(0L, Z_NULL, 0);
-
- while (length != 0) {
- size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
- actual = read(fd, readBuf, wanted);
- if (actual <= 0) {
- LOGE("Read failed (%d) while computing checksum (len=%zu): %s\n",
- (int) actual, length, strerror(errno));
- return false;
- }
-
- adler = adler32(adler, readBuf, actual);
-
- length -= actual;
- }
-
- *pSum = adler;
- return true;
-}
-
-
-/*
- * ===========================================================================
- * Optimizations
- * ===========================================================================
- */
-
-/*
- * Perform in-place rewrites on a memory-mapped DEX file.
- *
- * This happens in a short-lived child process, so we can go nutty with
- * loading classes and allocating memory.
- */
-static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,
- u4* pHeaderFlags, DexClassLookup** ppClassLookup)
-{
- u8 prepWhen, loadWhen, verifyWhen, optWhen;
- DvmDex* pDvmDex = NULL;
- bool result = false;
-
- *pHeaderFlags = 0;
-
- LOGV("+++ swapping bytes\n");
- if (dexFixByteOrdering(addr, len) != 0)
- goto bail;
-#if __BYTE_ORDER != __LITTLE_ENDIAN
- *pHeaderFlags |= DEX_OPT_FLAG_BIG;
-#endif
-
- /*
- * Now that the DEX file can be read directly, create a DexFile for it.
- */
- if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
- LOGE("Unable to create DexFile\n");
- goto bail;
- }
-
- /*
- * Create the class lookup table.
- */
- //startWhen = dvmGetRelativeTimeUsec();
- *ppClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
- if (*ppClassLookup == NULL)
- goto bail;
-
- /*
- * Bail out early if they don't want The Works. The current implementation
- * doesn't fork a new process if this flag isn't set, so we really don't
- * want to continue on with the crazy class loading.
- */
- if (!doVerify && !doOpt) {
- result = true;
- goto bail;
- }
-
- /* this is needed for the next part */
- pDvmDex->pDexFile->pClassLookup = *ppClassLookup;
-
- prepWhen = dvmGetRelativeTimeUsec();
-
- /*
- * Load all classes found in this DEX file. If they fail to load for
- * some reason, they won't get verified (which is as it should be).
- */
- if (!loadAllClasses(pDvmDex))
- goto bail;
- loadWhen = dvmGetRelativeTimeUsec();
-
- /*
- * Verify all classes in the DEX file. Export the "is verified" flag
- * to the DEX file we're creating.
- */
- if (doVerify) {
- dvmVerifyAllClasses(pDvmDex->pDexFile);
- *pHeaderFlags |= DEX_FLAG_VERIFIED;
- }
- verifyWhen = dvmGetRelativeTimeUsec();
-
- /*
- * Optimize the classes we successfully loaded. If the opt mode is
- * OPTIMIZE_MODE_VERIFIED, each class must have been successfully
- * verified or we'll skip it.
- */
-#ifndef PROFILE_FIELD_ACCESS
- if (doOpt) {
- optimizeLoadedClasses(pDvmDex->pDexFile);
- *pHeaderFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
- }
-#endif
- optWhen = dvmGetRelativeTimeUsec();
-
- LOGD("DexOpt: load %dms, verify %dms, opt %dms\n",
- (int) (loadWhen - prepWhen) / 1000,
- (int) (verifyWhen - loadWhen) / 1000,
- (int) (optWhen - verifyWhen) / 1000);
-
- result = true;
-
-bail:
- /* free up storage */
- dvmDexFileFree(pDvmDex);
-
- return result;
-}
-
-/*
- * Update the Adler-32 checksum stored in the DEX file. This covers the
- * swapped and optimized DEX data, but does not include the opt header
- * or auxillary data.
- */
-static void updateChecksum(u1* addr, int len, DexHeader* pHeader)
-{
- /*
- * Rewrite the checksum. We leave the SHA-1 signature alone.
- */
- uLong adler = adler32(0L, Z_NULL, 0);
- const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
-
- adler = adler32(adler, addr + nonSum, len - nonSum);
- pHeader->checksum = adler;
-}
-
-/*
- * Try to load all classes in the specified DEX. If they have some sort
- * of broken dependency, e.g. their superclass lives in a different DEX
- * that wasn't previously loaded into the bootstrap class path, loading
- * will fail. This is the desired behavior.
- *
- * We have no notion of class loader at this point, so we load all of
- * the classes with the bootstrap class loader. It turns out this has
- * exactly the behavior we want, and has no ill side effects because we're
- * running in a separate process and anything we load here will be forgotten.
- *
- * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
- * This works because we only call here as part of optimization / pre-verify,
- * not during verification as part of loading a class into a running VM.
- *
- * This returns "false" if the world is too screwed up to do anything
- * useful at all.
- */
-static bool loadAllClasses(DvmDex* pDvmDex)
-{
- u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
- u4 idx;
- int loaded = 0;
-
- LOGV("DexOpt: +++ trying to load %d classes\n", count);
-
- dvmSetBootPathExtraDex(pDvmDex);
-
- /*
- * We have some circularity issues with Class and Object that are most
- * easily avoided by ensuring that Object is never the first thing we
- * try to find. Take care of that here. (We only need to do this when
- * loading classes from the DEX file that contains Object, and only
- * when Object comes first in the list, but it costs very little to
- * do it in all cases.)
- */
- if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) {
- LOGE("ERROR: java.lang.Class does not exist!\n");
- return false;
- }
-
- for (idx = 0; idx < count; idx++) {
- const DexClassDef* pClassDef;
- const char* classDescriptor;
- ClassObject* newClass;
-
- pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
- classDescriptor =
- dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
-
- LOGV("+++ loading '%s'", classDescriptor);
- //newClass = dvmDefineClass(pDexFile, classDescriptor,
- // NULL);
- newClass = dvmFindSystemClassNoInit(classDescriptor);
- if (newClass == NULL) {
- LOGV("DexOpt: failed loading '%s'\n", classDescriptor);
- dvmClearOptException(dvmThreadSelf());
- } else if (newClass->pDvmDex != pDvmDex) {
- /*
- * We don't load the new one, and we tag the first one found
- * with the "multiple def" flag so the resolver doesn't try
- * to make it available.
- */
- LOGD("DexOpt: '%s' has an earlier definition; blocking out\n",
- classDescriptor);
- SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
- } else {
- loaded++;
- }
- }
- LOGV("DexOpt: +++ successfully loaded %d classes\n", loaded);
-
- dvmSetBootPathExtraDex(NULL);
- return true;
-}
-
-
-/*
- * Create a table of inline substitutions.
- *
- * TODO: this is currently just a linear array. We will want to put this
- * into a hash table as the list size increases.
- */
-static InlineSub* createInlineSubsTable(void)
-{
- const InlineOperation* ops = dvmGetInlineOpsTable();
- const int count = dvmGetInlineOpsTableLength();
- InlineSub* table;
- Method* method;
- ClassObject* clazz;
- int i, tableIndex;
-
- /*
- * Allocate for optimism: one slot per entry, plus an end-of-list marker.
- */
- table = malloc(sizeof(InlineSub) * (count+1));
-
- tableIndex = 0;
- for (i = 0; i < count; i++) {
- clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL);
- if (clazz == NULL) {
- LOGV("DexOpt: can't inline for class '%s': not found\n",
- ops[i].classDescriptor);
- dvmClearOptException(dvmThreadSelf());
- } else {
- /*
- * Method could be virtual or direct. Try both. Don't use
- * the "hier" versions.
- */
- method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName,
- ops[i].methodSignature);
- if (method == NULL)
- method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName,
- ops[i].methodSignature);
- if (method == NULL) {
- LOGW("DexOpt: can't inline %s.%s %s: method not found\n",
- ops[i].classDescriptor, ops[i].methodName,
- ops[i].methodSignature);
- } else {
- if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
- LOGW("DexOpt: WARNING: inline op on non-final class/method "
- "%s.%s\n",
- clazz->descriptor, method->name);
- /* fail? */
- }
- if (dvmIsSynchronizedMethod(method) ||
- dvmIsDeclaredSynchronizedMethod(method))
- {
- LOGW("DexOpt: WARNING: inline op on synchronized method "
- "%s.%s\n",
- clazz->descriptor, method->name);
- /* fail? */
- }
-
- table[tableIndex].method = method;
- table[tableIndex].inlineIdx = i;
- tableIndex++;
-
- LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
- ops[i].classDescriptor, ops[i].methodName,
- ops[i].methodSignature);
- }
- }
- }
-
- /* mark end of table */
- table[tableIndex].method = NULL;
- LOGV("DexOpt: inline table has %d entries\n", tableIndex);
-
- return table;
-}
-
-/*
- * Run through all classes that were successfully loaded from this DEX
- * file and optimize their code sections.
- */
-static void optimizeLoadedClasses(DexFile* pDexFile)
-{
- u4 count = pDexFile->pHeader->classDefsSize;
- u4 idx;
- InlineSub* inlineSubs = NULL;
-
- LOGV("DexOpt: +++ optimizing up to %d classes\n", count);
- assert(gDvm.dexOptMode != OPTIMIZE_MODE_NONE);
-
- inlineSubs = createInlineSubsTable();
-
- for (idx = 0; idx < count; idx++) {
- const DexClassDef* pClassDef;
- const char* classDescriptor;
- ClassObject* clazz;
-
- pClassDef = dexGetClassDef(pDexFile, idx);
- classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-
- /* all classes are loaded into the bootstrap class loader */
- clazz = dvmLookupClass(classDescriptor, NULL, false);
- if (clazz != NULL) {
- if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) == 0 &&
- gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
- {
- LOGV("DexOpt: not optimizing '%s': not verified\n",
- classDescriptor);
- } else if (clazz->pDvmDex->pDexFile != pDexFile) {
- /* shouldn't be here -- verifier should have caught */
- LOGD("DexOpt: not optimizing '%s': multiple definitions\n",
- classDescriptor);
- } else {
- optimizeClass(clazz, inlineSubs);
-
- /* set the flag whether or not we actually did anything */
- ((DexClassDef*)pClassDef)->accessFlags |=
- CLASS_ISOPTIMIZED;
- }
- } else {
- LOGV("DexOpt: not optimizing unavailable class '%s'\n",
- classDescriptor);
- }
- }
-
- free(inlineSubs);
-}
-
-/*
- * Optimize the specified class.
- */
-static void optimizeClass(ClassObject* clazz, const InlineSub* inlineSubs)
-{
- int i;
-
- for (i = 0; i < clazz->directMethodCount; i++) {
- if (!optimizeMethod(&clazz->directMethods[i], inlineSubs))
- goto fail;
- }
- for (i = 0; i < clazz->virtualMethodCount; i++) {
- if (!optimizeMethod(&clazz->virtualMethods[i], inlineSubs))
- goto fail;
- }
-
- return;
-
-fail:
- LOGV("DexOpt: ceasing optimization attempts on %s\n", clazz->descriptor);
-}
-
-/*
- * Optimize instructions in a method.
- *
- * Returns "true" if all went well, "false" if we bailed out early when
- * something failed.
- */
-static bool optimizeMethod(Method* method, const InlineSub* inlineSubs)
-{
- u4 insnsSize;
- u2* insns;
- u2 inst;
-
- if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
- return true;
-
- insns = (u2*) method->insns;
- assert(insns != NULL);
- insnsSize = dvmGetMethodInsnsSize(method);
-
- while (insnsSize > 0) {
- int width;
-
- inst = *insns & 0xff;
-
- switch (inst) {
- case OP_IGET:
- case OP_IGET_BOOLEAN:
- case OP_IGET_BYTE:
- case OP_IGET_CHAR:
- case OP_IGET_SHORT:
- rewriteInstField(method, insns, OP_IGET_QUICK);
- break;
- case OP_IGET_WIDE:
- rewriteInstField(method, insns, OP_IGET_WIDE_QUICK);
- break;
- case OP_IGET_OBJECT:
- rewriteInstField(method, insns, OP_IGET_OBJECT_QUICK);
- break;
- case OP_IPUT:
- case OP_IPUT_BOOLEAN:
- case OP_IPUT_BYTE:
- case OP_IPUT_CHAR:
- case OP_IPUT_SHORT:
- rewriteInstField(method, insns, OP_IPUT_QUICK);
- break;
- case OP_IPUT_WIDE:
- rewriteInstField(method, insns, OP_IPUT_WIDE_QUICK);
- break;
- case OP_IPUT_OBJECT:
- rewriteInstField(method, insns, OP_IPUT_OBJECT_QUICK);
- break;
-
- case OP_INVOKE_VIRTUAL:
- if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL,inlineSubs))
- {
- if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK))
- return false;
- }
- break;
- case OP_INVOKE_VIRTUAL_RANGE:
- if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL,
- inlineSubs))
- {
- if (!rewriteVirtualInvoke(method, insns,
- OP_INVOKE_VIRTUAL_QUICK_RANGE))
- {
- return false;
- }
- }
- break;
- case OP_INVOKE_SUPER:
- if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK))
- return false;
- break;
- case OP_INVOKE_SUPER_RANGE:
- if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE))
- return false;
- break;
-
- case OP_INVOKE_DIRECT:
- if (!rewriteExecuteInline(method, insns, METHOD_DIRECT, inlineSubs))
- {
- if (!rewriteEmptyDirectInvoke(method, insns))
- return false;
- }
- break;
- case OP_INVOKE_DIRECT_RANGE:
- rewriteExecuteInlineRange(method, insns, METHOD_DIRECT, inlineSubs);
- break;
-
- case OP_INVOKE_STATIC:
- rewriteExecuteInline(method, insns, METHOD_STATIC, inlineSubs);
- break;
- case OP_INVOKE_STATIC_RANGE:
- rewriteExecuteInlineRange(method, insns, METHOD_STATIC, inlineSubs);
- break;
-
- default:
- // ignore this instruction
- ;
- }
-
- if (*insns == kPackedSwitchSignature) {
- width = 4 + insns[1] * 2;
- } else if (*insns == kSparseSwitchSignature) {
- width = 2 + insns[1] * 4;
- } else if (*insns == kArrayDataSignature) {
- u2 elemWidth = insns[1];
- u4 len = insns[2] | (((u4)insns[3]) << 16);
- width = 4 + (elemWidth * len + 1) / 2;
- } else {
- width = dexGetInstrWidth(gDvm.instrWidth, inst);
- }
- assert(width > 0);
-
- insns += width;
- insnsSize -= width;
- }
-
- assert(insnsSize == 0);
- return true;
-}
-
-
-/*
- * If "referrer" and "resClass" don't come from the same DEX file, and
- * the DEX we're working on is not destined for the bootstrap class path,
- * tweak the class loader so package-access checks work correctly.
- *
- * Only do this if we're doing pre-verification or optimization.
- */
-static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
-{
- if (!gDvm.optimizing)
- return;
- assert(referrer->classLoader == NULL);
- assert(resClass->classLoader == NULL);
-
- if (!gDvm.optimizingBootstrapClass) {
- /* class loader for an array class comes from element type */
- if (dvmIsArrayClass(resClass))
- resClass = resClass->elementClass;
- if (referrer->pDvmDex != resClass->pDvmDex)
- resClass->classLoader = (Object*) 0xdead3333;
- }
-}
-
-/*
- * Undo the effects of tweakLoader.
- */
-static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
-{
- if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
- return;
-
- if (dvmIsArrayClass(resClass))
- resClass = resClass->elementClass;
- resClass->classLoader = NULL;
-}
-
-
-/*
- * Alternate version of dvmResolveClass for use with verification and
- * optimization. Performs access checks on every resolve, and refuses
- * to acknowledge the existence of classes defined in more than one DEX
- * file.
- *
- * Exceptions caused by failures are cleared before returning.
- *
- * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
- */
-ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
- VerifyError* pFailure)
-{
- DvmDex* pDvmDex = referrer->pDvmDex;
- ClassObject* resClass;
-
- /*
- * Check the table first. If not there, do the lookup by name.
- */
- resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
- if (resClass == NULL) {
- const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
- if (className[0] != '\0' && className[1] == '\0') {
- /* primitive type */
- resClass = dvmFindPrimitiveClass(className[0]);
- } else {
- resClass = dvmFindClassNoInit(className, referrer->classLoader);
- }
- if (resClass == NULL) {
- /* not found, exception should be raised */
- LOGV("DexOpt: class %d (%s) not found\n",
- classIdx,
- dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
- if (pFailure != NULL) {
- /* dig through the wrappers to find the original failure */
- Object* excep = dvmGetException(dvmThreadSelf());
- while (true) {
- Object* cause = dvmGetExceptionCause(excep);
- if (cause == NULL)
- break;
- excep = cause;
- }
- if (strcmp(excep->clazz->descriptor,
- "Ljava/lang/IncompatibleClassChangeError;") == 0)
- {
- *pFailure = VERIFY_ERROR_CLASS_CHANGE;
- } else {
- *pFailure = VERIFY_ERROR_NO_CLASS;
- }
- }
- dvmClearOptException(dvmThreadSelf());
- return NULL;
- }
-
- /*
- * Add it to the resolved table so we're faster on the next lookup.
- */
- dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
- }
-
- /* multiple definitions? */
- if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
- LOGI("DexOpt: not resolving ambiguous class '%s'\n",
- resClass->descriptor);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_NO_CLASS;
- return NULL;
- }
-
- /* access allowed? */
- tweakLoader(referrer, resClass);
- bool allowed = dvmCheckClassAccess(referrer, resClass);
- untweakLoader(referrer, resClass);
- if (!allowed) {
- LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
- referrer->descriptor, resClass->descriptor);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_ACCESS_CLASS;
- return NULL;
- }
-
- return resClass;
-}
-
-/*
- * Alternate version of dvmResolveInstField().
- *
- * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
- */
-InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
- VerifyError* pFailure)
-{
- DvmDex* pDvmDex = referrer->pDvmDex;
- InstField* resField;
-
- resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
- if (resField == NULL) {
- const DexFieldId* pFieldId;
- ClassObject* resClass;
-
- pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
-
- /*
- * Find the field's class.
- */
- resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
- if (resClass == NULL) {
- //dvmClearOptException(dvmThreadSelf());
- assert(!dvmCheckException(dvmThreadSelf()));
- if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
- return NULL;
- }
-
- resField = (InstField*)dvmFindFieldHier(resClass,
- dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
- dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
- if (resField == NULL) {
- LOGD("DexOpt: couldn't find field %s.%s\n",
- resClass->descriptor,
- dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_NO_FIELD;
- return NULL;
- }
- if (dvmIsStaticField(&resField->field)) {
- LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
- resClass->descriptor,
- dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_CLASS_CHANGE;
- return NULL;
- }
-
- /*
- * Add it to the resolved table so we're faster on the next lookup.
- */
- dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
- }
-
- /* access allowed? */
- tweakLoader(referrer, resField->field.clazz);
- bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
- untweakLoader(referrer, resField->field.clazz);
- if (!allowed) {
- LOGI("DexOpt: access denied from %s to field %s.%s\n",
- referrer->descriptor, resField->field.clazz->descriptor,
- resField->field.name);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_ACCESS_FIELD;
- return NULL;
- }
-
- return resField;
-}
-
-/*
- * Alternate version of dvmResolveStaticField().
- *
- * Does not force initialization of the resolved field's class.
- *
- * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
- */
-StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
- VerifyError* pFailure)
-{
- DvmDex* pDvmDex = referrer->pDvmDex;
- StaticField* resField;
-
- resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
- if (resField == NULL) {
- const DexFieldId* pFieldId;
- ClassObject* resClass;
-
- pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
-
- /*
- * Find the field's class.
- */
- resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
- if (resClass == NULL) {
- //dvmClearOptException(dvmThreadSelf());
- assert(!dvmCheckException(dvmThreadSelf()));
- if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
- return NULL;
- }
-
- resField = (StaticField*)dvmFindFieldHier(resClass,
- dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
- dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
- if (resField == NULL) {
- LOGD("DexOpt: couldn't find static field\n");
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_NO_FIELD;
- return NULL;
- }
- if (!dvmIsStaticField(&resField->field)) {
- LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
- resClass->descriptor,
- dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_CLASS_CHANGE;
- return NULL;
- }
-
- /*
- * Add it to the resolved table so we're faster on the next lookup.
- *
- * We can only do this if we're in "dexopt", because the presence
- * of a valid value in the resolution table implies that the class
- * containing the static field has been initialized.
- */
- if (gDvm.optimizing)
- dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
- }
-
- /* access allowed? */
- tweakLoader(referrer, resField->field.clazz);
- bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
- untweakLoader(referrer, resField->field.clazz);
- if (!allowed) {
- LOGI("DexOpt: access denied from %s to field %s.%s\n",
- referrer->descriptor, resField->field.clazz->descriptor,
- resField->field.name);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_ACCESS_FIELD;
- return NULL;
- }
-
- return resField;
-}
-
-
-/*
- * Rewrite an iget/iput instruction. These all have the form:
- * op vA, vB, field@CCCC
- *
- * Where vA holds the value, vB holds the object reference, and CCCC is
- * the field reference constant pool offset. We want to replace CCCC
- * with the byte offset from the start of the object.
- *
- * "clazz" is the referring class. We need this because we verify
- * access rights here.
- */
-static void rewriteInstField(Method* method, u2* insns, OpCode newOpc)
-{
- ClassObject* clazz = method->clazz;
- u2 fieldIdx = insns[1];
- InstField* field;
- int byteOffset;
-
- field = dvmOptResolveInstField(clazz, fieldIdx, NULL);
- if (field == NULL) {
- LOGI("DexOpt: unable to optimize field ref 0x%04x at 0x%02x in %s.%s\n",
- fieldIdx, (int) (insns - method->insns), clazz->descriptor,
- method->name);
- return;
- }
-
- if (field->byteOffset >= 65536) {
- LOGI("DexOpt: field offset exceeds 64K (%d)\n", field->byteOffset);
- return;
- }
-
- insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
- insns[1] = (u2) field->byteOffset;
- LOGVV("DexOpt: rewrote access to %s.%s --> %d\n",
- field->field.clazz->descriptor, field->field.name,
- field->byteOffset);
-}
-
-/*
- * Alternate version of dvmResolveMethod().
- *
- * Doesn't throw exceptions, and checks access on every lookup.
- *
- * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
- */
-Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
- MethodType methodType, VerifyError* pFailure)
-{
- DvmDex* pDvmDex = referrer->pDvmDex;
- Method* resMethod;
-
- assert(methodType == METHOD_DIRECT ||
- methodType == METHOD_VIRTUAL ||
- methodType == METHOD_STATIC);
-
- LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
- referrer->descriptor);
-
- resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
- if (resMethod == NULL) {
- const DexMethodId* pMethodId;
- ClassObject* resClass;
-
- pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
-
- resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
- if (resClass == NULL) {
- /*
- * Can't find the class that the method is a part of, or don't
- * have permission to access the class.
- */
- LOGV("DexOpt: can't find called method's class (?.%s)\n",
- dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
- if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
- return NULL;
- }
- if (dvmIsInterfaceClass(resClass)) {
- /* method is part of an interface; this is wrong method for that */
- LOGW("DexOpt: method is in an interface\n");
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_GENERIC;
- return NULL;
- }
-
- /*
- * We need to chase up the class hierarchy to find methods defined
- * in super-classes. (We only want to check the current class
- * if we're looking for a constructor.)
- */
- DexProto proto;
- dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
-
- if (methodType == METHOD_DIRECT) {
- resMethod = dvmFindDirectMethod(resClass,
- dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
- } else {
- /* METHOD_STATIC or METHOD_VIRTUAL */
- resMethod = dvmFindMethodHier(resClass,
- dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
- }
-
- if (resMethod == NULL) {
- LOGV("DexOpt: couldn't find method '%s'\n",
- dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_NO_METHOD;
- return NULL;
- }
- if (methodType == METHOD_STATIC) {
- if (!dvmIsStaticMethod(resMethod)) {
- LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
- resClass->descriptor, resMethod->name);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_CLASS_CHANGE;
- return NULL;
- }
- } else if (methodType == METHOD_VIRTUAL) {
- if (dvmIsStaticMethod(resMethod)) {
- LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
- resClass->descriptor, resMethod->name);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_CLASS_CHANGE;
- return NULL;
- }
- }
-
- /* see if this is a pure-abstract method */
- if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
- LOGW("DexOpt: pure-abstract method '%s' in %s\n",
- dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
- resClass->descriptor);
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_GENERIC;
- return NULL;
- }
-
- /*
- * Add it to the resolved table so we're faster on the next lookup.
- *
- * We can only do this for static methods if we're not in "dexopt",
- * because the presence of a valid value in the resolution table
- * implies that the class containing the static field has been
- * initialized.
- */
- if (methodType != METHOD_STATIC || gDvm.optimizing)
- dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
- }
-
- LOGVV("--- found method %d (%s.%s)\n",
- methodIdx, resMethod->clazz->descriptor, resMethod->name);
-
- /* access allowed? */
- tweakLoader(referrer, resMethod->clazz);
- bool allowed = dvmCheckMethodAccess(referrer, resMethod);
- untweakLoader(referrer, resMethod->clazz);
- if (!allowed) {
- IF_LOGI() {
- char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
- LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
- resMethod->clazz->descriptor, resMethod->name, desc,
- referrer->descriptor);
- free(desc);
- }
- if (pFailure != NULL)
- *pFailure = VERIFY_ERROR_ACCESS_METHOD;
- return NULL;
- }
-
- return resMethod;
-}
-
-/*
- * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
- * invoke-super/range. These all have the form:
- * op vAA, meth@BBBB, reg stuff @CCCC
- *
- * We want to replace the method constant pool index BBBB with the
- * vtable index.
- */
-static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
-{
- ClassObject* clazz = method->clazz;
- Method* baseMethod;
- u2 methodIdx = insns[1];
-
- baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
- if (baseMethod == NULL) {
- LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
- methodIdx,
- (int) (insns - method->insns), clazz->descriptor,
- method->name);
- return false;
- }
-
- assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
- (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
- (insns[0] & 0xff) == OP_INVOKE_SUPER ||
- (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
-
- /*
- * Note: Method->methodIndex is a u2 and is range checked during the
- * initial load.
- */
- insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
- insns[1] = baseMethod->methodIndex;
-
- //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
- // method->clazz->descriptor, method->name,
- // baseMethod->clazz->descriptor, baseMethod->name);
-
- return true;
-}
-
-/*
- * Rewrite invoke-direct, which has the form:
- * op vAA, meth@BBBB, reg stuff @CCCC
- *
- * There isn't a lot we can do to make this faster, but in some situations
- * we can make it go away entirely.
- *
- * This must only be used when the invoked method does nothing and has
- * no return value (the latter being very important for verification).
- */
-static bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
-{
- ClassObject* clazz = method->clazz;
- Method* calledMethod;
- u2 methodIdx = insns[1];
-
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
- if (calledMethod == NULL) {
- LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
- methodIdx,
- (int) (insns - method->insns), clazz->descriptor,
- method->name);
- return false;
- }
-
- /* TODO: verify that java.lang.Object() is actually empty! */
- if (calledMethod->clazz == gDvm.classJavaLangObject &&
- dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
- {
- /*
- * Replace with "empty" instruction. DO NOT disturb anything
- * else about it, as we want it to function the same as
- * OP_INVOKE_DIRECT when debugging is enabled.
- */
- assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
- insns[0] = (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY;
-
- //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
- // method->clazz->descriptor, method->name,
- // calledMethod->clazz->descriptor, calledMethod->name);
- }
-
- return true;
-}
-
-/*
- * Resolve an interface method reference.
- *
- * No method access check here -- interface methods are always public.
- *
- * Returns NULL if the method was not found. Does not throw an exception.
- */
-Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
-{
- DvmDex* pDvmDex = referrer->pDvmDex;
- Method* resMethod;
- int i;
-
- LOGVV("--- resolving interface method %d (referrer=%s)\n",
- methodIdx, referrer->descriptor);
-
- resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
- if (resMethod == NULL) {
- const DexMethodId* pMethodId;
- ClassObject* resClass;
-
- pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
-
- resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
- if (resClass == NULL) {
- /* can't find the class that the method is a part of */
- dvmClearOptException(dvmThreadSelf());
- return NULL;
- }
- if (!dvmIsInterfaceClass(resClass)) {
- /* whoops */
- LOGI("Interface method not part of interface class\n");
- return NULL;
- }
-
- const char* methodName =
- dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
- DexProto proto;
- dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
-
- LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
- methodName, methodSig, resClass->descriptor);
- resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
- if (resMethod == NULL) {
- /* scan superinterfaces and superclass interfaces */
- LOGVV("+++ did not resolve immediately\n");
- for (i = 0; i < resClass->iftableCount; i++) {
- resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
- methodName, &proto);
- if (resMethod != NULL)
- break;
- }
-
- if (resMethod == NULL) {
- LOGVV("+++ unable to resolve method %s\n", methodName);
- return NULL;
- }
- } else {
- LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
- resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
- }
-
- /* we're expecting this to be abstract */
- if (!dvmIsAbstractMethod(resMethod)) {
- char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
- LOGW("Found non-abstract interface method %s.%s %s\n",
- resMethod->clazz->descriptor, resMethod->name, desc);
- free(desc);
- return NULL;
- }
-
- /*
- * Add it to the resolved table so we're faster on the next lookup.
- */
- dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
- }
-
- LOGVV("--- found interface method %d (%s.%s)\n",
- methodIdx, resMethod->clazz->descriptor, resMethod->name);
-
- /* interface methods are always public; no need to check access */
-
- return resMethod;
-}
-
-/*
- * See if the method being called can be rewritten as an inline operation.
- * Works for invoke-virtual, invoke-direct, and invoke-static.
- *
- * Returns "true" if we replace it.
- */
-static bool rewriteExecuteInline(Method* method, u2* insns,
- MethodType methodType, const InlineSub* inlineSubs)
-{
- ClassObject* clazz = method->clazz;
- Method* calledMethod;
- u2 methodIdx = insns[1];
-
- //return false;
-
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
- if (calledMethod == NULL) {
- LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
- return false;
- }
-
- while (inlineSubs->method != NULL) {
- /*
- if (extra) {
- LOGI("comparing %p vs %p %s.%s %s\n",
- inlineSubs->method, calledMethod,
- inlineSubs->method->clazz->descriptor,
- inlineSubs->method->name,
- inlineSubs->method->signature);
- }
- */
- if (inlineSubs->method == calledMethod) {
- assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
- (insns[0] & 0xff) == OP_INVOKE_STATIC ||
- (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
- insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE;
- insns[1] = (u2) inlineSubs->inlineIdx;
-
- //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
- // method->clazz->descriptor, method->name,
- // calledMethod->clazz->descriptor, calledMethod->name);
- return true;
- }
-
- inlineSubs++;
- }
-
- return false;
-}
-
-/*
- * See if the method being called can be rewritten as an inline operation.
- * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
- *
- * Returns "true" if we replace it.
- */
-static bool rewriteExecuteInlineRange(Method* method, u2* insns,
- MethodType methodType, const InlineSub* inlineSubs)
-{
- ClassObject* clazz = method->clazz;
- Method* calledMethod;
- u2 methodIdx = insns[1];
-
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
- if (calledMethod == NULL) {
- LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
- return false;
- }
-
- while (inlineSubs->method != NULL) {
- if (inlineSubs->method == calledMethod) {
- assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
- (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
- (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
- insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE;
- insns[1] = (u2) inlineSubs->inlineIdx;
-
- //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
- // method->clazz->descriptor, method->name,
- // calledMethod->clazz->descriptor, calledMethod->name);
- return true;
- }
-
- inlineSubs++;
- }
-
- return false;
-}
-
diff --git a/vm/analysis/DexPrepare.c b/vm/analysis/DexPrepare.c
new file mode 100644
index 0000000..d9871c9
--- /dev/null
+++ b/vm/analysis/DexPrepare.c
@@ -0,0 +1,1442 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Prepare a DEX file for use by the VM. Depending upon the VM options
+ * we will attempt to verify and/or optimize the code, possibly appending
+ * register maps.
+ *
+ * TODO: the format of the optimized header is currently "whatever we
+ * happen to write", since the VM that writes it is by definition the same
+ * as the VM that reads it. Still, it should be better documented and
+ * more rigorously structured.
+ */
+#include "Dalvik.h"
+#include "libdex/OptInvocation.h"
+#include "analysis/RegisterMap.h"
+#include "analysis/Optimize.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+/* fwd */
+static bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
+ DexClassLookup** ppClassLookup);
+static bool loadAllClasses(DvmDex* pDvmDex);
+static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
+ bool doOpt);
+static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
+ const DexClassDef* pClassDef, bool doVerify, bool doOpt);
+static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
+static int writeDependencies(int fd, u4 modWhen, u4 crc);
+static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
+ const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
+static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
+
+
+/*
+ * Return the fd of an open file in the DEX file cache area. If the cache
+ * file doesn't exist or is out of date, this will remove the old entry,
+ * create a new one (writing only the file header), and return with the
+ * "new file" flag set.
+ *
+ * It's possible to execute from an unoptimized DEX file directly,
+ * assuming the byte ordering and structure alignment is correct, but
+ * disadvantageous because some significant optimizations are not possible.
+ * It's not generally possible to do the same from an uncompressed Jar
+ * file entry, because we have to guarantee 32-bit alignment in the
+ * memory-mapped file.
+ *
+ * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
+ * and "crc32" come from the Zip directory entry. For a stand-alone DEX
+ * file, it's the modification date of the file and the Adler32 from the
+ * DEX header (which immediately follows the magic). If these don't
+ * match what's stored in the opt header, we reject the file immediately.
+ *
+ * On success, the file descriptor will be positioned just past the "opt"
+ * file header, and will be locked with flock. "*pCachedName" will point
+ * to newly-allocated storage.
+ */
+int dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
+ u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
+{
+ int fd, cc;
+ struct stat fdStat, fileStat;
+ bool readOnly = false;
+
+ *pNewFile = false;
+
+retry:
+ /*
+ * Try to open the cache file. If we've been asked to,
+ * create it if it doesn't exist.
+ */
+ fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
+ if (fd < 0) {
+ fd = open(cacheFileName, O_RDONLY, 0);
+ if (fd < 0) {
+ if (createIfMissing) {
+ LOGE("Can't open dex cache '%s': %s\n",
+ cacheFileName, strerror(errno));
+ }
+ return fd;
+ }
+ readOnly = true;
+ }
+
+ /*
+ * Grab an exclusive lock on the cache file. If somebody else is
+ * working on it, we'll block here until they complete. Because
+ * we're waiting on an external resource, we go into VMWAIT mode.
+ */
+ int oldStatus;
+ LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)\n",
+ cacheFileName, fd, isBootstrap);
+ oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
+ cc = flock(fd, LOCK_EX | LOCK_NB);
+ if (cc != 0) {
+ LOGD("DexOpt: sleeping on flock(%s)\n", cacheFileName);
+ cc = flock(fd, LOCK_EX);
+ }
+ dvmChangeStatus(NULL, oldStatus);
+ if (cc != 0) {
+ LOGE("Can't lock dex cache '%s': %d\n", cacheFileName, cc);
+ close(fd);
+ return -1;
+ }
+ LOGV("DexOpt: locked cache file\n");
+
+ /*
+ * Check to see if the fd we opened and locked matches the file in
+ * the filesystem. If they don't, then somebody else unlinked ours
+ * and created a new file, and we need to use that one instead. (If
+ * we caught them between the unlink and the create, we'll get an
+ * ENOENT from the file stat.)
+ */
+ cc = fstat(fd, &fdStat);
+ if (cc != 0) {
+ LOGE("Can't stat open file '%s'\n", cacheFileName);
+ LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
+ goto close_fail;
+ }
+ cc = stat(cacheFileName, &fileStat);
+ if (cc != 0 ||
+ fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
+ {
+ LOGD("DexOpt: our open cache file is stale; sleeping and retrying\n");
+ LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
+ flock(fd, LOCK_UN);
+ close(fd);
+ usleep(250 * 1000); /* if something is hosed, don't peg machine */
+ goto retry;
+ }
+
+ /*
+ * We have the correct file open and locked. If the file size is zero,
+ * then it was just created by us, and we want to fill in some fields
+ * in the "opt" header and set "*pNewFile". Otherwise, we want to
+ * verify that the fields in the header match our expectations, and
+ * reset the file if they don't.
+ */
+ if (fdStat.st_size == 0) {
+ if (readOnly) {
+ LOGW("DexOpt: file has zero length and isn't writable\n");
+ goto close_fail;
+ }
+ cc = dexOptCreateEmptyHeader(fd);
+ if (cc != 0)
+ goto close_fail;
+ *pNewFile = true;
+ LOGV("DexOpt: successfully initialized new cache file\n");
+ } else {
+ bool expectVerify, expectOpt;
+
+ if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
+ expectVerify = false;
+ else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
+ expectVerify = !isBootstrap;
+ else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
+ expectVerify = true;
+
+ if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
+ expectOpt = false;
+ else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
+ expectOpt = expectVerify;
+ else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
+ expectOpt = true;
+
+ LOGV("checking deps, expecting vfy=%d opt=%d\n",
+ expectVerify, expectOpt);
+
+ if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
+ expectVerify, expectOpt))
+ {
+ if (readOnly) {
+ /*
+ * We could unlink and rewrite the file if we own it or
+ * the "sticky" bit isn't set on the directory. However,
+ * we're not able to truncate it, which spoils things. So,
+ * give up now.
+ */
+ if (createIfMissing) {
+ LOGW("Cached DEX '%s' (%s) is stale and not writable\n",
+ fileName, cacheFileName);
+ }
+ goto close_fail;
+ }
+
+ /*
+ * If we truncate the existing file before unlinking it, any
+ * process that has it mapped will fail when it tries to touch
+ * the pages.
+ *
+ * This is very important. The zygote process will have the
+ * boot DEX files (core, framework, etc.) mapped early. If
+ * (say) core.dex gets updated, and somebody launches an app
+ * that uses App.dex, then App.dex gets reoptimized because it's
+ * dependent upon the boot classes. However, dexopt will be
+ * using the *new* core.dex to do the optimizations, while the
+ * app will actually be running against the *old* core.dex
+ * because it starts from zygote.
+ *
+ * Even without zygote, it's still possible for a class loader
+ * to pull in an APK that was optimized against an older set
+ * of DEX files. We must ensure that everything fails when a
+ * boot DEX gets updated, and for general "why aren't my
+ * changes doing anything" purposes its best if we just make
+ * everything crash when a DEX they're using gets updated.
+ */
+ LOGD("Stale deps in cache file; removing and retrying\n");
+ if (ftruncate(fd, 0) != 0) {
+ LOGW("Warning: unable to truncate cache file '%s': %s\n",
+ cacheFileName, strerror(errno));
+ /* keep going */
+ }
+ if (unlink(cacheFileName) != 0) {
+ LOGW("Warning: unable to remove cache file '%s': %d %s\n",
+ cacheFileName, errno, strerror(errno));
+ /* keep going; permission failure should probably be fatal */
+ }
+ LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
+ flock(fd, LOCK_UN);
+ close(fd);
+ goto retry;
+ } else {
+ LOGV("DexOpt: good deps in cache file\n");
+ }
+ }
+
+ assert(fd >= 0);
+ return fd;
+
+close_fail:
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+}
+
+/*
+ * Unlock the file descriptor.
+ *
+ * Returns "true" on success.
+ */
+bool dvmUnlockCachedDexFile(int fd)
+{
+ LOGVV("DexOpt: unlocking cache file fd=%d\n", fd);
+ return (flock(fd, LOCK_UN) == 0);
+}
+
+
+/*
+ * Given a descriptor for a file with DEX data in it, produce an
+ * optimized version.
+ *
+ * The file pointed to by "fd" is expected to be a locked shared resource
+ * (or private); we make no efforts to enforce multi-process correctness
+ * here.
+ *
+ * "fileName" is only used for debug output. "modWhen" and "crc" are stored
+ * in the dependency set.
+ *
+ * The "isBootstrap" flag determines how the optimizer and verifier handle
+ * package-scope access checks. When optimizing, we only load the bootstrap
+ * class DEX files and the target DEX, so the flag determines whether the
+ * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
+ * This only really matters if the target DEX contains classes that claim to
+ * be in the same package as bootstrap classes.
+ *
+ * The optimizer will need to load every class in the target DEX file.
+ * This is generally undesirable, so we start a subprocess to do the
+ * work and wait for it to complete.
+ *
+ * Returns "true" on success. All data will have been written to "fd".
+ */
+bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
+ const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
+{
+ const char* lastPart = strrchr(fileName, '/');
+ if (lastPart != NULL)
+ lastPart++;
+ else
+ lastPart = fileName;
+
+ LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---\n", lastPart, isBootstrap);
+
+ pid_t pid;
+
+ /*
+ * This could happen if something in our bootclasspath, which we thought
+ * was all optimized, got rejected.
+ */
+ if (gDvm.optimizing) {
+ LOGW("Rejecting recursive optimization attempt on '%s'\n", fileName);
+ return false;
+ }
+
+ pid = fork();
+ if (pid == 0) {
+ static const int kUseValgrind = 0;
+ static const char* kDexOptBin = "/bin/dexopt";
+ static const char* kValgrinder = "/usr/bin/valgrind";
+ static const int kFixedArgCount = 10;
+ static const int kValgrindArgCount = 5;
+ static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8dig
+ int bcpSize = dvmGetBootPathSize();
+ int argc = kFixedArgCount + bcpSize
+ + (kValgrindArgCount * kUseValgrind);
+ char* argv[argc+1]; // last entry is NULL
+ char values[argc][kMaxIntLen];
+ char* execFile;
+ char* androidRoot;
+ int flags;
+
+ /* change process groups, so we don't clash with ProcessManager */
+ setpgid(0, 0);
+
+ /* full path to optimizer */
+ androidRoot = getenv("ANDROID_ROOT");
+ if (androidRoot == NULL) {
+ LOGW("ANDROID_ROOT not set, defaulting to /system\n");
+ androidRoot = "/system";
+ }
+ execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
+ strcpy(execFile, androidRoot);
+ strcat(execFile, kDexOptBin);
+
+ /*
+ * Create arg vector.
+ */
+ int curArg = 0;
+
+ if (kUseValgrind) {
+ /* probably shouldn't ship the hard-coded path */
+ argv[curArg++] = (char*)kValgrinder;
+ argv[curArg++] = "--tool=memcheck";
+ argv[curArg++] = "--leak-check=yes"; // check for leaks too
+ argv[curArg++] = "--leak-resolution=med"; // increase from 2 to 4
+ argv[curArg++] = "--num-callers=16"; // default is 12
+ assert(curArg == kValgrindArgCount);
+ }
+ argv[curArg++] = execFile;
+
+ argv[curArg++] = "--dex";
+
+ sprintf(values[2], "%d", DALVIK_VM_BUILD);
+ argv[curArg++] = values[2];
+
+ sprintf(values[3], "%d", fd);
+ argv[curArg++] = values[3];
+
+ sprintf(values[4], "%d", (int) dexOffset);
+ argv[curArg++] = values[4];
+
+ sprintf(values[5], "%d", (int) dexLength);
+ argv[curArg++] = values[5];
+
+ argv[curArg++] = (char*)fileName;
+
+ sprintf(values[7], "%d", (int) modWhen);
+ argv[curArg++] = values[7];
+
+ sprintf(values[8], "%d", (int) crc);
+ argv[curArg++] = values[8];
+
+ flags = 0;
+ if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
+ flags |= DEXOPT_OPT_ENABLED;
+ if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
+ flags |= DEXOPT_OPT_ALL;
+ }
+ if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
+ flags |= DEXOPT_VERIFY_ENABLED;
+ if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
+ flags |= DEXOPT_VERIFY_ALL;
+ }
+ if (isBootstrap)
+ flags |= DEXOPT_IS_BOOTSTRAP;
+ if (gDvm.generateRegisterMaps)
+ flags |= DEXOPT_GEN_REGISTER_MAP;
+ sprintf(values[9], "%d", flags);
+ argv[curArg++] = values[9];
+
+ assert(((!kUseValgrind && curArg == kFixedArgCount) ||
+ ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
+
+ ClassPathEntry* cpe;
+ for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+ argv[curArg++] = cpe->fileName;
+ }
+ assert(curArg == argc);
+
+ argv[curArg] = NULL;
+
+ if (kUseValgrind)
+ execv(kValgrinder, argv);
+ else
+ execv(execFile, argv);
+
+ LOGE("execv '%s'%s failed: %s\n", execFile,
+ kUseValgrind ? " [valgrind]" : "", strerror(errno));
+ exit(1);
+ } else {
+ LOGV("DexOpt: waiting for verify+opt, pid=%d\n", (int) pid);
+ int status;
+ pid_t gotPid;
+ int oldStatus;
+
+ /*
+ * Wait for the optimization process to finish. We go into VMWAIT
+ * mode here so GC suspension won't have to wait for us.
+ */
+ oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
+ while (true) {
+ gotPid = waitpid(pid, &status, 0);
+ if (gotPid == -1 && errno == EINTR) {
+ LOGD("waitpid interrupted, retrying\n");
+ } else {
+ break;
+ }
+ }
+ dvmChangeStatus(NULL, oldStatus);
+ if (gotPid != pid) {
+ LOGE("waitpid failed: wanted %d, got %d: %s\n",
+ (int) pid, (int) gotPid, strerror(errno));
+ return false;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ LOGD("DexOpt: --- END '%s' (success) ---\n", lastPart);
+ return true;
+ } else {
+ LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed\n",
+ lastPart, status);
+ return false;
+ }
+ }
+}
+
+/*
+ * Do the actual optimization. This is executed in the dexopt process.
+ *
+ * For best use of disk/memory, we want to extract once and perform
+ * optimizations in place. If the file has to expand or contract
+ * to match local structure padding/alignment expectations, we want
+ * to do the rewrite as part of the extract, rather than extracting
+ * into a temp file and slurping it back out. (The structure alignment
+ * is currently correct for all platforms, and this isn't expected to
+ * change, so we should be okay with having it already extracted.)
+ *
+ * Returns "true" on success.
+ */
+bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
+ const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
+{
+ DexClassLookup* pClassLookup = NULL;
+ IndexMapSet* pIndexMapSet = NULL;
+ RegisterMapBuilder* pRegMapBuilder = NULL;
+ u4 headerFlags = 0;
+
+ assert(gDvm.optimizing);
+
+ LOGV("Continuing optimization (%s, isb=%d, vfy=%d, opt=%d)\n",
+ fileName, isBootstrap, doVerify, doOpt);
+
+ assert(dexOffset >= 0);
+
+ /* quick test so we don't blow up on empty file */
+ if (dexLength < (int) sizeof(DexHeader)) {
+ LOGE("too small to be DEX\n");
+ return false;
+ }
+ if (dexOffset < (int) sizeof(DexOptHeader)) {
+ LOGE("not enough room for opt header\n");
+ return false;
+ }
+
+ bool result = false;
+
+ /*
+ * Drop this into a global so we don't have to pass it around. We could
+ * also add a field to DexFile, but since it only pertains to DEX
+ * creation that probably doesn't make sense.
+ */
+ gDvm.optimizingBootstrapClass = isBootstrap;
+
+ {
+ /*
+ * Map the entire file (so we don't have to worry about page
+ * alignment). The expectation is that the output file contains
+ * our DEX data plus room for a small header.
+ */
+ bool success;
+ void* mapAddr;
+ mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (mapAddr == MAP_FAILED) {
+ LOGE("unable to mmap DEX cache: %s\n", strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Rewrite the file. Byte reordering, structure realigning,
+ * class verification, and bytecode optimization are all performed
+ * here.
+ *
+ * In theory the file could change size and bits could shift around.
+ * In practice this would be annoying to deal with, so the file
+ * layout is designed so that it can always be rewritten in place.
+ *
+ * This sets "headerFlags" and creates the class lookup table as
+ * part of doing the processing.
+ */
+ success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
+ &headerFlags, &pClassLookup);
+
+ if (success) {
+ DvmDex* pDvmDex = NULL;
+ u1* dexAddr = ((u1*) mapAddr) + dexOffset;
+
+ if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
+ LOGE("Unable to create DexFile\n");
+ success = false;
+ } else {
+ /*
+ * If configured to do so, scan the instructions, looking
+ * for ways to reduce the size of the resolved-constant table.
+ * This is done post-optimization, across the instructions
+ * in all methods in all classes (even the ones that failed
+ * to load).
+ */
+ pIndexMapSet = dvmRewriteConstants(pDvmDex);
+
+ /*
+ * If configured to do so, generate register map output
+ * for all verified classes. The register maps were
+ * generated during verification, and will now be serialized.
+ */
+ if (gDvm.generateRegisterMaps) {
+ pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
+ if (pRegMapBuilder == NULL) {
+ LOGE("Failed generating register maps\n");
+ success = false;
+ }
+ }
+
+ DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
+ updateChecksum(dexAddr, dexLength, pHeader);
+
+ dvmDexFileFree(pDvmDex);
+ }
+ }
+
+ /* unmap the read-write version, forcing writes to disk */
+ if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
+ LOGW("msync failed: %s\n", strerror(errno));
+ // weird, but keep going
+ }
+#if 1
+ /*
+ * This causes clean shutdown to fail, because we have loaded classes
+ * that point into it. For the optimizer this isn't a problem,
+ * because it's more efficient for the process to simply exit.
+ * Exclude this code when doing clean shutdown for valgrind.
+ */
+ if (munmap(mapAddr, dexOffset + dexLength) != 0) {
+ LOGE("munmap failed: %s\n", strerror(errno));
+ goto bail;
+ }
+#endif
+
+ if (!success)
+ goto bail;
+ }
+
+ /* get start offset, and adjust deps start for 64-bit alignment */
+ off_t depsOffset, auxOffset, endOffset, adjOffset;
+ int depsLength, auxLength;
+ u4 optChecksum;
+
+ depsOffset = lseek(fd, 0, SEEK_END);
+ if (depsOffset < 0) {
+ LOGE("lseek to EOF failed: %s\n", strerror(errno));
+ goto bail;
+ }
+ adjOffset = (depsOffset + 7) & ~(0x07);
+ if (adjOffset != depsOffset) {
+ LOGV("Adjusting deps start from %d to %d\n",
+ (int) depsOffset, (int) adjOffset);
+ depsOffset = adjOffset;
+ lseek(fd, depsOffset, SEEK_SET);
+ }
+
+ /*
+ * Append the dependency list.
+ */
+ if (writeDependencies(fd, modWhen, crc) != 0) {
+ LOGW("Failed writing dependencies\n");
+ goto bail;
+ }
+
+ /* compute deps length, then adjust aux start for 64-bit alignment */
+ auxOffset = lseek(fd, 0, SEEK_END);
+ depsLength = auxOffset - depsOffset;
+
+ adjOffset = (auxOffset + 7) & ~(0x07);
+ if (adjOffset != auxOffset) {
+ LOGV("Adjusting aux start from %d to %d\n",
+ (int) auxOffset, (int) adjOffset);
+ auxOffset = adjOffset;
+ lseek(fd, auxOffset, SEEK_SET);
+ }
+
+ /*
+ * Append any auxillary pre-computed data structures.
+ */
+ if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
+ LOGW("Failed writing aux data\n");
+ goto bail;
+ }
+
+ endOffset = lseek(fd, 0, SEEK_END);
+ auxLength = endOffset - auxOffset;
+
+ /* compute checksum from start of deps to end of aux area */
+ if (!computeFileChecksum(fd, depsOffset,
+ (auxOffset+auxLength) - depsOffset, &optChecksum))
+ {
+ goto bail;
+ }
+
+ /*
+ * Output the "opt" header with all values filled in and a correct
+ * magic number.
+ */
+ DexOptHeader optHdr;
+ memset(&optHdr, 0xff, sizeof(optHdr));
+ memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
+ memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
+ optHdr.dexOffset = (u4) dexOffset;
+ optHdr.dexLength = (u4) dexLength;
+ optHdr.depsOffset = (u4) depsOffset;
+ optHdr.depsLength = (u4) depsLength;
+ optHdr.auxOffset = (u4) auxOffset;
+ optHdr.auxLength = (u4) auxLength;
+
+ optHdr.flags = headerFlags;
+ optHdr.checksum = optChecksum;
+
+ lseek(fd, 0, SEEK_SET);
+ if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
+ goto bail;
+
+ LOGV("Successfully wrote DEX header\n");
+ result = true;
+
+ //dvmRegisterMapDumpStats();
+
+bail:
+ dvmFreeIndexMapSet(pIndexMapSet);
+ dvmFreeRegisterMapBuilder(pRegMapBuilder);
+ free(pClassLookup);
+ return result;
+}
+
+
+/*
+ * Perform in-place rewrites on a memory-mapped DEX file.
+ *
+ * This happens in a short-lived child process, so we can go nutty with
+ * loading classes and allocating memory.
+ */
+static bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
+ DexClassLookup** ppClassLookup)
+{
+ u8 prepWhen, loadWhen, verifyOptWhen;
+ DvmDex* pDvmDex = NULL;
+ bool doVerify, doOpt;
+ bool result = false;
+
+ *pHeaderFlags = 0;
+
+ /* if the DEX is in the wrong byte order, swap it now */
+ if (dexSwapAndVerify(addr, len) != 0)
+ goto bail;
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+ *pHeaderFlags |= DEX_OPT_FLAG_BIG;
+#endif
+
+ if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
+ doVerify = false;
+ else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
+ doVerify = !gDvm.optimizingBootstrapClass;
+ else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
+ doVerify = true;
+
+ if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
+ doOpt = false;
+ else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
+ doOpt = doVerify;
+ else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
+ doOpt = true;
+
+ /* TODO: decide if this is actually useful */
+ if (doVerify)
+ *pHeaderFlags |= DEX_FLAG_VERIFIED;
+ if (doOpt)
+ *pHeaderFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
+
+ /*
+ * Now that the DEX file can be read directly, create a DexFile struct
+ * for it.
+ */
+ if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
+ LOGE("Unable to create DexFile\n");
+ goto bail;
+ }
+
+ /*
+ * Create the class lookup table. This will eventually be appended
+ * to the end of the .odex.
+ */
+ *ppClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
+ if (*ppClassLookup == NULL)
+ goto bail;
+
+ /*
+ * If we're not going to attempt to verify or optimize the classes,
+ * there's no value in loading them, so bail out early.
+ */
+ if (!doVerify && !doOpt) {
+ result = true;
+ goto bail;
+ }
+
+ /* this is needed for the next part */
+ pDvmDex->pDexFile->pClassLookup = *ppClassLookup;
+
+ prepWhen = dvmGetRelativeTimeUsec();
+
+ /*
+ * Load all classes found in this DEX file. If they fail to load for
+ * some reason, they won't get verified (which is as it should be).
+ */
+ if (!loadAllClasses(pDvmDex))
+ goto bail;
+ loadWhen = dvmGetRelativeTimeUsec();
+
+ /*
+ * Verify and optimize all classes in the DEX file (command-line
+ * options permitting).
+ *
+ * This is best-effort, so there's really no way for dexopt to
+ * fail at this point.
+ */
+ verifyAndOptimizeClasses(pDvmDex->pDexFile, doVerify, doOpt);
+ verifyOptWhen = dvmGetRelativeTimeUsec();
+
+ const char* msgStr = "???";
+ if (doVerify && doOpt)
+ msgStr = "verify+opt";
+ else if (doVerify)
+ msgStr = "verify";
+ else if (doOpt)
+ msgStr = "opt";
+ LOGD("DexOpt: load %dms, %s %dms\n",
+ (int) (loadWhen - prepWhen) / 1000,
+ msgStr,
+ (int) (verifyOptWhen - loadWhen) / 1000);
+
+ result = true;
+
+bail:
+ /* free up storage */
+ dvmDexFileFree(pDvmDex);
+
+ return result;
+}
+
+/*
+ * Try to load all classes in the specified DEX. If they have some sort
+ * of broken dependency, e.g. their superclass lives in a different DEX
+ * that wasn't previously loaded into the bootstrap class path, loading
+ * will fail. This is the desired behavior.
+ *
+ * We have no notion of class loader at this point, so we load all of
+ * the classes with the bootstrap class loader. It turns out this has
+ * exactly the behavior we want, and has no ill side effects because we're
+ * running in a separate process and anything we load here will be forgotten.
+ *
+ * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
+ * This works because we only call here as part of optimization / pre-verify,
+ * not during verification as part of loading a class into a running VM.
+ *
+ * This returns "false" if the world is too screwed up to do anything
+ * useful at all.
+ */
+static bool loadAllClasses(DvmDex* pDvmDex)
+{
+ u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
+ u4 idx;
+ int loaded = 0;
+
+ LOGV("DexOpt: +++ trying to load %d classes\n", count);
+
+ dvmSetBootPathExtraDex(pDvmDex);
+
+ /*
+ * We have some circularity issues with Class and Object that are most
+ * easily avoided by ensuring that Object is never the first thing we
+ * try to find. Take care of that here. (We only need to do this when
+ * loading classes from the DEX file that contains Object, and only
+ * when Object comes first in the list, but it costs very little to
+ * do it in all cases.)
+ */
+ if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) {
+ LOGE("ERROR: java.lang.Class does not exist!\n");
+ return false;
+ }
+
+ for (idx = 0; idx < count; idx++) {
+ const DexClassDef* pClassDef;
+ const char* classDescriptor;
+ ClassObject* newClass;
+
+ pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
+ classDescriptor =
+ dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
+
+ LOGV("+++ loading '%s'", classDescriptor);
+ //newClass = dvmDefineClass(pDexFile, classDescriptor,
+ // NULL);
+ newClass = dvmFindSystemClassNoInit(classDescriptor);
+ if (newClass == NULL) {
+ LOGV("DexOpt: failed loading '%s'\n", classDescriptor);
+ dvmClearOptException(dvmThreadSelf());
+ } else if (newClass->pDvmDex != pDvmDex) {
+ /*
+ * We don't load the new one, and we tag the first one found
+ * with the "multiple def" flag so the resolver doesn't try
+ * to make it available.
+ */
+ LOGD("DexOpt: '%s' has an earlier definition; blocking out\n",
+ classDescriptor);
+ SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
+ } else {
+ loaded++;
+ }
+ }
+ LOGV("DexOpt: +++ successfully loaded %d classes\n", loaded);
+
+ dvmSetBootPathExtraDex(NULL);
+ return true;
+}
+
+/*
+ * Verify and/or optimize all classes that were successfully loaded from
+ * this DEX file.
+ */
+static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
+ bool doOpt)
+{
+ u4 count = pDexFile->pHeader->classDefsSize;
+ u4 idx;
+
+ /*
+ * Create a data structure for use by the bytecode optimizer. We
+ * stuff it into a global so we don't have to pass it around as
+ * a function argument.
+ *
+ * We could create this at VM startup, but there's no need to do so
+ * unless we're optimizing, which means we're in dexopt, and we're
+ * only going to call here once.
+ */
+ if (doOpt) {
+ gDvm.inlineSubs = dvmCreateInlineSubsTable();
+ if (gDvm.inlineSubs == NULL)
+ return;
+ }
+
+ for (idx = 0; idx < count; idx++) {
+ const DexClassDef* pClassDef;
+ const char* classDescriptor;
+ ClassObject* clazz;
+
+ pClassDef = dexGetClassDef(pDexFile, idx);
+ classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+ /* all classes are loaded into the bootstrap class loader */
+ clazz = dvmLookupClass(classDescriptor, NULL, false);
+ if (clazz != NULL) {
+ verifyAndOptimizeClass(pDexFile, clazz, pClassDef, doVerify, doOpt);
+
+ } else {
+ // TODO: log when in verbose mode
+ LOGV("DexOpt: not optimizing unavailable class '%s'\n",
+ classDescriptor);
+ }
+ }
+
+ if (gDvm.inlineSubs != NULL) {
+ dvmFreeInlineSubsTable(gDvm.inlineSubs);
+ gDvm.inlineSubs = NULL;
+ }
+}
+
+/*
+ * Verify and/or optimize a specific class.
+ */
+static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
+ const DexClassDef* pClassDef, bool doVerify, bool doOpt)
+{
+ const char* classDescriptor;
+ bool verified = false;
+
+ classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+ /*
+ * First, try to verify it.
+ */
+ if (doVerify) {
+ if (clazz->pDvmDex->pDexFile != pDexFile) {
+ LOGD("DexOpt: not verifying '%s': multiple definitions\n",
+ classDescriptor);
+ } else {
+ if (dvmVerifyClass(clazz)) {
+ /*
+ * Set the "is preverified" flag in the DexClassDef. We
+ * do it here, rather than in the ClassObject structure,
+ * because the DexClassDef is part of the odex file.
+ */
+ assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
+ pClassDef->accessFlags);
+ ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED;
+ verified = true;
+ } else {
+ // TODO: log when in verbose mode
+ LOGV("DexOpt: '%s' failed verification\n", classDescriptor);
+ }
+ }
+ }
+
+ if (doOpt) {
+ if (!verified && gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED) {
+ LOGV("DexOpt: not optimizing '%s': not verified\n",
+ classDescriptor);
+ } else {
+ dvmOptimizeClass(clazz, false);
+
+ /* set the flag whether or not we actually changed anything */
+ ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISOPTIMIZED;
+ }
+ }
+}
+
+
+/*
+ * Get the cache file name from a ClassPathEntry.
+ */
+static const char* getCacheFileName(const ClassPathEntry* cpe)
+{
+ switch (cpe->kind) {
+ case kCpeJar:
+ return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
+ case kCpeDex:
+ return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
+ default:
+ LOGE("DexOpt: unexpected cpe kind %d\n", cpe->kind);
+ dvmAbort();
+ return NULL;
+ }
+}
+
+/*
+ * Get the SHA-1 signature.
+ */
+static const u1* getSignature(const ClassPathEntry* cpe)
+{
+ DvmDex* pDvmDex;
+
+ switch (cpe->kind) {
+ case kCpeJar:
+ pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
+ break;
+ case kCpeDex:
+ pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
+ break;
+ default:
+ LOGE("unexpected cpe kind %d\n", cpe->kind);
+ dvmAbort();
+ pDvmDex = NULL; // make gcc happy
+ }
+
+ assert(pDvmDex != NULL);
+ return pDvmDex->pDexFile->pHeader->signature;
+}
+
+
+/*
+ * Dependency layout:
+ * 4b Source file modification time, in seconds since 1970 UTC
+ * 4b CRC-32 from Zip entry, or Adler32 from source DEX header
+ * 4b Dalvik VM build number
+ * 4b Number of dependency entries that follow
+ * Dependency entries:
+ * 4b Name length (including terminating null)
+ * var Full path of cache entry (null terminated)
+ * 20b SHA-1 signature from source DEX file
+ *
+ * If this changes, update DEX_OPT_MAGIC_VERS.
+ */
+static const size_t kMinDepSize = 4 * 4;
+static const size_t kMaxDepSize = 4 * 4 + 2048; // sanity check
+
+/*
+ * Read the "opt" header, verify it, then read the dependencies section
+ * and verify that data as well.
+ *
+ * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
+ * match up with what is stored in the header. If they don't, we reject
+ * the file so that it can be recreated from the updated original. If
+ * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
+ *
+ * On successful return, the file will be seeked immediately past the
+ * "opt" header.
+ */
+bool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
+ u4 crc, bool expectVerify, bool expectOpt)
+{
+ DexOptHeader optHdr;
+ u1* depData = NULL;
+ const u1* magic;
+ off_t posn;
+ int result = false;
+ ssize_t actual;
+
+ /*
+ * Start at the start. The "opt" header, when present, will always be
+ * the first thing in the file.
+ */
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ LOGE("DexOpt: failed to seek to start of file: %s\n", strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Read and do trivial verification on the opt header. The header is
+ * always in host byte order.
+ */
+ if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
+ LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
+ goto bail;
+ }
+
+ magic = optHdr.magic;
+ if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
+ /* not a DEX file, or previous attempt was interrupted */
+ LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
+ magic[0], magic[1], magic[2], magic[3]);
+ goto bail;
+ }
+ if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
+ LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)\n",
+ magic[4], magic[5], magic[6], magic[7]);
+ goto bail;
+ }
+ if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
+ LOGW("DexOpt: weird deps length %d, bailing\n", optHdr.depsLength);
+ goto bail;
+ }
+
+ /*
+ * Do the header flags match up with what we want?
+ *
+ * This is useful because it allows us to automatically regenerate
+ * a file when settings change (e.g. verification is now mandatory),
+ * but can cause difficulties if the bootstrap classes we depend upon
+ * were handled differently than the current options specify. We get
+ * upset because they're not verified or optimized, but we're not able
+ * to regenerate them because the installer won't let us.
+ *
+ * (This is also of limited value when !sourceAvail.)
+ *
+ * So, for now, we essentially ignore "expectVerify" and "expectOpt"
+ * by limiting the match mask.
+ *
+ * The only thing we really can't handle is incorrect byte-ordering.
+ */
+ const u4 matchMask = DEX_OPT_FLAG_BIG;
+ u4 expectedFlags = 0;
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+ expectedFlags |= DEX_OPT_FLAG_BIG;
+#endif
+ if (expectVerify)
+ expectedFlags |= DEX_FLAG_VERIFIED;
+ if (expectOpt)
+ expectedFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
+ if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
+ LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)\n",
+ expectedFlags, optHdr.flags, matchMask);
+ goto bail;
+ }
+
+ posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
+ if (posn < 0) {
+ LOGW("DexOpt: seek to deps failed: %s\n", strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Read all of the dependency stuff into memory.
+ */
+ depData = (u1*) malloc(optHdr.depsLength);
+ if (depData == NULL) {
+ LOGW("DexOpt: unable to allocate %d bytes for deps\n",
+ optHdr.depsLength);
+ goto bail;
+ }
+ actual = read(fd, depData, optHdr.depsLength);
+ if (actual != (ssize_t) optHdr.depsLength) {
+ LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
+ (int) actual, optHdr.depsLength, strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Verify simple items.
+ */
+ const u1* ptr;
+ u4 val;
+
+ ptr = depData;
+ val = read4LE(&ptr);
+ if (sourceAvail && val != modWhen) {
+ LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)\n",
+ val, modWhen);
+ goto bail;
+ }
+ val = read4LE(&ptr);
+ if (sourceAvail && val != crc) {
+ LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)\n", val, crc);
+ goto bail;
+ }
+ val = read4LE(&ptr);
+ if (val != DALVIK_VM_BUILD) {
+ LOGD("DexOpt: VM build version mismatch (%d vs %d)\n",
+ val, DALVIK_VM_BUILD);
+ goto bail;
+ }
+
+ /*
+ * Verify dependencies on other cached DEX files. It must match
+ * exactly with what is currently defined in the bootclasspath.
+ */
+ ClassPathEntry* cpe;
+ u4 numDeps;
+
+ numDeps = read4LE(&ptr);
+ LOGV("+++ DexOpt: numDeps = %d\n", numDeps);
+ for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+ const char* cacheFileName = getCacheFileName(cpe);
+ const u1* signature = getSignature(cpe);
+ size_t len = strlen(cacheFileName) +1;
+ u4 storedStrLen;
+
+ if (numDeps == 0) {
+ /* more entries in bootclasspath than in deps list */
+ LOGI("DexOpt: not all deps represented\n");
+ goto bail;
+ }
+
+ storedStrLen = read4LE(&ptr);
+ if (len != storedStrLen ||
+ strcmp(cacheFileName, (const char*) ptr) != 0)
+ {
+ LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'\n",
+ cacheFileName, ptr);
+ goto bail;
+ }
+
+ ptr += storedStrLen;
+
+ if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
+ LOGI("DexOpt: mismatch dep signature for '%s'\n", cacheFileName);
+ goto bail;
+ }
+ ptr += kSHA1DigestLen;
+
+ LOGV("DexOpt: dep match on '%s'\n", cacheFileName);
+
+ numDeps--;
+ }
+
+ if (numDeps != 0) {
+ /* more entries in deps list than in classpath */
+ LOGI("DexOpt: Some deps went away\n");
+ goto bail;
+ }
+
+ // consumed all data and no more?
+ if (ptr != depData + optHdr.depsLength) {
+ LOGW("DexOpt: Spurious dep data? %d vs %d\n",
+ (int) (ptr - depData), optHdr.depsLength);
+ assert(false);
+ }
+
+ result = true;
+
+bail:
+ free(depData);
+ return result;
+}
+
+/*
+ * Write the dependency info to "fd" at the current file position.
+ */
+static int writeDependencies(int fd, u4 modWhen, u4 crc)
+{
+ u1* buf = NULL;
+ int result = -1;
+ ssize_t bufLen;
+ ClassPathEntry* cpe;
+ int numDeps;
+
+ /*
+ * Count up the number of completed entries in the bootclasspath.
+ */
+ numDeps = 0;
+ bufLen = 0;
+ for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+ const char* cacheFileName = getCacheFileName(cpe);
+ LOGV("+++ DexOpt: found dep '%s'\n", cacheFileName);
+
+ numDeps++;
+ bufLen += strlen(cacheFileName) +1;
+ }
+
+ bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
+
+ buf = malloc(bufLen);
+
+ set4LE(buf+0, modWhen);
+ set4LE(buf+4, crc);
+ set4LE(buf+8, DALVIK_VM_BUILD);
+ set4LE(buf+12, numDeps);
+
+ // TODO: do we want to add dvmGetInlineOpsTableLength() here? Won't
+ // help us if somebody replaces an existing entry, but it'd catch
+ // additions/removals.
+
+ u1* ptr = buf + 4*4;
+ for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+ const char* cacheFileName = getCacheFileName(cpe);
+ const u1* signature = getSignature(cpe);
+ int len = strlen(cacheFileName) +1;
+
+ if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
+ LOGE("DexOpt: overran buffer\n");
+ dvmAbort();
+ }
+
+ set4LE(ptr, len);
+ ptr += 4;
+ memcpy(ptr, cacheFileName, len);
+ ptr += len;
+ memcpy(ptr, signature, kSHA1DigestLen);
+ ptr += kSHA1DigestLen;
+ }
+
+ assert(ptr == buf + bufLen);
+
+ result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
+
+ free(buf);
+ return result;
+}
+
+
+/*
+ * Write a block of data in "chunk" format.
+ *
+ * The chunk header fields are always in "native" byte order. If "size"
+ * is not a multiple of 8 bytes, the data area is padded out.
+ */
+static bool writeChunk(int fd, u4 type, const void* data, size_t size)
+{
+ union { /* save a syscall by grouping these together */
+ char raw[8];
+ struct {
+ u4 type;
+ u4 size;
+ } ts;
+ } header;
+
+ assert(sizeof(header) == 8);
+
+ LOGV("Writing chunk, type=%.4s size=%d\n", (char*) &type, size);
+
+ header.ts.type = type;
+ header.ts.size = (u4) size;
+ if (sysWriteFully(fd, &header, sizeof(header),
+ "DexOpt aux chunk header write") != 0)
+ {
+ return false;
+ }
+
+ if (size > 0) {
+ if (sysWriteFully(fd, data, size, "DexOpt aux chunk write") != 0)
+ return false;
+ }
+
+ /* if necessary, pad to 64-bit alignment */
+ if ((size & 7) != 0) {
+ int padSize = 8 - (size & 7);
+ LOGV("size was %d, inserting %d pad bytes\n", size, padSize);
+ lseek(fd, padSize, SEEK_CUR);
+ }
+
+ assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
+
+ return true;
+}
+
+/*
+ * Write aux data.
+ *
+ * We have different pieces, some of which may be optional. To make the
+ * most effective use of space, we use a "chunk" format, with a 4-byte
+ * type and a 4-byte length. We guarantee 64-bit alignment for the data,
+ * so it can be used directly when the file is mapped for reading.
+ */
+static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
+ const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
+{
+ /* pre-computed class lookup hash table */
+ if (!writeChunk(fd, (u4) kDexChunkClassLookup,
+ pClassLookup, pClassLookup->size))
+ {
+ return false;
+ }
+
+ /* remapped constants (optional) */
+ if (pIndexMapSet != NULL) {
+ if (!writeChunk(fd, pIndexMapSet->chunkType,
+ pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
+ {
+ return false;
+ }
+ }
+
+ /* register maps (optional) */
+ if (pRegMapBuilder != NULL) {
+ if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
+ pRegMapBuilder->data, pRegMapBuilder->size))
+ {
+ return false;
+ }
+ }
+
+ /* write the end marker */
+ if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Compute a checksum on a piece of an open file.
+ *
+ * File will be positioned at end of checksummed area.
+ *
+ * Returns "true" on success.
+ */
+static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
+{
+ unsigned char readBuf[8192];
+ ssize_t actual;
+ uLong adler;
+
+ if (lseek(fd, start, SEEK_SET) != start) {
+ LOGE("Unable to seek to start of checksum area (%ld): %s\n",
+ (long) start, strerror(errno));
+ return false;
+ }
+
+ adler = adler32(0L, Z_NULL, 0);
+
+ while (length != 0) {
+ size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
+ actual = read(fd, readBuf, wanted);
+ if (actual <= 0) {
+ LOGE("Read failed (%d) while computing checksum (len=%zu): %s\n",
+ (int) actual, length, strerror(errno));
+ return false;
+ }
+
+ adler = adler32(adler, readBuf, actual);
+
+ length -= actual;
+ }
+
+ *pSum = adler;
+ return true;
+}
+
+/*
+ * Update the Adler-32 checksum stored in the DEX file. This covers the
+ * swapped and optimized DEX data, but does not include the opt header
+ * or auxillary data.
+ */
+static void updateChecksum(u1* addr, int len, DexHeader* pHeader)
+{
+ /*
+ * Rewrite the checksum. We leave the SHA-1 signature alone.
+ */
+ uLong adler = adler32(0L, Z_NULL, 0);
+ const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
+
+ adler = adler32(adler, addr + nonSum, len - nonSum);
+ pHeader->checksum = adler;
+}
diff --git a/vm/analysis/DexOptimize.h b/vm/analysis/DexPrepare.h
similarity index 84%
rename from vm/analysis/DexOptimize.h
rename to vm/analysis/DexPrepare.h
index afcb3cb..ae94979 100644
--- a/vm/analysis/DexOptimize.h
+++ b/vm/analysis/DexPrepare.h
@@ -15,10 +15,10 @@
*/
/*
- * DEX optimization declarations.
+ * DEX preparation declarations.
*/
-#ifndef _DALVIK_DEXOPTIMIZE
-#define _DALVIK_DEXOPTIMIZE
+#ifndef _DALVIK_DEXPREPARE
+#define _DALVIK_DEXPREPARE
/*
* Global DEX optimizer control. Determines the circumstances in which we
@@ -112,18 +112,4 @@
bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
const char* fileName, u4 modWhen, u4 crc, bool isBootstrap);
-/*
- * Abbreviated resolution functions, for use by optimization and verification
- * code.
- */
-ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
- VerifyError* pFailure);
-Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
- MethodType methodType, VerifyError* pFailure);
-Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx);
-InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
- VerifyError* pFailure);
-StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
- VerifyError* pFailure);
-
-#endif /*_DALVIK_DEXOPTIMIZE*/
+#endif /*_DALVIK_DEXPREPARE*/
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index 088309c..b934481 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -23,9 +23,8 @@
/* fwd */
-static bool verifyMethod(Method* meth, int verifyFlags);
-static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
- int verifyFlags);
+static bool verifyMethod(Method* meth);
+static bool verifyInstructions(VerifierData* vdata);
/*
@@ -56,61 +55,6 @@
free(gDvm.instrFlags);
}
-/*
- * Induce verification on all classes loaded from this DEX file as part
- * of pre-verification and optimization. This is never called from a
- * normally running VM.
- *
- * Returns "true" when all classes have been processed.
- */
-bool dvmVerifyAllClasses(DexFile* pDexFile)
-{
- u4 count = pDexFile->pHeader->classDefsSize;
- u4 idx;
-
- assert(gDvm.optimizing);
-
- if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
- LOGV("+++ verification is disabled, skipping all classes\n");
- return true;
- }
- if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE &&
- gDvm.optimizingBootstrapClass)
- {
- LOGV("+++ verification disabled for bootstrap classes\n");
- return true;
- }
-
- for (idx = 0; idx < count; idx++) {
- const DexClassDef* pClassDef;
- const char* classDescriptor;
- ClassObject* clazz;
-
- pClassDef = dexGetClassDef(pDexFile, idx);
- classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-
- /* all classes are loaded into the bootstrap class loader */
- clazz = dvmLookupClass(classDescriptor, NULL, false);
- if (clazz != NULL) {
- if (clazz->pDvmDex->pDexFile != pDexFile) {
- LOGD("DexOpt: not verifying '%s': multiple definitions\n",
- classDescriptor);
- } else {
- if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
- assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
- pClassDef->accessFlags);
- ((DexClassDef*)pClassDef)->accessFlags |=
- CLASS_ISPREVERIFIED;
- }
- /* keep going even if one fails */
- }
- } else {
- LOGV("DexOpt: +++ not verifying '%s'\n", classDescriptor);
- }
- }
-
- return true;
-}
/*
* Verify a class.
@@ -121,7 +65,7 @@
*
* Returns "true" on success.
*/
-bool dvmVerifyClass(ClassObject* clazz, int verifyFlags)
+bool dvmVerifyClass(ClassObject* clazz)
{
int i;
@@ -130,18 +74,14 @@
return true;
}
- //LOGI("Verify1 '%s'\n", clazz->descriptor);
-
- // TODO - verify class structure in DEX?
-
for (i = 0; i < clazz->directMethodCount; i++) {
- if (!verifyMethod(&clazz->directMethods[i], verifyFlags)) {
+ if (!verifyMethod(&clazz->directMethods[i])) {
LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
return false;
}
}
for (i = 0; i < clazz->virtualMethodCount; i++) {
- if (!verifyMethod(&clazz->virtualMethods[i], verifyFlags)) {
+ if (!verifyMethod(&clazz->virtualMethods[i])) {
LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
return false;
}
@@ -155,36 +95,53 @@
* Perform verification on a single method.
*
* We do this in three passes:
- * (1) Walk through all code units, determining instruction lengths.
- * (2) Do static checks, including branch target and operand validation.
- * (3) Do structural checks, including data-flow analysis.
+ * (1) Walk through all code units, determining instruction locations,
+ * widths, and other characteristics.
+ * (2) Walk through all code units, performing static checks on
+ * operands.
+ * (3) Iterate through the method, checking type safety and looking
+ * for code flow problems.
*
* Some checks may be bypassed depending on the verification mode. We can't
* turn this stuff off completely if we want to do "exact" GC.
*
- * - operands of getfield, putfield, getstatic, putstatic must be valid
- * - operands of method invocation instructions must be valid
- *
+ * TODO: cite source?
+ * Confirmed here:
* - code array must not be empty
* - (N/A) code_length must be less than 65536
+ * Confirmed by dvmComputeCodeWidths():
* - opcode of first instruction begins at index 0
* - only documented instructions may appear
* - each instruction follows the last
- * - (below) last byte of last instruction is at (code_length-1)
+ * - last byte of last instruction is at (code_length-1)
*/
-static bool verifyMethod(Method* meth, int verifyFlags)
+static bool verifyMethod(Method* meth)
{
bool result = false;
- UninitInstanceMap* uninitMap = NULL;
- InsnFlags* insnFlags = NULL;
- int i, newInstanceCount;
+ int newInstanceCount;
+
+ /*
+ * Verifier state blob. Various values will be cached here so we
+ * can avoid expensive lookups and pass fewer arguments around.
+ */
+ VerifierData vdata;
+#if 1 // ndef NDEBUG
+ memset(&vdata, 0x99, sizeof(vdata));
+#endif
+
+ vdata.method = meth;
+ vdata.insnsSize = dvmGetMethodInsnsSize(meth);
+ vdata.insnRegCount = meth->registersSize;
+ vdata.insnFlags = NULL;
+ vdata.uninitMap = NULL;
/*
* If there aren't any instructions, make sure that's expected, then
- * exit successfully. Note: meth->insns gets set to a native function
- * pointer on first call.
+ * exit successfully. Note: for native methods, meth->insns gets set
+ * to a native function pointer on first call, so don't use that as
+ * an indicator.
*/
- if (dvmGetMethodInsnsSize(meth) == 0) {
+ if (vdata.insnsSize == 0) {
if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
LOG_VFY_METH(meth,
"VFY: zero-length code in concrete non-native method\n");
@@ -210,9 +167,9 @@
* TODO: Consider keeping a reusable pre-allocated array sitting
* around for smaller methods.
*/
- insnFlags = (InsnFlags*)
+ vdata.insnFlags = (InsnFlags*)
calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
- if (insnFlags == NULL)
+ if (vdata.insnFlags == NULL)
goto bail;
/*
@@ -220,26 +177,27 @@
* Count up the #of occurrences of new-instance instructions while we're
* at it.
*/
- if (!dvmComputeCodeWidths(meth, insnFlags, &newInstanceCount))
+ if (!dvmComputeCodeWidths(meth, vdata.insnFlags, &newInstanceCount))
goto bail;
/*
* Allocate a map to hold the classes of uninitialized instances.
*/
- uninitMap = dvmCreateUninitInstanceMap(meth, insnFlags, newInstanceCount);
- if (uninitMap == NULL)
+ vdata.uninitMap = dvmCreateUninitInstanceMap(meth, vdata.insnFlags,
+ newInstanceCount);
+ if (vdata.uninitMap == NULL)
goto bail;
/*
* Set the "in try" flags for all instructions guarded by a "try" block.
*/
- if (!dvmSetTryFlags(meth, insnFlags))
+ if (!dvmSetTryFlags(meth, vdata.insnFlags))
goto bail;
/*
* Perform static instruction verification.
*/
- if (!verifyInstructions(meth, insnFlags, verifyFlags))
+ if (!verifyInstructions(&vdata))
goto bail;
/*
@@ -250,7 +208,7 @@
* analysis, but we still need to verify that nothing actually tries
* to use a register.
*/
- if (!dvmVerifyCodeFlow(meth, insnFlags, uninitMap)) {
+ if (!dvmVerifyCodeFlow(&vdata)) {
//LOGD("+++ %s failed code flow\n", meth->name);
goto bail;
}
@@ -259,8 +217,8 @@
result = true;
bail:
- dvmFreeUninitInstanceMap(uninitMap);
- free(insnFlags);
+ dvmFreeUninitInstanceMap(vdata.uninitMap);
+ free(vdata.insnFlags);
return result;
}
@@ -311,7 +269,7 @@
LOG_VFY_METH(meth,
"VFY: invalid array data end: at %d, data offset %d, end %d, "
"count %d\n",
- curOffset, offsetToArrayData,
+ curOffset, offsetToArrayData,
curOffset + offsetToArrayData + tableSize,
insnCount);
return false;
@@ -530,17 +488,18 @@
* code-flow analysis sometimes has to process the same instruction several
* times).
*/
-static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
- int verifyFlags)
+static bool verifyInstructions(VerifierData* vdata)
{
- const int insnCount = dvmGetMethodInsnsSize(meth);
+ const Method* meth = vdata->method;
+ InsnFlags* insnFlags = vdata->insnFlags;
+ const size_t insnCount = vdata->insnsSize;
const u2* insns = meth->insns;
int i;
/* the start of the method is a "branch target" */
dvmInsnSetBranchTarget(insnFlags, 0, true);
- for (i = 0; i < insnCount; /**/) {
+ for (i = 0; i < (int) insnCount; /**/) {
/*
* These types of instructions can be GC points. To support precise
* GC, all such instructions must export the PC in the interpreter,
@@ -552,7 +511,6 @@
int width = dvmInsnGetWidth(insnFlags, i);
OpCode opcode = *insns & 0xff;
InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
- int offset, absOffset;
if ((opFlags & gcMask) != 0) {
/*
@@ -563,7 +521,7 @@
int offset = -1;
bool unused;
if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
- if (offset < 0) {
+ if (offset <= 0) {
dvmInsnSetGcPoint(insnFlags, i, true);
}
} else {
@@ -713,10 +671,8 @@
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE:
- if ((verifyFlags & VERIFY_ALLOW_OPT_INSTRS) == 0) {
- LOG_VFY("VFY: not expecting optimized instructions\n");
- return false;
- }
+ LOG_VFY("VFY: not expecting optimized instructions\n");
+ return false;
break;
default:
@@ -730,7 +686,7 @@
}
/* make sure the last instruction ends at the end of the insn area */
- if (i != insnCount) {
+ if (i != (int) insnCount) {
LOG_VFY_METH(meth,
"VFY: code did not end when expected (end at %d, count %d)\n",
i, insnCount);
@@ -739,4 +695,3 @@
return true;
}
-
diff --git a/vm/analysis/DexVerify.h b/vm/analysis/DexVerify.h
index 9deaad9..ab2af52 100644
--- a/vm/analysis/DexVerify.h
+++ b/vm/analysis/DexVerify.h
@@ -32,30 +32,19 @@
VERIFY_MODE_ALL
} DexClassVerifyMode;
-/*
- * Bit values for dvmVerifyClass() "verifyFlags" arg.
- *
- * (Verification is currently a prerequisite for optimization, not an
- * after-effect, so we don't currently use VERIFY_ALLOW_OPT_INSTRS.)
- */
-enum {
- VERIFY_DEFAULT = 0,
- VERIFY_ALLOW_OPT_INSTRS = 1, // allow instrs emitted by optimizer
-};
-
bool dvmVerificationStartup(void);
void dvmVerificationShutdown(void);
/*
- * Perform verification on all classes loaded from this DEX file. This
- * should be done before optimization.
+ * Perform verification on all classes loaded from this DEX file. If
+ * enabled, it must happen before optimization.
*/
bool dvmVerifyAllClasses(DexFile* pDexFile);
/*
* Verify a single class.
*/
-bool dvmVerifyClass(ClassObject* clazz, int verifyFlags);
+bool dvmVerifyClass(ClassObject* clazz);
/*
* Release the storage associated with a RegisterMap.
diff --git a/vm/analysis/Optimize.c b/vm/analysis/Optimize.c
new file mode 100644
index 0000000..4ac19f3
--- /dev/null
+++ b/vm/analysis/Optimize.c
@@ -0,0 +1,1097 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Perform some simple bytecode optimizations, chiefly "quickening" of
+ * opcodes.
+ */
+#include "Dalvik.h"
+#include "libdex/InstrUtils.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+
+/*
+ * Virtual/direct calls to "method" are replaced with an execute-inline
+ * instruction with index "idx".
+ */
+struct InlineSub {
+ Method* method;
+ int inlineIdx;
+};
+
+
+/* fwd */
+static void optimizeMethod(Method* method, bool essentialOnly);
+static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
+ OpCode volatileOpc);
+static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc);
+static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc);
+static bool rewriteEmptyDirectInvoke(Method* method, u2* insns);
+static bool rewriteExecuteInline(Method* method, u2* insns,
+ MethodType methodType);
+static bool rewriteExecuteInlineRange(Method* method, u2* insns,
+ MethodType methodType);
+
+
+/*
+ * Create a table of inline substitutions.
+ *
+ * TODO: this is currently just a linear array. We will want to put this
+ * into a hash table as the list size increases.
+ */
+InlineSub* dvmCreateInlineSubsTable(void)
+{
+ const InlineOperation* ops = dvmGetInlineOpsTable();
+ const int count = dvmGetInlineOpsTableLength();
+ InlineSub* table;
+ Method* method;
+ ClassObject* clazz;
+ int i, tableIndex;
+
+ /*
+ * Allocate for optimism: one slot per entry, plus an end-of-list marker.
+ */
+ table = malloc(sizeof(InlineSub) * (count+1));
+
+ tableIndex = 0;
+ for (i = 0; i < count; i++) {
+ clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL);
+ if (clazz == NULL) {
+ LOGV("DexOpt: can't inline for class '%s': not found\n",
+ ops[i].classDescriptor);
+ dvmClearOptException(dvmThreadSelf());
+ } else {
+ /*
+ * Method could be virtual or direct. Try both. Don't use
+ * the "hier" versions.
+ */
+ method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName,
+ ops[i].methodSignature);
+ if (method == NULL)
+ method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName,
+ ops[i].methodSignature);
+ if (method == NULL) {
+ LOGW("DexOpt: can't inline %s.%s %s: method not found\n",
+ ops[i].classDescriptor, ops[i].methodName,
+ ops[i].methodSignature);
+ } else {
+ if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
+ LOGW("DexOpt: WARNING: inline op on non-final class/method "
+ "%s.%s\n",
+ clazz->descriptor, method->name);
+ /* fail? */
+ }
+ if (dvmIsSynchronizedMethod(method) ||
+ dvmIsDeclaredSynchronizedMethod(method))
+ {
+ LOGW("DexOpt: WARNING: inline op on synchronized method "
+ "%s.%s\n",
+ clazz->descriptor, method->name);
+ /* fail? */
+ }
+
+ table[tableIndex].method = method;
+ table[tableIndex].inlineIdx = i;
+ tableIndex++;
+
+ LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
+ ops[i].classDescriptor, ops[i].methodName,
+ ops[i].methodSignature);
+ }
+ }
+ }
+
+ /* mark end of table */
+ table[tableIndex].method = NULL;
+ LOGV("DexOpt: inline table has %d entries\n", tableIndex);
+
+ return table;
+}
+
+/*
+ * Release inline sub data structure.
+ */
+void dvmFreeInlineSubsTable(InlineSub* inlineSubs)
+{
+ free(inlineSubs);
+}
+
+
+/*
+ * Optimize the specified class.
+ *
+ * If "essentialOnly" is true, we only do essential optimizations. For
+ * example, accesses to volatile 64-bit fields must be replaced with
+ * "-wide-volatile" instructions or the program could behave incorrectly.
+ * (Skipping non-essential optimizations makes us a little bit faster, and
+ * more importantly avoids dirtying DEX pages.)
+ */
+void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
+{
+ int i;
+
+ for (i = 0; i < clazz->directMethodCount; i++) {
+ optimizeMethod(&clazz->directMethods[i], essentialOnly);
+ }
+ for (i = 0; i < clazz->virtualMethodCount; i++) {
+ optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
+ }
+}
+
+/*
+ * Optimize instructions in a method.
+ *
+ * This does a single pass through the code, examining each instruction.
+ *
+ * This is not expected to fail if the class was successfully verified.
+ * The only significant failure modes occur when an "essential" update fails,
+ * but we can't generally identify those: if we can't look up a field,
+ * we can't know if the field access was supposed to be handled as volatile.
+ *
+ * Instead, we give it our best effort, and hope for the best. For 100%
+ * reliability, only optimize a class after verification succeeds.
+ */
+static void optimizeMethod(Method* method, bool essentialOnly)
+{
+ u4 insnsSize;
+ u2* insns;
+ u2 inst;
+
+ if (!gDvm.optimizing && !essentialOnly) {
+ /* unexpected; will force copy-on-write of a lot of pages */
+ LOGD("NOTE: doing full bytecode optimization outside dexopt\n");
+ }
+
+ if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
+ return;
+
+ insns = (u2*) method->insns;
+ assert(insns != NULL);
+ insnsSize = dvmGetMethodInsnsSize(method);
+
+ while (insnsSize > 0) {
+ OpCode quickOpc, volatileOpc = OP_NOP;
+ int width;
+ bool notMatched = false;
+
+ inst = *insns & 0xff;
+
+ switch (inst) {
+ case OP_IGET:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ quickOpc = OP_IGET_QUICK;
+ if (ANDROID_SMP != 0)
+ volatileOpc = OP_IGET_VOLATILE;
+ goto rewrite_inst_field;
+ case OP_IGET_WIDE:
+ quickOpc = OP_IGET_WIDE_QUICK;
+ volatileOpc = OP_IGET_WIDE_VOLATILE;
+ goto rewrite_inst_field;
+ case OP_IGET_OBJECT:
+ quickOpc = OP_IGET_OBJECT_QUICK;
+ if (ANDROID_SMP != 0)
+ volatileOpc = OP_IGET_OBJECT_VOLATILE;
+ goto rewrite_inst_field;
+ case OP_IPUT:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ quickOpc = OP_IPUT_QUICK;
+ if (ANDROID_SMP != 0)
+ volatileOpc = OP_IPUT_VOLATILE;
+ goto rewrite_inst_field;
+ case OP_IPUT_WIDE:
+ quickOpc = OP_IPUT_WIDE_QUICK;
+ volatileOpc = OP_IPUT_WIDE_VOLATILE;
+ goto rewrite_inst_field;
+ case OP_IPUT_OBJECT:
+ quickOpc = OP_IPUT_OBJECT_QUICK;
+ if (ANDROID_SMP != 0)
+ volatileOpc = OP_IPUT_OBJECT_VOLATILE;
+rewrite_inst_field:
+ if (essentialOnly)
+ quickOpc = OP_NOP;
+ if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
+ rewriteInstField(method, insns, quickOpc, volatileOpc);
+ break;
+
+#if ANDROID_SMP != 0
+ case OP_SGET:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ volatileOpc = OP_SGET_VOLATILE;
+ goto rewrite_static_field;
+ case OP_SGET_OBJECT:
+ volatileOpc = OP_SGET_OBJECT_VOLATILE;
+ goto rewrite_static_field;
+ case OP_SPUT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ volatileOpc = OP_SPUT_VOLATILE;
+ goto rewrite_static_field;
+ case OP_SPUT_OBJECT:
+ volatileOpc = OP_SPUT_OBJECT_VOLATILE;
+ goto rewrite_static_field;
+#endif
+ case OP_SGET_WIDE:
+ volatileOpc = OP_SGET_WIDE_VOLATILE;
+ goto rewrite_static_field;
+ case OP_SPUT_WIDE:
+ volatileOpc = OP_SPUT_WIDE_VOLATILE;
+rewrite_static_field:
+ rewriteStaticField(method, insns, volatileOpc);
+ break;
+
+ default:
+ /* not one of the "essential" replacements; check for more */
+ notMatched = true;
+ }
+
+ if (notMatched && !essentialOnly) {
+ switch (inst) {
+ case OP_INVOKE_VIRTUAL:
+ if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
+ rewriteVirtualInvoke(method, insns,
+ OP_INVOKE_VIRTUAL_QUICK);
+ }
+ break;
+ case OP_INVOKE_VIRTUAL_RANGE:
+ if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
+ rewriteVirtualInvoke(method, insns,
+ OP_INVOKE_VIRTUAL_QUICK_RANGE);
+ }
+ break;
+ case OP_INVOKE_SUPER:
+ rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
+ break;
+ case OP_INVOKE_SUPER_RANGE:
+ rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
+ break;
+
+ case OP_INVOKE_DIRECT:
+ if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
+ rewriteEmptyDirectInvoke(method, insns);
+ }
+ break;
+ case OP_INVOKE_DIRECT_RANGE:
+ rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
+ break;
+
+ case OP_INVOKE_STATIC:
+ rewriteExecuteInline(method, insns, METHOD_STATIC);
+ break;
+ case OP_INVOKE_STATIC_RANGE:
+ rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
+ break;
+
+ default:
+ /* nothing to do for this instruction */
+ ;
+ }
+ }
+
+ width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns);
+ assert(width > 0);
+
+ insns += width;
+ insnsSize -= width;
+ }
+
+ assert(insnsSize == 0);
+}
+
+/*
+ * Update a 16-bit code unit in "meth".
+ */
+static inline void updateCode(const Method* meth, u2* ptr, u2 newVal)
+{
+ if (gDvm.optimizing) {
+ /* dexopt time, alter the output directly */
+ *ptr = newVal;
+ } else {
+ /* runtime, toggle the page read/write status */
+ dvmDexChangeDex2(meth->clazz->pDvmDex, ptr, newVal);
+ }
+}
+
+/*
+ * If "referrer" and "resClass" don't come from the same DEX file, and
+ * the DEX we're working on is not destined for the bootstrap class path,
+ * tweak the class loader so package-access checks work correctly.
+ *
+ * Only do this if we're doing pre-verification or optimization.
+ */
+static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
+{
+ if (!gDvm.optimizing)
+ return;
+ assert(referrer->classLoader == NULL);
+ assert(resClass->classLoader == NULL);
+
+ if (!gDvm.optimizingBootstrapClass) {
+ /* class loader for an array class comes from element type */
+ if (dvmIsArrayClass(resClass))
+ resClass = resClass->elementClass;
+ if (referrer->pDvmDex != resClass->pDvmDex)
+ resClass->classLoader = (Object*) 0xdead3333;
+ }
+}
+
+/*
+ * Undo the effects of tweakLoader.
+ */
+static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
+{
+ if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
+ return;
+
+ if (dvmIsArrayClass(resClass))
+ resClass = resClass->elementClass;
+ resClass->classLoader = NULL;
+}
+
+
+/*
+ * Alternate version of dvmResolveClass for use with verification and
+ * optimization. Performs access checks on every resolve, and refuses
+ * to acknowledge the existence of classes defined in more than one DEX
+ * file.
+ *
+ * Exceptions caused by failures are cleared before returning.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+ VerifyError* pFailure)
+{
+ DvmDex* pDvmDex = referrer->pDvmDex;
+ ClassObject* resClass;
+
+ /*
+ * Check the table first. If not there, do the lookup by name.
+ */
+ resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
+ if (resClass == NULL) {
+ const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
+ if (className[0] != '\0' && className[1] == '\0') {
+ /* primitive type */
+ resClass = dvmFindPrimitiveClass(className[0]);
+ } else {
+ resClass = dvmFindClassNoInit(className, referrer->classLoader);
+ }
+ if (resClass == NULL) {
+ /* not found, exception should be raised */
+ LOGV("DexOpt: class %d (%s) not found\n",
+ classIdx,
+ dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
+ if (pFailure != NULL) {
+ /* dig through the wrappers to find the original failure */
+ Object* excep = dvmGetException(dvmThreadSelf());
+ while (true) {
+ Object* cause = dvmGetExceptionCause(excep);
+ if (cause == NULL)
+ break;
+ excep = cause;
+ }
+ if (strcmp(excep->clazz->descriptor,
+ "Ljava/lang/IncompatibleClassChangeError;") == 0)
+ {
+ *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+ } else {
+ *pFailure = VERIFY_ERROR_NO_CLASS;
+ }
+ }
+ dvmClearOptException(dvmThreadSelf());
+ return NULL;
+ }
+
+ /*
+ * Add it to the resolved table so we're faster on the next lookup.
+ */
+ dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
+ }
+
+ /* multiple definitions? */
+ if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
+ LOGI("DexOpt: not resolving ambiguous class '%s'\n",
+ resClass->descriptor);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_CLASS;
+ return NULL;
+ }
+
+ /* access allowed? */
+ tweakLoader(referrer, resClass);
+ bool allowed = dvmCheckClassAccess(referrer, resClass);
+ untweakLoader(referrer, resClass);
+ if (!allowed) {
+ LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
+ referrer->descriptor, resClass->descriptor);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS_CLASS;
+ return NULL;
+ }
+
+ return resClass;
+}
+
+/*
+ * Alternate version of dvmResolveInstField().
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+ VerifyError* pFailure)
+{
+ DvmDex* pDvmDex = referrer->pDvmDex;
+ InstField* resField;
+
+ resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
+ if (resField == NULL) {
+ const DexFieldId* pFieldId;
+ ClassObject* resClass;
+
+ pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
+
+ /*
+ * Find the field's class.
+ */
+ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
+ if (resClass == NULL) {
+ //dvmClearOptException(dvmThreadSelf());
+ assert(!dvmCheckException(dvmThreadSelf()));
+ if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
+ return NULL;
+ }
+
+ resField = (InstField*)dvmFindFieldHier(resClass,
+ dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
+ dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
+ if (resField == NULL) {
+ LOGD("DexOpt: couldn't find field %s.%s\n",
+ resClass->descriptor,
+ dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_FIELD;
+ return NULL;
+ }
+ if (dvmIsStaticField(&resField->field)) {
+ LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
+ resClass->descriptor,
+ dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+ return NULL;
+ }
+
+ /*
+ * Add it to the resolved table so we're faster on the next lookup.
+ */
+ dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
+ }
+
+ /* access allowed? */
+ tweakLoader(referrer, resField->field.clazz);
+ bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
+ untweakLoader(referrer, resField->field.clazz);
+ if (!allowed) {
+ LOGI("DexOpt: access denied from %s to field %s.%s\n",
+ referrer->descriptor, resField->field.clazz->descriptor,
+ resField->field.name);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS_FIELD;
+ return NULL;
+ }
+
+ return resField;
+}
+
+/*
+ * Alternate version of dvmResolveStaticField().
+ *
+ * Does not force initialization of the resolved field's class.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+ VerifyError* pFailure)
+{
+ DvmDex* pDvmDex = referrer->pDvmDex;
+ StaticField* resField;
+
+ resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
+ if (resField == NULL) {
+ const DexFieldId* pFieldId;
+ ClassObject* resClass;
+
+ pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
+
+ /*
+ * Find the field's class.
+ */
+ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
+ if (resClass == NULL) {
+ //dvmClearOptException(dvmThreadSelf());
+ assert(!dvmCheckException(dvmThreadSelf()));
+ if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
+ return NULL;
+ }
+
+ resField = (StaticField*)dvmFindFieldHier(resClass,
+ dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
+ dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
+ if (resField == NULL) {
+ LOGD("DexOpt: couldn't find static field\n");
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_FIELD;
+ return NULL;
+ }
+ if (!dvmIsStaticField(&resField->field)) {
+ LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
+ resClass->descriptor,
+ dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+ return NULL;
+ }
+
+ /*
+ * Add it to the resolved table so we're faster on the next lookup.
+ *
+ * We can only do this if we're in "dexopt", because the presence
+ * of a valid value in the resolution table implies that the class
+ * containing the static field has been initialized.
+ */
+ if (gDvm.optimizing)
+ dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
+ }
+
+ /* access allowed? */
+ tweakLoader(referrer, resField->field.clazz);
+ bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
+ untweakLoader(referrer, resField->field.clazz);
+ if (!allowed) {
+ LOGI("DexOpt: access denied from %s to field %s.%s\n",
+ referrer->descriptor, resField->field.clazz->descriptor,
+ resField->field.name);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS_FIELD;
+ return NULL;
+ }
+
+ return resField;
+}
+
+
+/*
+ * Rewrite an iget/iput instruction. These all have the form:
+ * op vA, vB, field@CCCC
+ *
+ * Where vA holds the value, vB holds the object reference, and CCCC is
+ * the field reference constant pool offset. For a non-volatile field,
+ * we want to replace the opcode with "quickOpc" and replace CCCC with
+ * the byte offset from the start of the object. For a volatile field,
+ * we just want to replace the opcode with "volatileOpc".
+ *
+ * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
+ * field. If "quickOpc" is OP_NOP, and this is a non-volatile field,
+ * we don't do anything.
+ *
+ * "method" is the referring method.
+ */
+static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
+ OpCode volatileOpc)
+{
+ ClassObject* clazz = method->clazz;
+ u2 fieldIdx = insns[1];
+ InstField* instField;
+
+ instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
+ if (instField == NULL) {
+ LOGI("DexOpt: unable to optimize instance field ref "
+ "0x%04x at 0x%02x in %s.%s\n",
+ fieldIdx, (int) (insns - method->insns), clazz->descriptor,
+ method->name);
+ return false;
+ }
+
+ if (instField->byteOffset >= 65536) {
+ LOGI("DexOpt: field offset exceeds 64K (%d)\n", instField->byteOffset);
+ return false;
+ }
+
+ if (volatileOpc != OP_NOP && dvmIsVolatileField(&instField->field)) {
+ updateCode(method, insns, (insns[0] & 0xff00) | (u2) volatileOpc);
+ LOGV("DexOpt: rewrote ifield access %s.%s --> volatile\n",
+ instField->field.clazz->descriptor, instField->field.name);
+ } else if (quickOpc != OP_NOP) {
+ updateCode(method, insns, (insns[0] & 0xff00) | (u2) quickOpc);
+ updateCode(method, insns+1, (u2) instField->byteOffset);
+ LOGV("DexOpt: rewrote ifield access %s.%s --> %d\n",
+ instField->field.clazz->descriptor, instField->field.name,
+ instField->byteOffset);
+ } else {
+ LOGV("DexOpt: no rewrite of ifield access %s.%s\n",
+ instField->field.clazz->descriptor, instField->field.name);
+ }
+
+ return true;
+}
+
+/*
+ * Rewrite an sget/sput instruction. These all have the form:
+ * op vAA, field@BBBB
+ *
+ * Where vAA holds the value, and BBBB is the field reference constant
+ * pool offset. There is no "quick" form of static field accesses, so
+ * this is only useful for volatile fields.
+ *
+ * "method" is the referring method.
+ */
+static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc)
+{
+ ClassObject* clazz = method->clazz;
+ u2 fieldIdx = insns[1];
+ StaticField* staticField;
+
+ assert(volatileOpc != OP_NOP);
+
+ staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
+ if (staticField == NULL) {
+ LOGI("DexOpt: unable to optimize static field ref "
+ "0x%04x at 0x%02x in %s.%s\n",
+ fieldIdx, (int) (insns - method->insns), clazz->descriptor,
+ method->name);
+ return false;
+ }
+
+ if (dvmIsVolatileField(&staticField->field)) {
+ updateCode(method, insns, (insns[0] & 0xff00) | (u2) volatileOpc);
+ LOGV("DexOpt: rewrote sfield access %s.%s --> volatile\n",
+ staticField->field.clazz->descriptor, staticField->field.name);
+ }
+
+ return true;
+}
+
+/*
+ * Alternate version of dvmResolveMethod().
+ *
+ * Doesn't throw exceptions, and checks access on every lookup.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
+ MethodType methodType, VerifyError* pFailure)
+{
+ DvmDex* pDvmDex = referrer->pDvmDex;
+ Method* resMethod;
+
+ assert(methodType == METHOD_DIRECT ||
+ methodType == METHOD_VIRTUAL ||
+ methodType == METHOD_STATIC);
+
+ LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
+ referrer->descriptor);
+
+ resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
+ if (resMethod == NULL) {
+ const DexMethodId* pMethodId;
+ ClassObject* resClass;
+
+ pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
+
+ resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
+ if (resClass == NULL) {
+ /*
+ * Can't find the class that the method is a part of, or don't
+ * have permission to access the class.
+ */
+ LOGV("DexOpt: can't find called method's class (?.%s)\n",
+ dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
+ if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
+ return NULL;
+ }
+ if (dvmIsInterfaceClass(resClass)) {
+ /* method is part of an interface; this is wrong method for that */
+ LOGW("DexOpt: method is in an interface\n");
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /*
+ * We need to chase up the class hierarchy to find methods defined
+ * in super-classes. (We only want to check the current class
+ * if we're looking for a constructor.)
+ */
+ DexProto proto;
+ dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
+
+ if (methodType == METHOD_DIRECT) {
+ resMethod = dvmFindDirectMethod(resClass,
+ dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
+ } else {
+ /* METHOD_STATIC or METHOD_VIRTUAL */
+ resMethod = dvmFindMethodHier(resClass,
+ dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
+ }
+
+ if (resMethod == NULL) {
+ LOGV("DexOpt: couldn't find method '%s'\n",
+ dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_METHOD;
+ return NULL;
+ }
+ if (methodType == METHOD_STATIC) {
+ if (!dvmIsStaticMethod(resMethod)) {
+ LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
+ resClass->descriptor, resMethod->name);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+ return NULL;
+ }
+ } else if (methodType == METHOD_VIRTUAL) {
+ if (dvmIsStaticMethod(resMethod)) {
+ LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
+ resClass->descriptor, resMethod->name);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+ return NULL;
+ }
+ }
+
+ /* see if this is a pure-abstract method */
+ if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
+ LOGW("DexOpt: pure-abstract method '%s' in %s\n",
+ dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
+ resClass->descriptor);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /*
+ * Add it to the resolved table so we're faster on the next lookup.
+ *
+ * We can only do this for static methods if we're not in "dexopt",
+ * because the presence of a valid value in the resolution table
+ * implies that the class containing the static field has been
+ * initialized.
+ */
+ if (methodType != METHOD_STATIC || gDvm.optimizing)
+ dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+ }
+
+ LOGVV("--- found method %d (%s.%s)\n",
+ methodIdx, resMethod->clazz->descriptor, resMethod->name);
+
+ /* access allowed? */
+ tweakLoader(referrer, resMethod->clazz);
+ bool allowed = dvmCheckMethodAccess(referrer, resMethod);
+ untweakLoader(referrer, resMethod->clazz);
+ if (!allowed) {
+ IF_LOGI() {
+ char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+ LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
+ resMethod->clazz->descriptor, resMethod->name, desc,
+ referrer->descriptor);
+ free(desc);
+ }
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS_METHOD;
+ return NULL;
+ }
+
+ return resMethod;
+}
+
+/*
+ * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
+ * invoke-super/range. These all have the form:
+ * op vAA, meth@BBBB, reg stuff @CCCC
+ *
+ * We want to replace the method constant pool index BBBB with the
+ * vtable index.
+ */
+static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
+{
+ ClassObject* clazz = method->clazz;
+ Method* baseMethod;
+ u2 methodIdx = insns[1];
+
+ baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
+ if (baseMethod == NULL) {
+ LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
+ methodIdx,
+ (int) (insns - method->insns), clazz->descriptor,
+ method->name);
+ return false;
+ }
+
+ assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
+ (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
+ (insns[0] & 0xff) == OP_INVOKE_SUPER ||
+ (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
+
+ /*
+ * Note: Method->methodIndex is a u2 and is range checked during the
+ * initial load.
+ */
+ updateCode(method, insns, (insns[0] & 0xff00) | (u2) newOpc);
+ updateCode(method, insns+1, baseMethod->methodIndex);
+
+ //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
+ // method->clazz->descriptor, method->name,
+ // baseMethod->clazz->descriptor, baseMethod->name);
+
+ return true;
+}
+
+/*
+ * Rewrite invoke-direct, which has the form:
+ * op vAA, meth@BBBB, reg stuff @CCCC
+ *
+ * There isn't a lot we can do to make this faster, but in some situations
+ * we can make it go away entirely.
+ *
+ * This must only be used when the invoked method does nothing and has
+ * no return value (the latter being very important for verification).
+ */
+static bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
+{
+ ClassObject* clazz = method->clazz;
+ Method* calledMethod;
+ u2 methodIdx = insns[1];
+
+ calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
+ if (calledMethod == NULL) {
+ LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
+ methodIdx,
+ (int) (insns - method->insns), clazz->descriptor,
+ method->name);
+ return false;
+ }
+
+ /* TODO: verify that java.lang.Object() is actually empty! */
+ if (calledMethod->clazz == gDvm.classJavaLangObject &&
+ dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
+ {
+ /*
+ * Replace with "empty" instruction. DO NOT disturb anything
+ * else about it, as we want it to function the same as
+ * OP_INVOKE_DIRECT when debugging is enabled.
+ */
+ assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
+ updateCode(method, insns,
+ (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY);
+
+ //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
+ // method->clazz->descriptor, method->name,
+ // calledMethod->clazz->descriptor, calledMethod->name);
+ }
+
+ return true;
+}
+
+/*
+ * Resolve an interface method reference.
+ *
+ * No method access check here -- interface methods are always public.
+ *
+ * Returns NULL if the method was not found. Does not throw an exception.
+ */
+Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
+{
+ DvmDex* pDvmDex = referrer->pDvmDex;
+ Method* resMethod;
+ int i;
+
+ LOGVV("--- resolving interface method %d (referrer=%s)\n",
+ methodIdx, referrer->descriptor);
+
+ resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
+ if (resMethod == NULL) {
+ const DexMethodId* pMethodId;
+ ClassObject* resClass;
+
+ pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
+
+ resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
+ if (resClass == NULL) {
+ /* can't find the class that the method is a part of */
+ dvmClearOptException(dvmThreadSelf());
+ return NULL;
+ }
+ if (!dvmIsInterfaceClass(resClass)) {
+ /* whoops */
+ LOGI("Interface method not part of interface class\n");
+ return NULL;
+ }
+
+ const char* methodName =
+ dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
+ DexProto proto;
+ dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
+
+ LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
+ methodName, methodSig, resClass->descriptor);
+ resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
+ if (resMethod == NULL) {
+ /* scan superinterfaces and superclass interfaces */
+ LOGVV("+++ did not resolve immediately\n");
+ for (i = 0; i < resClass->iftableCount; i++) {
+ resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
+ methodName, &proto);
+ if (resMethod != NULL)
+ break;
+ }
+
+ if (resMethod == NULL) {
+ LOGVV("+++ unable to resolve method %s\n", methodName);
+ return NULL;
+ }
+ } else {
+ LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
+ resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
+ }
+
+ /* we're expecting this to be abstract */
+ if (!dvmIsAbstractMethod(resMethod)) {
+ char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+ LOGW("Found non-abstract interface method %s.%s %s\n",
+ resMethod->clazz->descriptor, resMethod->name, desc);
+ free(desc);
+ return NULL;
+ }
+
+ /*
+ * Add it to the resolved table so we're faster on the next lookup.
+ */
+ dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+ }
+
+ LOGVV("--- found interface method %d (%s.%s)\n",
+ methodIdx, resMethod->clazz->descriptor, resMethod->name);
+
+ /* interface methods are always public; no need to check access */
+
+ return resMethod;
+}
+
+/*
+ * See if the method being called can be rewritten as an inline operation.
+ * Works for invoke-virtual, invoke-direct, and invoke-static.
+ *
+ * Returns "true" if we replace it.
+ */
+static bool rewriteExecuteInline(Method* method, u2* insns,
+ MethodType methodType)
+{
+ const InlineSub* inlineSubs = gDvm.inlineSubs;
+ ClassObject* clazz = method->clazz;
+ Method* calledMethod;
+ u2 methodIdx = insns[1];
+
+ //return false;
+
+ calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
+ if (calledMethod == NULL) {
+ LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
+ return false;
+ }
+
+ while (inlineSubs->method != NULL) {
+ /*
+ if (extra) {
+ LOGI("comparing %p vs %p %s.%s %s\n",
+ inlineSubs->method, calledMethod,
+ inlineSubs->method->clazz->descriptor,
+ inlineSubs->method->name,
+ inlineSubs->method->signature);
+ }
+ */
+ if (inlineSubs->method == calledMethod) {
+ assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
+ (insns[0] & 0xff) == OP_INVOKE_STATIC ||
+ (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
+ updateCode(method, insns,
+ (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE);
+ updateCode(method, insns+1, (u2) inlineSubs->inlineIdx);
+
+ //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
+ // method->clazz->descriptor, method->name,
+ // calledMethod->clazz->descriptor, calledMethod->name);
+ return true;
+ }
+
+ inlineSubs++;
+ }
+
+ return false;
+}
+
+/*
+ * See if the method being called can be rewritten as an inline operation.
+ * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
+ *
+ * Returns "true" if we replace it.
+ */
+static bool rewriteExecuteInlineRange(Method* method, u2* insns,
+ MethodType methodType)
+{
+ const InlineSub* inlineSubs = gDvm.inlineSubs;
+ ClassObject* clazz = method->clazz;
+ Method* calledMethod;
+ u2 methodIdx = insns[1];
+
+ calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
+ if (calledMethod == NULL) {
+ LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
+ return false;
+ }
+
+ while (inlineSubs->method != NULL) {
+ if (inlineSubs->method == calledMethod) {
+ assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
+ (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
+ (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
+ updateCode(method, insns,
+ (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE);
+ updateCode(method, insns+1, (u2) inlineSubs->inlineIdx);
+
+ //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
+ // method->clazz->descriptor, method->name,
+ // calledMethod->clazz->descriptor, calledMethod->name);
+ return true;
+ }
+
+ inlineSubs++;
+ }
+
+ return false;
+}
diff --git a/vm/analysis/Optimize.h b/vm/analysis/Optimize.h
new file mode 100644
index 0000000..30f7eef
--- /dev/null
+++ b/vm/analysis/Optimize.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Bytecode optimization declarations.
+ */
+#ifndef _DALVIK_OPTIMIZE
+#define _DALVIK_OPTIMIZE
+
+/*
+ * Prep data structures.
+ */
+InlineSub* dvmCreateInlineSubsTable(void);
+void dvmFreeInlineSubsTable(InlineSub* inlineSubs);
+
+/*
+ * Entry point from DEX preparation.
+ */
+void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly);
+
+/*
+ * Abbreviated resolution functions, for use by optimization and verification
+ * code.
+ */
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+ VerifyError* pFailure);
+Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
+ MethodType methodType, VerifyError* pFailure);
+Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx);
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+ VerifyError* pFailure);
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+ VerifyError* pFailure);
+
+#endif /*_DALVIK_OPTIMIZE*/
diff --git a/vm/analysis/ReduceConstants.c b/vm/analysis/ReduceConstants.c
index ec7ba0f..69657e3 100644
--- a/vm/analysis/ReduceConstants.c
+++ b/vm/analysis/ReduceConstants.c
@@ -189,7 +189,7 @@
*/
/*
Output Formats
-
+
There are two possible output formats, from which we choose based on how
we plan to take advantage of the remapped constants. At most one of these
will appear in the DEX.
@@ -644,6 +644,7 @@
*
* Run through the instructions in this method, altering the constants used.
*/
+#if DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
static void updateUsedConstants(DexFile* pDexFile, const char* classDescriptor,
DexMethod* pDexMethod, void* arg)
{
@@ -666,6 +667,7 @@
//printf(" (no code)\n");
}
}
+#endif
/*
* Count up the bits and show a count.
@@ -682,9 +684,9 @@
static void summarizeResults(DvmDex* pDvmDex, ScanResults* pResults)
{
DexFile* pDexFile = pDvmDex->pDexFile;
+#if 0
int i;
-#if 0
for (i = 0; i < (int) pDvmDex->pDexFile->pHeader->typeIdsSize; i++) {
const DexTypeId* pDexTypeId;
const char* classDescr;
@@ -890,6 +892,7 @@
* Construct an "expanding" chunk, with maps that convert instructions
* with reduced constants back to their full original values.
*/
+#if DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
static bool constructExpandingDataChunk(IndexMapSet* pIndexMapSet)
{
int chunkLen = 0;
@@ -939,6 +942,7 @@
return true;
}
+#endif
/*
* Construct the "chunk" of data that will be appended to the optimized DEX
@@ -963,7 +967,6 @@
ScanResults* pResults)
{
IndexMapSet* pIndexMapSet;
- int setCount;
bool okay = true;
pIndexMapSet = calloc(1, sizeof(*pIndexMapSet));
@@ -1054,4 +1057,3 @@
return pIndexMapSet;
}
-
diff --git a/vm/analysis/RegisterMap.c b/vm/analysis/RegisterMap.c
index 744832f..f7d92cd 100644
--- a/vm/analysis/RegisterMap.c
+++ b/vm/analysis/RegisterMap.c
@@ -35,19 +35,20 @@
/* verbose logging */
#define REGISTER_MAP_VERBOSE false
+//#define REGISTER_MAP_STATS
// fwd
static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data);
static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap);
static int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2);
+#ifdef REGISTER_MAP_STATS
static void computeMapStats(RegisterMap* pMap, const Method* method);
+#endif
static RegisterMap* compressMapDifferential(const RegisterMap* pMap,\
const Method* meth);
static RegisterMap* uncompressMapDifferential(const RegisterMap* pMap);
-
-//#define REGISTER_MAP_STATS
#ifdef REGISTER_MAP_STATS
/*
* Generate some statistics on the register maps we create and use.
@@ -223,7 +224,7 @@
* since we don't count method entry as a GC point.
*/
gcPointCount = 0;
- for (i = 0; i < vdata->insnsSize; i++) {
+ for (i = 0; i < (int) vdata->insnsSize; i++) {
if (dvmInsnIsGcPoint(vdata->insnFlags, i))
gcPointCount++;
}
@@ -253,7 +254,7 @@
* Populate it.
*/
mapData = pMap->data;
- for (i = 0; i < vdata->insnsSize; i++) {
+ for (i = 0; i < (int) vdata->insnsSize; i++) {
if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
assert(vdata->addrRegs[i] != NULL);
if (format == kRegMapFormatCompact8) {
@@ -471,7 +472,6 @@
if (false) {
const char* cd = "Landroid/net/http/Request;";
const char* mn = "readResponse";
- const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
if (strcmp(vdata->method->clazz->descriptor, cd) == 0 &&
strcmp(vdata->method->name, mn) == 0)
{
@@ -508,7 +508,6 @@
dvmAbort();
}
- const u1* dataStart = rawMap;
const RegType* regs = vdata->addrRegs[addr];
if (regs == NULL) {
LOGE("GLITCH: addr %d has no data\n", addr);
@@ -1010,7 +1009,7 @@
/* sanity check to ensure this isn't called w/o external locking */
/* (if we use this at a time other than during GC, fix/remove this test) */
if (true) {
- if (!gDvm.zygote && pthread_mutex_trylock(&gDvm.gcHeapLock) == 0) {
+ if (!gDvm.zygote && dvmTryLockMutex(&gDvm.gcHeapLock) == 0) {
LOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time\n");
dvmAbort();
}
@@ -1243,9 +1242,9 @@
/*
* Compute some stats on an uncompressed register map.
*/
+#ifdef REGISTER_MAP_STATS
static void computeMapStats(RegisterMap* pMap, const Method* method)
{
-#ifdef REGISTER_MAP_STATS
MapStats* pStats = (MapStats*) gDvm.registerMapStats;
const u1 format = dvmRegisterMapGetFormat(pMap);
const u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
@@ -1361,9 +1360,8 @@
prevAddr = addr;
prevData = dataStart;
}
-#endif
}
-
+#endif
/*
* Compute the difference between two bit vectors.
@@ -3008,6 +3006,10 @@
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
case OP_INVOKE_VIRTUAL_QUICK:
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
@@ -3031,10 +3033,6 @@
case OP_UNUSED_E5:
case OP_UNUSED_E6:
case OP_UNUSED_E7:
- case OP_UNUSED_E8:
- case OP_UNUSED_E9:
- case OP_UNUSED_EA:
- case OP_UNUSED_EB:
case OP_BREAKPOINT:
case OP_UNUSED_ED:
case OP_UNUSED_F1:
@@ -3272,4 +3270,3 @@
}
#endif /*#if 0*/
-
diff --git a/vm/analysis/RegisterMap.h b/vm/analysis/RegisterMap.h
index dc17b1d..7897d45 100644
--- a/vm/analysis/RegisterMap.h
+++ b/vm/analysis/RegisterMap.h
@@ -228,50 +228,6 @@
*/
void dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder);
-
-/*
- * Generate the register map for a previously-verified method.
- *
- * Returns a pointer to a newly-allocated RegisterMap.
- */
-//RegisterMap* dvmGenerateRegisterMap(const Method* meth);
-
-/*
- * Various bits of data generated by the verifier, wrapped up in a package
- * for ease of use by the register map generator.
- */
-typedef struct VerifierData {
- /*
- * The method we're working on.
- */
- const Method* method;
-
- /*
- * Number of instructions in the method.
- */
- int insnsSize;
-
- /*
- * Number of registers we track for each instruction. This is equal
- * to the method's declared "registersSize". (Does not include the
- * pending return value.)
- */
- int insnRegCount;
-
- /*
- * Instruction widths and flags, one entry per code unit.
- */
- InsnFlags* insnFlags;
-
- /*
- * Array of SRegType arrays, one entry per code unit. We only need
- * entries for code units that hold the start of an "interesting"
- * instruction. For register map generation, we're only interested
- * in GC points.
- */
- RegType** addrRegs;
-} VerifierData;
-
/*
* Generate the register map for a method that has just been verified
* (i.e. we're doing this as part of verification).
diff --git a/vm/analysis/VerifySubs.c b/vm/analysis/VerifySubs.c
index 39d6dc8..2285aef 100644
--- a/vm/analysis/VerifySubs.c
+++ b/vm/analysis/VerifySubs.c
@@ -32,52 +32,35 @@
* If "pNewInstanceCount" is not NULL, it will be set to the number of
* new-instance instructions in the method.
*
+ * Performs some static checks, notably:
+ * - opcode of first instruction begins at index 0
+ * - only documented instructions may appear
+ * - each instruction follows the last
+ * - last byte of last instruction is at (code_length-1)
+ *
* Logs an error and returns "false" on failure.
*/
bool dvmComputeCodeWidths(const Method* meth, InsnFlags* insnFlags,
int* pNewInstanceCount)
{
- const int insnCount = dvmGetMethodInsnsSize(meth);
+ size_t insnCount = dvmGetMethodInsnsSize(meth);
const u2* insns = meth->insns;
bool result = false;
int newInstanceCount = 0;
int i;
- for (i = 0; i < insnCount; /**/) {
- int width;
-
- /*
- * Switch tables and array data tables are identified with
- * "extended NOP" opcodes. They contain no executable code,
- * so we can just skip past them.
- */
- if (*insns == kPackedSwitchSignature) {
- width = 4 + insns[1] * 2;
- } else if (*insns == kSparseSwitchSignature) {
- width = 2 + insns[1] * 4;
- } else if (*insns == kArrayDataSignature) {
- u4 size = insns[2] | (((u4)insns[3]) << 16);
- width = 4 + (insns[1] * size + 1) / 2;
- } else {
- int instr = *insns & 0xff;
- width = dexGetInstrWidthAbs(gDvm.instrWidth, instr);
- if (width == 0) {
- LOG_VFY_METH(meth,
- "VFY: invalid post-opt instruction (0x%x)\n", instr);
- LOGI("### instr=%d width=%d table=%d\n",
- instr, width, dexGetInstrWidthAbs(gDvm.instrWidth, instr));
- goto bail;
- }
- if (width < 0 || width > 5) {
- LOGE("VFY: bizarre width value %d\n", width);
- dvmAbort();
- }
-
- if (instr == OP_NEW_INSTANCE)
- newInstanceCount++;
+ for (i = 0; i < (int) insnCount; /**/) {
+ size_t width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns);
+ if (width == 0) {
+ LOG_VFY_METH(meth,
+ "VFY: invalid post-opt instruction (0x%04x)\n", *insns);
+ goto bail;
}
+ if ((*insns & 0xff) == OP_NEW_INSTANCE)
+ newInstanceCount++;
+
if (width > 65535) {
LOG_VFY_METH(meth, "VFY: insane width %d\n", width);
goto bail;
@@ -113,7 +96,6 @@
bool dvmSetTryFlags(const Method* meth, InsnFlags* insnFlags)
{
u4 insnsSize = dvmGetMethodInsnsSize(meth);
- DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
const DexCode* pCode = dvmGetMethodCode(meth);
u4 triesSize = pCode->triesSize;
const DexTry* pTries;
@@ -311,7 +293,6 @@
int curOffset, bool selfOkay)
{
const int insnCount = dvmGetMethodInsnsSize(meth);
- const u2* insns = meth->insns + curOffset;
int offset, absOffset;
bool isConditional;
@@ -411,7 +392,6 @@
int curOffset, int* pOffset, bool* pConditional)
{
const u2* insns = meth->insns + curOffset;
- int tmp;
switch (*insns & 0xff) {
case OP_GOTO:
@@ -474,4 +454,3 @@
else
return kRegTypeInteger;
}
-
diff --git a/vm/analysis/VerifySubs.h b/vm/analysis/VerifySubs.h
index a87c6f1..9e05e9d 100644
--- a/vm/analysis/VerifySubs.h
+++ b/vm/analysis/VerifySubs.h
@@ -22,11 +22,13 @@
/*
* InsnFlags is a 32-bit integer with the following layout:
- * 0-15 instruction length (or 0 if this address doesn't hold an opcode)
- * 16 opcode flag (indicating this address holds an opcode)
- * 17 try block (indicating exceptions thrown here may be caught locally)
- * 30 visited (verifier has examined this instruction at least once)
- * 31 changed (set/cleared as bytecode verifier runs)
+ * 0-15 instruction length (or 0 if this address doesn't hold an opcode)
+ * 16-31 single bit flags:
+ * InTry: in "try" block; exceptions thrown here may be caught locally
+ * BranchTarget: other instructions can branch to this instruction
+ * GcPoint: this instruction is a GC safe point
+ * Visited: verifier has examined this instruction at least once
+ * Changed: set/cleared as bytecode verifier runs
*/
typedef u4 InsnFlags;
diff --git a/vm/arch/arm/CallEABI.S b/vm/arch/arm/CallEABI.S
index 9717e3b..e0d4f5c 100644
--- a/vm/arch/arm/CallEABI.S
+++ b/vm/arch/arm/CallEABI.S
@@ -36,7 +36,7 @@
Function prototype:
void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
- const u4* argv, const char* signature, void* func, JValue* pReturn)
+ const u4* argv, const char* signature, void* func, JValue* pReturn)
The method we are calling has the form:
diff --git a/vm/arch/arm/CallOldABI.S b/vm/arch/arm/CallOldABI.S
index c098218..2463d3c 100644
--- a/vm/arch/arm/CallOldABI.S
+++ b/vm/arch/arm/CallOldABI.S
@@ -30,7 +30,7 @@
Function prototype:
void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
- const u4* argv, const char* signature, void* func, JValue* pReturn)
+ const u4* argv, const char* signature, void* func, JValue* pReturn)
The method we are calling has the form:
diff --git a/vm/arch/arm/HintsEABI.c b/vm/arch/arm/HintsEABI.c
index d842859..3e27e5a 100644
--- a/vm/arch/arm/HintsEABI.c
+++ b/vm/arch/arm/HintsEABI.c
@@ -59,7 +59,7 @@
const char* sig = dexProtoGetShorty(proto);
int padFlags, jniHints;
char sigByte;
- int stackOffset, padMask, hints;
+ int stackOffset, padMask;
stackOffset = padFlags = 0;
padMask = 0x00000001;
diff --git a/vm/arch/generic/Call.c b/vm/arch/generic/Call.c
index 4f084d0..a39b761 100644
--- a/vm/arch/generic/Call.c
+++ b/vm/arch/generic/Call.c
@@ -22,8 +22,6 @@
#include "Dalvik.h"
#include "ffi.h"
-#include <assert.h>
-
/*
* Convert a signature type character to an FFI type.
*/
@@ -104,4 +102,3 @@
ffi_call(&cif, FFI_FN(func), pReturn, values);
}
-
diff --git a/vm/arch/x86-atom/Call386ABI.S b/vm/arch/x86-atom/Call386ABI.S
index 1146c2d..db1541e 100644
--- a/vm/arch/x86-atom/Call386ABI.S
+++ b/vm/arch/x86-atom/Call386ABI.S
@@ -16,7 +16,7 @@
/*
* File: CallABI.S
*
- * Code: facitliates call to native code C and C++ routines.
+ * Code: facilitates call to native code C and C++ routines.
*
*/
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 6a58d8b..2b0ad52 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -40,7 +40,7 @@
}
gDvmJit.compilerQueueLength--;
if (gDvmJit.compilerQueueLength == 0) {
- int cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
+ dvmSignalCond(&gDvmJit.compilerQueueEmpty);
}
/* Remember the high water mark of the queue length */
@@ -95,6 +95,7 @@
newOrder->pc = pc;
newOrder->kind = kind;
newOrder->info = info;
+ newOrder->result.methodCompilationAborted = NULL;
newOrder->result.codeAddress = NULL;
newOrder->result.discardResult =
(kind == kWorkOrderTraceDebug) ? true : false;
@@ -153,6 +154,8 @@
return false;
}
+ gDvmJit.pageSizeMask = getpagesize() - 1;
+
/* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
// LOGD("Code cache starts at %p", gDvmJit.codeCache);
@@ -177,6 +180,15 @@
/* Only flush the part in the code cache that is being used now */
cacheflush((intptr_t) gDvmJit.codeCache,
(intptr_t) gDvmJit.codeCache + templateSize, 0);
+
+ int result = mprotect(gDvmJit.codeCache, gDvmJit.codeCacheSize,
+ PROTECT_CODE_CACHE_ATTRS);
+
+ if (result == -1) {
+ LOGE("Failed to remove the write permission for the code cache");
+ dvmAbort();
+ }
+
return true;
}
@@ -261,6 +273,7 @@
/* Reset the JitEntry table contents to the initial unpopulated state */
dvmJitResetTable();
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
/*
* Wipe out the code cache content to force immediate crashes if
* stale JIT'ed code is invoked.
@@ -271,6 +284,8 @@
cacheflush((intptr_t) gDvmJit.codeCache,
(intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
/* Reset the current mark of used bytes to the end of template code */
gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
gDvmJit.numCompilations = 0;
@@ -337,9 +352,10 @@
dvmLockMutex(&gDvmJit.compilerLock);
-#if defined(WITH_JIT_TUNING)
/* Track method-level compilation statistics */
gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
+
+#if defined(WITH_JIT_TUNING)
gDvm.verboseShutdown = true;
#endif
@@ -506,9 +522,6 @@
static void *compilerThreadStart(void *arg)
{
- int ret;
- struct timespec ts;
-
dvmChangeStatus(NULL, THREAD_VMWAIT);
/*
@@ -577,7 +590,7 @@
do {
CompilerWorkOrder work = workDequeue();
dvmUnlockMutex(&gDvmJit.compilerLock);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
u8 startTime = dvmGetRelativeTimeUsec();
#endif
/*
@@ -591,7 +604,7 @@
* of the vm but this should be acceptable.
*/
if (!gDvmJit.blockingMode)
- dvmCheckSuspendPending(NULL);
+ dvmCheckSuspendPending(dvmThreadSelf());
/* Is JitTable filling up? */
if (gDvmJit.jitTableEntriesUsed >
(gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
@@ -615,14 +628,16 @@
}
if (aborted || !compileOK) {
dvmCompilerArenaReset();
- work.result.codeAddress = gDvmJit.interpretTemplate;
- } else if (!work.result.discardResult) {
+ } else if (!work.result.discardResult &&
+ work.result.codeAddress) {
+ /* Make sure that proper code addr is installed */
+ assert(work.result.codeAddress != NULL);
dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
work.result.instructionSet);
}
}
free(work.info);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
#endif
dvmLockMutex(&gDvmJit.compilerLock);
@@ -649,6 +664,7 @@
dvmInitMutex(&gDvmJit.compilerLock);
dvmInitMutex(&gDvmJit.compilerICPatchLock);
+ dvmInitMutex(&gDvmJit.codeCacheProtectionLock);
dvmLockMutex(&gDvmJit.compilerLock);
pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
@@ -725,7 +741,16 @@
dvmLockMutex(&gDvmJit.tableLock);
jitActive = gDvmJit.pProfTable != NULL;
+
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
+#elif defined(WITH_DEBUGGER)
+ jitActivate = !gDvm.debuggerActive;
+#elif defined(WITH_PROFILER)
+ jitActivate = !(gDvm.activeProfilers > 0);
+#else
+ jitActivate = true;
+#endif
if (jitActivate && !jitActive) {
gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index ba23d7d..1d074f2 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -29,10 +29,50 @@
#define COMPILER_WORK_QUEUE_SIZE 100
#define COMPILER_IC_PATCH_QUEUE_SIZE 64
+/* Architectural-independent parameters for predicted chains */
+#define PREDICTED_CHAIN_CLAZZ_INIT 0
+#define PREDICTED_CHAIN_METHOD_INIT 0
+#define PREDICTED_CHAIN_COUNTER_INIT 0
+/* A fake value which will avoid initialization and won't match any class */
+#define PREDICTED_CHAIN_FAKE_CLAZZ 0xdeadc001
+/* Has to be positive */
+#define PREDICTED_CHAIN_COUNTER_AVOID 0x7fffffff
+/* Rechain after this many misses - shared globally and has to be positive */
+#define PREDICTED_CHAIN_COUNTER_RECHAIN 8192
+
#define COMPILER_TRACED(X)
#define COMPILER_TRACEE(X)
#define COMPILER_TRACE_CHAINING(X)
+/* Macro to change the permissions applied to a chunk of the code cache */
+#if !defined(WITH_JIT_TUNING)
+#define PROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC)
+#define UNPROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC | PROT_WRITE)
+#else
+/* When doing JIT profiling always grant the write permission */
+#define PROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC | \
+ (gDvmJit.profile ? PROT_WRITE : 0))
+#define UNPROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC | PROT_WRITE)
+#endif
+
+/* Acquire the lock before removing PROT_WRITE from the specified mem region */
+#define UNPROTECT_CODE_CACHE(addr, size) \
+ { \
+ dvmLockMutex(&gDvmJit.codeCacheProtectionLock); \
+ mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask), \
+ (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask), \
+ (UNPROTECT_CODE_CACHE_ATTRS)); \
+ }
+
+/* Add the PROT_WRITE to the specified memory region then release the lock */
+#define PROTECT_CODE_CACHE(addr, size) \
+ { \
+ mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask), \
+ (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask), \
+ (PROTECT_CODE_CACHE_ATTRS)); \
+ dvmUnlockMutex(&gDvmJit.codeCacheProtectionLock); \
+ }
+
typedef enum JitInstructionSetType {
DALVIK_JIT_NONE = 0,
DALVIK_JIT_ARM,
@@ -47,6 +87,7 @@
void *codeAddress;
JitInstructionSetType instructionSet;
bool discardResult; // Used for debugging divergence and IC patching
+ bool methodCompilationAborted; // Cannot compile the whole method
Thread *requestingThread; // For debugging purpose
} JitTranslationInfo;
@@ -68,9 +109,9 @@
/* Chain cell for predicted method invocation */
typedef struct PredictedChainingCell {
u4 branch; /* Branch to chained destination */
- const ClassObject *clazz; /* key #1 for prediction */
- const Method *method; /* key #2 to lookup native PC from dalvik PC */
- u4 counter; /* counter to patch the chaining cell */
+ const ClassObject *clazz; /* key for prediction */
+ const Method *method; /* to lookup native PC from dalvik PC */
+ const ClassObject *stagedClazz; /* possible next key for prediction */
} PredictedChainingCell;
/* Work order for inline cache patching */
@@ -101,8 +142,8 @@
kSVSStart = 1, // Shadow space set up, running compiled code
kSVSPunt = 2, // Exiting compiled code by punting
kSVSSingleStep = 3, // Exiting compiled code by single stepping
- kSVSTraceSelectNoChain = 4,// Exiting compiled code by trace select no chain
- kSVSTraceSelect = 5, // Exiting compiled code by trace select
+ kSVSNoProfile = 4, // Exiting compiled code and don't collect profiles
+ kSVSTraceSelect = 5, // Exiting compiled code and compile the next pc
kSVSNormal = 6, // Exiting compiled code normally
kSVSNoChain = 7, // Exiting compiled code by no chain
kSVSBackwardBranch = 8, // Exiting compiled code with backward branch trace
@@ -118,21 +159,41 @@
} jitHint;
/*
- * Element of a Jit trace description. Describes a contiguous
- * sequence of Dalvik byte codes, the last of which can be
- * associated with a hint.
- * Dalvik byte code
+ * Element of a Jit trace description. If the isCode bit is set, it describes
+ * a contiguous sequence of Dalvik byte codes.
*/
typedef struct {
- u2 startOffset; // Starting offset for trace run
+ unsigned isCode:1; // If set denotes code fragments
unsigned numInsts:8; // Number of Byte codes in run
unsigned runEnd:1; // Run ends with last byte code
- jitHint hint:7; // Hint to apply to final code of run
+ jitHint hint:6; // Hint to apply to final code of run
+ u2 startOffset; // Starting offset for trace run
} JitCodeDesc;
+/*
+ * A complete list of trace runs passed to the compiler looks like the
+ * following:
+ * frag1
+ * frag2
+ * frag3
+ * meta1
+ * meta2
+ * frag4
+ *
+ * frags 1-4 have the "isCode" field set, and metas 1-2 are plain pointers or
+ * pointers to auxiliary data structures as long as the LSB is null.
+ * The meaning of the meta content is loosely defined. It is usually the code
+ * fragment right before the first meta field (frag3 in this case) to
+ * understand and parse them. Frag4 could be a dummy one with 0 "numInsts" but
+ * the "runEnd" field set.
+ *
+ * For example, if a trace run contains a method inlining target, the class
+ * type of "this" and the currently resolved method pointer are two instances
+ * of meta information stored there.
+ */
typedef union {
JitCodeDesc frag;
- void* hint;
+ void* meta;
} JitTraceRun;
/*
@@ -143,16 +204,42 @@
*/
typedef struct {
const Method* method;
- JitTraceRun trace[];
+ JitTraceRun trace[0]; // Variable-length trace descriptors
} JitTraceDescription;
+typedef enum JitMethodAttributes {
+ kIsCallee = 0, /* Code is part of a callee (invoked by a hot trace) */
+ kIsHot, /* Code is part of a hot trace */
+ kIsLeaf, /* Method is leaf */
+ kIsEmpty, /* Method is empty */
+ kIsThrowFree, /* Method doesn't throw */
+ kIsGetter, /* Method fits the getter pattern */
+ kIsSetter, /* Method fits the setter pattern */
+} JitMethodAttributes;
+
+#define METHOD_IS_CALLEE (1 << kIsCallee)
+#define METHOD_IS_HOT (1 << kIsHot)
+#define METHOD_IS_LEAF (1 << kIsLeaf)
+#define METHOD_IS_EMPTY (1 << kIsEmpty)
+#define METHOD_IS_THROW_FREE (1 << kIsThrowFree)
+#define METHOD_IS_GETTER (1 << kIsGetter)
+#define METHOD_IS_SETTER (1 << kIsSetter)
+
typedef struct CompilerMethodStats {
const Method *method; // Used as hash entry signature
int dalvikSize; // # of bytes for dalvik bytecodes
int compiledDalvikSize; // # of compiled dalvik bytecodes
int nativeSize; // # of bytes for produced native code
+ int attributes; // attribute vector
} CompilerMethodStats;
+struct CompilationUnit;
+struct BasicBlock;
+struct SSARepresentation;
+struct GrowableList;
+struct JitEntry;
+struct MIR;
+
bool dvmCompilerSetupCodeCache(void);
bool dvmCompilerArchInit(void);
void dvmCompilerArchDump(void);
@@ -160,20 +247,20 @@
void dvmCompilerShutdown(void);
bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
void *dvmCheckCodeCache(void *method);
-bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+ bool isCallee);
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+ const DecodedInstruction *insn);
+bool dvmCompileMethod(struct CompilationUnit *cUnit, const Method *method,
+ JitTranslationInfo *info);
bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
JitTranslationInfo *info, jmp_buf *bailPtr);
void dvmCompilerDumpStats(void);
void dvmCompilerDrainQueue(void);
void dvmJitUnchainAll(void);
void dvmCompilerSortAndPrintTraceProfiles(void);
-
-struct CompilationUnit;
-struct BasicBlock;
-struct SSARepresentation;
-struct GrowableList;
-struct JitEntry;
-
+void dvmCompilerPerformSafePointChecks(void);
+void dvmCompilerInlineMIR(struct CompilationUnit *cUnit);
void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
int dvmConvertSSARegToDalvik(struct CompilationUnit *cUnit, int ssaReg);
void dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
@@ -186,7 +273,7 @@
struct BasicBlock *bb);
void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
struct BasicBlock *bb);
-char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn);
+char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, char *note);
char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit,
struct SSARepresentation *ssaRep);
void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
@@ -194,4 +281,5 @@
void dvmCompilerStateRefresh(void);
JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
const struct JitEntry *desc);
+void *dvmCompilerGetInterpretTemplate();
#endif /* _DALVIK_VM_COMPILER */
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 2bf243d..21aadec 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -54,9 +54,11 @@
kChainingCellGap,
/* Don't insert new fields between Gap and Last */
kChainingCellLast = kChainingCellGap + 1,
- kEntryBlock,
+ kMethodEntryBlock,
+ kTraceEntryBlock,
kDalvikByteCode,
- kExitBlock,
+ kTraceExitBlock,
+ kMethodExitBlock,
kPCReconstruction,
kExceptionHandling,
} BBType;
@@ -82,6 +84,7 @@
kMirOpNullNRangeDownCheck,
kMirOpLowerBound,
kMirOpPunt,
+ kMirOpCheckInlinePrediction, // Gen checks for predicted inlining
kMirOpLast,
};
@@ -92,12 +95,24 @@
kMIRNullCheckOnly,
kMIRIgnoreRangeCheck,
kMIRRangeCheckOnly,
+ kMIRInlined, // Invoke is inlined (ie dead)
+ kMIRInlinedPred, // Invoke is inlined via prediction
+ kMIRCallee, // Instruction is inlined from callee
} MIROptimizationFlagPositons;
#define MIR_IGNORE_NULL_CHECK (1 << kMIRIgnoreNullCheck)
#define MIR_NULL_CHECK_ONLY (1 << kMIRNullCheckOnly)
#define MIR_IGNORE_RANGE_CHECK (1 << kMIRIgnoreRangeCheck)
#define MIR_RANGE_CHECK_ONLY (1 << kMIRRangeCheckOnly)
+#define MIR_INLINED (1 << kMIRInlined)
+#define MIR_INLINED_PRED (1 << kMIRInlinedPred)
+#define MIR_CALLEE (1 << kMIRCallee)
+
+typedef struct CallsiteInfo {
+ const ClassObject *clazz;
+ const Method *method;
+ LIR *misPredBranchOver;
+} CallsiteInfo;
typedef struct MIR {
DecodedInstruction dalvikInsn;
@@ -108,6 +123,12 @@
struct SSARepresentation *ssaRep;
int OptimizationFlags;
int seqNum;
+ union {
+ // Used by the inlined insn from the callee to find the mother method
+ const Method *calleeMethod;
+ // Used by the inlined invoke to find the class and method pointers
+ CallsiteInfo *callsiteInfo;
+ } meta;
} MIR;
struct BasicBlockDataFlow;
@@ -119,6 +140,7 @@
const Method *containingMethod; // For blocks from the callee
BBType blockType;
bool needFallThroughBranch; // For blocks ended due to length limit
+ bool isFallThroughFromInvoke; // True means the block needs alignment
MIR *firstMIRInsn;
MIR *lastMIRInsn;
struct BasicBlock *fallThrough;
@@ -150,8 +172,10 @@
bool allSingleStep;
bool halveInstCount;
bool executionCount; // Add code to count trace executions
- bool hasLoop;
+ bool hasLoop; // Contains a loop
+ bool hasInvoke; // Contains an invoke instruction
bool heapMemOp; // Mark mem ops for self verification
+ bool wholeMethod;
int numChainingCells[kChainingCellGap];
LIR *firstChainingLIR[kChainingCellGap];
LIR *chainingCellBottom;
@@ -196,6 +220,8 @@
void dvmCompilerPrependMIR(BasicBlock *bb, MIR *mir);
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR);
+
void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir);
void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR);
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
index 4ab650d..551edb8 100644
--- a/vm/compiler/CompilerUtility.h
+++ b/vm/compiler/CompilerUtility.h
@@ -26,6 +26,7 @@
bool dvmCompilerHeapInit(void);
typedef struct ArenaMemBlock {
+ size_t blockSize;
size_t bytesAllocated;
struct ArenaMemBlock *next;
char ptr[0];
@@ -42,8 +43,6 @@
} GrowableList;
#define GET_ELEM_N(LIST, TYPE, N) (((TYPE*) LIST->elemList)[N])
-#define MIN(x,y) (((x) < (y)) ? (x) : (y))
-#define MAX(x,y) (((x) > (y)) ? (x) : (y))
struct LIR;
diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c
index 787ac15..89c5b35 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -17,7 +17,7 @@
#include "Dalvik.h"
#include "Dataflow.h"
#include "Loop.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
/*
* Main table containing data flow attributes for each bytecode. The first
@@ -234,130 +234,130 @@
DF_NOP,
// 44 OP_AGET vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 45 OP_AGET_WIDE vAA, vBB, vCC
- DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 46 OP_AGET_OBJECT vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 47 OP_AGET_BOOLEAN vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 48 OP_AGET_BYTE vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 49 OP_AGET_CHAR vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 4A OP_AGET_SHORT vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 4B OP_APUT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 4C OP_APUT_WIDE vAA, vBB, vCC
- DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2,
+ DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2 | DF_IS_SETTER,
// 4D OP_APUT_OBJECT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 4E OP_APUT_BOOLEAN vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 4F OP_APUT_BYTE vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 50 OP_APUT_CHAR vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 51 OP_APUT_SHORT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 52 OP_IGET vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 53 OP_IGET_WIDE vA, vB, field@CCCC
- DF_DA_WIDE | DF_UB,
+ DF_DA_WIDE | DF_UB | DF_IS_GETTER,
// 54 OP_IGET_OBJECT vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 55 OP_IGET_BOOLEAN vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 56 OP_IGET_BYTE vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 57 OP_IGET_CHAR vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 58 OP_IGET_SHORT vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 59 OP_IPUT vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5A OP_IPUT_WIDE vA, vB, field@CCCC
- DF_UA_WIDE | DF_UB,
+ DF_UA_WIDE | DF_UB | DF_IS_SETTER,
// 5B OP_IPUT_OBJECT vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5C OP_IPUT_BOOLEAN vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5D OP_IPUT_BYTE vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5E OP_IPUT_CHAR vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5F OP_IPUT_SHORT vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 60 OP_SGET vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 61 OP_SGET_WIDE vAA, field@BBBB
- DF_DA_WIDE,
+ DF_DA_WIDE | DF_IS_GETTER,
// 62 OP_SGET_OBJECT vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 63 OP_SGET_BOOLEAN vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 64 OP_SGET_BYTE vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 65 OP_SGET_CHAR vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 66 OP_SGET_SHORT vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 67 OP_SPUT vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 68 OP_SPUT_WIDE vAA, field@BBBB
- DF_UA_WIDE,
+ DF_UA_WIDE | DF_IS_SETTER,
// 69 OP_SPUT_OBJECT vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6A OP_SPUT_BOOLEAN vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6B OP_SPUT_BYTE vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6C OP_SPUT_CHAR vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6D OP_SPUT_SHORT vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6E OP_INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
DF_FORMAT_35C,
@@ -710,32 +710,32 @@
// E2 OP_USHR_INT_LIT8 vAA, vBB, #+CC
DF_DA | DF_UB,
- // E3 OP_UNUSED_E3
- DF_NOP,
+ // E3 OP_IGET_VOLATILE
+ DF_DA | DF_UB,
- // E4 OP_UNUSED_E4
- DF_NOP,
+ // E4 OP_IPUT_VOLATILE
+ DF_UA | DF_UB,
- // E5 OP_UNUSED_E5
- DF_NOP,
+ // E5 OP_SGET_VOLATILE
+ DF_DA,
- // E6 OP_UNUSED_E6
- DF_NOP,
+ // E6 OP_SPUT_VOLATILE
+ DF_UA,
- // E7 OP_UNUSED_E7
- DF_NOP,
+ // E7 OP_IGET_OBJECT_VOLATILE
+ DF_DA | DF_UB,
- // E8 OP_UNUSED_E8
- DF_NOP,
+ // E8 OP_IGET_WIDE_VOLATILE
+ DF_DA_WIDE | DF_UB,
- // E9 OP_UNUSED_E9
- DF_NOP,
+ // E9 OP_IPUT_WIDE_VOLATILE
+ DF_UA_WIDE | DF_UB,
- // EA OP_UNUSED_EA
- DF_NOP,
+ // EA OP_SGET_WIDE_VOLATILE
+ DF_DA_WIDE,
- // EB OP_UNUSED_EB
- DF_NOP,
+ // EB OP_SPUT_WIDE_VOLATILE
+ DF_UA_WIDE,
// EC OP_BREAKPOINT
DF_NOP,
@@ -756,22 +756,22 @@
DF_NOP,
// F2 OP_IGET_QUICK
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// F3 OP_IGET_WIDE_QUICK
- DF_DA_WIDE | DF_UB,
+ DF_DA_WIDE | DF_UB | DF_IS_GETTER,
// F4 OP_IGET_OBJECT_QUICK
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// F5 OP_IPUT_QUICK
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// F6 OP_IPUT_WIDE_QUICK
- DF_UA_WIDE | DF_UB,
+ DF_UA_WIDE | DF_UB | DF_IS_SETTER,
// F7 OP_IPUT_OBJECT_QUICK
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// F8 OP_INVOKE_VIRTUAL_QUICK
DF_FORMAT_35C,
@@ -785,14 +785,14 @@
// FB OP_INVOKE_SUPER_QUICK_RANGE
DF_FORMAT_3RC,
- // FC OP_UNUSED_FC
- DF_NOP,
+ // FC OP_IPUT_OBJECT_VOLATILE
+ DF_UA | DF_UB,
- // FD OP_UNUSED_FD
- DF_NOP,
+ // FD OP_SGET_OBJECT_VOLATILE
+ DF_DA,
- // FE OP_UNUSED_FE
- DF_NOP,
+ // FE OP_SPUT_OBJECT_VOLATILE
+ DF_UA,
// FF OP_UNUSED_FF
DF_NOP,
@@ -818,7 +818,8 @@
* and subscript pair. Each SSA register can be used to index the
* ssaToDalvikMap list to get the subscript[31..16]/dalvik_reg[15..0] mapping.
*/
-char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn)
+char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn,
+ char *note)
{
char buffer[256];
int opcode = insn->opCode;
@@ -826,38 +827,37 @@
char *ret;
buffer[0] = 0;
- strcpy(buffer, getOpcodeName(opcode));
+ strcpy(buffer, dexGetOpcodeName(opcode));
+
+ if (note)
+ strcat(buffer, note);
if (dfAttributes & DF_FORMAT_35C) {
unsigned int i;
for (i = 0; i < insn->vA; i++) {
if (i != 0) strcat(buffer, ",");
- sprintf(buffer + strlen(buffer), " v%d", insn->arg[i]);
+ snprintf(buffer + strlen(buffer), 256, " v%d", insn->arg[i]);
}
}
else if (dfAttributes & DF_FORMAT_3RC) {
- sprintf(buffer + strlen(buffer),
- " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
+ snprintf(buffer + strlen(buffer), 256,
+ " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
}
else {
if (dfAttributes & DF_A_IS_REG) {
- sprintf(buffer + strlen(buffer), " v%d", insn->vA);
+ snprintf(buffer + strlen(buffer), 256, " v%d", insn->vA);
}
if (dfAttributes & DF_B_IS_REG) {
- sprintf(buffer + strlen(buffer),
- ", v%d", insn->vB);
+ snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vB);
}
else {
- sprintf(buffer + strlen(buffer),
- ", (#%d)", insn->vB);
+ snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vB);
}
if (dfAttributes & DF_C_IS_REG) {
- sprintf(buffer + strlen(buffer),
- ", v%d", insn->vC);
+ snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vC);
}
else {
- sprintf(buffer + strlen(buffer),
- ", (#%d)", insn->vC);
+ snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vC);
}
}
int length = strlen(buffer) + 1;
@@ -934,7 +934,7 @@
BitVector *useV, *defV, *liveInV;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock) {
+ bb->blockType != kTraceEntryBlock) {
return;
}
@@ -1041,7 +1041,7 @@
{
MIR *mir;
- if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock) {
+ if (bb->blockType != kDalvikByteCode && bb->blockType != kTraceEntryBlock) {
return;
}
@@ -1168,8 +1168,6 @@
int dfAttributes =
dvmCompilerDataFlowAttributes[mir->dalvikInsn.opCode];
- int numUses = 0;
-
DecodedInstruction *dInsn = &mir->dalvikInsn;
if (!(dfAttributes & DF_HAS_DEFS)) continue;
@@ -1242,7 +1240,7 @@
MIR *mir;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock) {
+ bb->blockType != kTraceEntryBlock) {
return;
}
@@ -1438,7 +1436,7 @@
for (i = 0; i < cUnit->numBlocks; i++) {
BasicBlock *bb = cUnit->blockList[i];
if (bb->blockType == kDalvikByteCode ||
- bb->blockType == kEntryBlock) {
+ bb->blockType == kTraceEntryBlock) {
bb->dataFlowInfo = dvmCompilerNew(sizeof(BasicBlockDataFlow), true);
}
}
diff --git a/vm/compiler/Dataflow.h b/vm/compiler/Dataflow.h
index 72c8b25..f3d3984 100644
--- a/vm/compiler/Dataflow.h
+++ b/vm/compiler/Dataflow.h
@@ -41,6 +41,8 @@
kFPA,
kFPB,
kFPC,
+ kGetter,
+ kSetter,
} DataFlowAttributes;
#define DF_NOP 0
@@ -64,6 +66,8 @@
#define DF_FP_A (1 << kFPA)
#define DF_FP_B (1 << kFPB)
#define DF_FP_C (1 << kFPC)
+#define DF_IS_GETTER (1 << kGetter)
+#define DF_IS_SETTER (1 << kSetter)
#define DF_HAS_USES (DF_UA | DF_UB | DF_UC | DF_UA_WIDE | \
DF_UB_WIDE | DF_UC_WIDE)
@@ -77,6 +81,7 @@
#define DF_A_IS_REG (DF_UA | DF_UA_WIDE | DF_DA | DF_DA_WIDE)
#define DF_B_IS_REG (DF_UB | DF_UB_WIDE)
#define DF_C_IS_REG (DF_UC | DF_UC_WIDE)
+#define DF_IS_GETTER_OR_SETTER (DF_IS_GETTER | DF_IS_SETTER)
extern int dvmCompilerDataFlowAttributes[kMirOpLast];
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index d97001f..40da0e1 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -18,6 +18,7 @@
#include "libdex/OpCode.h"
#include "interp/Jit.h"
#include "CompilerInternals.h"
+#include "Dataflow.h"
/*
* Parse an instruction, return the length of the instruction
@@ -41,7 +42,7 @@
dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
if (printMe) {
- char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn);
+ char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
}
return insnWidth;
@@ -191,13 +192,70 @@
return (int) m1->method - (int) m2->method;
}
-#if defined(WITH_JIT_TUNING)
+/*
+ * Analyze the body of the method to collect high-level information regarding
+ * inlining:
+ * - is empty method?
+ * - is getter/setter?
+ * - can throw exception?
+ *
+ * Currently the inliner only handles getters and setters. When its capability
+ * becomes more sophisticated more information will be retrieved here.
+ */
+static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
+ int offset)
+{
+ int flags = dexGetInstrFlags(gDvm.instrFlags, dalvikInsn->opCode);
+
+ if ((flags & kInstrInvoke) &&
+ (dalvikInsn->opCode != OP_INVOKE_DIRECT_EMPTY)) {
+ attributes &= ~METHOD_IS_LEAF;
+ }
+
+ if (!(flags & kInstrCanReturn)) {
+ if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
+ DF_IS_GETTER)) {
+ attributes &= ~METHOD_IS_GETTER;
+ }
+ if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
+ DF_IS_SETTER)) {
+ attributes &= ~METHOD_IS_SETTER;
+ }
+ }
+
+ /*
+ * The expected instruction sequence is setter will never return value and
+ * getter will also do. Clear the bits if the behavior is discovered
+ * otherwise.
+ */
+ if (flags & kInstrCanReturn) {
+ if (dalvikInsn->opCode == OP_RETURN_VOID) {
+ attributes &= ~METHOD_IS_GETTER;
+ }
+ else {
+ attributes &= ~METHOD_IS_SETTER;
+ }
+ }
+
+ if (flags & kInstrCanThrow) {
+ attributes &= ~METHOD_IS_THROW_FREE;
+ }
+
+ if (offset == 0 && dalvikInsn->opCode == OP_RETURN_VOID) {
+ attributes |= METHOD_IS_EMPTY;
+ }
+
+ return attributes;
+}
+
/*
* Analyze each method whose traces are ever compiled. Collect a variety of
* statistics like the ratio of exercised vs overall code and code bloat
- * ratios.
+ * ratios. If isCallee is true, also analyze each instruction in more details
+ * to see if it is suitable for inlining.
*/
-static CompilerMethodStats *analyzeMethodBody(const Method *method)
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+ bool isCallee)
{
const DexCode *dexCode = dvmGetMethodCode(method);
const u2 *codePtr = dexCode->insns;
@@ -215,22 +273,40 @@
(HashCompareFunc) compareMethod,
false);
- /* Part of this method has been compiled before - just return the entry */
- if (realMethodEntry != NULL) {
- return realMethodEntry;
+ /* This method has never been analyzed before - create an entry */
+ if (realMethodEntry == NULL) {
+ realMethodEntry =
+ (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
+ realMethodEntry->method = method;
+
+ dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+ realMethodEntry,
+ (HashCompareFunc) compareMethod,
+ true);
}
- /*
- * First time to compile this method - set up a new entry in the hash table
- */
- realMethodEntry =
- (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
- realMethodEntry->method = method;
+ /* This method is invoked as a callee and has been analyzed - just return */
+ if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
+ return realMethodEntry;
- dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
- realMethodEntry,
- (HashCompareFunc) compareMethod,
- true);
+ /*
+ * Similarly, return if this method has been compiled before as a hot
+ * method already.
+ */
+ if ((isCallee == false) &&
+ (realMethodEntry->attributes & METHOD_IS_HOT))
+ return realMethodEntry;
+
+ int attributes;
+
+ /* Method hasn't been analyzed for the desired purpose yet */
+ if (isCallee) {
+ /* Aggressively set the attributes until proven otherwise */
+ attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
+ METHOD_IS_GETTER | METHOD_IS_SETTER;
+ } else {
+ attributes = METHOD_IS_HOT;
+ }
/* Count the number of instructions */
while (codePtr < codeEnd) {
@@ -241,14 +317,51 @@
if (width == 0)
break;
+ if (isCallee) {
+ attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
+ }
+
insnSize += width;
codePtr += width;
}
+ /*
+ * Only handle simple getters/setters with one instruction followed by
+ * return
+ */
+ if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
+ (insnSize != 3)) {
+ attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
+ }
+
realMethodEntry->dalvikSize = insnSize * 2;
+ realMethodEntry->attributes |= attributes;
+
+#if 0
+ /* Uncomment the following to explore various callee patterns */
+ if (attributes & METHOD_IS_THROW_FREE) {
+ LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
+ (attributes & METHOD_IS_EMPTY) ? " empty" : "");
+ }
+
+ if (attributes & METHOD_IS_LEAF) {
+ LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
+ insnSize, insnSize < 5 ? " (small)" : "");
+ }
+
+ if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
+ LOGE("%s%s is %s", method->clazz->descriptor, method->name,
+ attributes & METHOD_IS_GETTER ? "getter": "setter");
+ }
+ if (attributes ==
+ (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
+ LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
+ method->name);
+ }
+#endif
+
return realMethodEntry;
}
-#endif
/*
* Crawl the stack of the thread that requesed compilation to see if any of the
@@ -305,6 +418,11 @@
/* If we've already compiled this trace, just return success */
if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
+ /*
+ * Make sure the codeAddress is NULL so that it won't clobber the
+ * existing entry.
+ */
+ info->codeAddress = NULL;
return true;
}
@@ -313,7 +431,7 @@
#if defined(WITH_JIT_TUNING)
/* Locate the entry to store compilation statistics for this method */
- methodStats = analyzeMethodBody(desc->method);
+ methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
#endif
/* Set the recover buffer pointer */
@@ -325,6 +443,12 @@
/* Initialize the profile flag */
cUnit.executionCount = gDvmJit.profile;
+ /* Setup the method */
+ cUnit.method = desc->method;
+
+ /* Initialize the PC reconstruction list */
+ dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
/* Identify traces that we don't want to compile */
if (gDvmJit.methodTable) {
int len = strlen(desc->method->clazz->descriptor) +
@@ -399,7 +523,7 @@
}
/* Allocate the entry block */
- lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
+ lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
curBB->startOffset = curOffset;
curBB->id = numBlocks++;
@@ -434,6 +558,19 @@
traceSize += width;
dvmCompilerAppendMIR(curBB, insn);
cUnit.numInsts++;
+
+ int flags = dexGetInstrFlags(gDvm.instrFlags, insn->dalvikInsn.opCode);
+
+ if ((flags & kInstrInvoke) &&
+ (insn->dalvikInsn.opCode != OP_INVOKE_DIRECT_EMPTY)) {
+ assert(numInsts == 1);
+ CallsiteInfo *callsiteInfo =
+ dvmCompilerNew(sizeof(CallsiteInfo), true);
+ callsiteInfo->clazz = currRun[1].meta;
+ callsiteInfo->method = currRun[2].meta;
+ insn->meta.callsiteInfo = callsiteInfo;
+ }
+
/* Instruction limit reached - terminate the trace here */
if (cUnit.numInsts >= numMaxInsts) {
break;
@@ -442,11 +579,20 @@
if (currRun->frag.runEnd) {
break;
} else {
+ /* Advance to the next trace description (ie non-meta info) */
+ do {
+ currRun++;
+ } while (!currRun->frag.isCode);
+
+ /* Dummy end-of-run marker seen */
+ if (currRun->frag.numInsts == 0) {
+ break;
+ }
+
curBB = dvmCompilerNewBB(kDalvikByteCode);
lastBB->next = curBB;
lastBB = curBB;
curBB->id = numBlocks++;
- currRun++;
curOffset = currRun->frag.startOffset;
numInsts = currRun->frag.numInsts;
curBB->startOffset = curOffset;
@@ -486,6 +632,13 @@
/* Link the taken and fallthrough blocks */
BasicBlock *searchBB;
+ int flags = dexGetInstrFlags(gDvm.instrFlags,
+ lastInsn->dalvikInsn.opCode);
+
+ if (flags & kInstrInvoke) {
+ cUnit.hasInvoke = true;
+ }
+
/* No backward branch in the trace - start searching the next BB */
for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
if (targetOffset == searchBB->startOffset) {
@@ -493,12 +646,18 @@
}
if (fallThroughOffset == searchBB->startOffset) {
curBB->fallThrough = searchBB;
+
+ /*
+ * Fallthrough block of an invoke instruction needs to be
+ * aligned to 4-byte boundary (alignment instruction to be
+ * inserted later.
+ */
+ if (flags & kInstrInvoke) {
+ searchBB->isFallThroughFromInvoke = true;
+ }
}
}
- int flags = dexGetInstrFlags(gDvm.instrFlags,
- lastInsn->dalvikInsn.opCode);
-
/*
* Some blocks are ended by non-control-flow-change instructions,
* currently only due to trace length constraint. In this case we need
@@ -523,7 +682,7 @@
if (cUnit.printMe) {
LOGD("Natural loop detected!");
}
- exitBB = dvmCompilerNewBB(kExitBlock);
+ exitBB = dvmCompilerNewBB(kTraceExitBlock);
lastBB->next = exitBB;
lastBB = exitBB;
@@ -682,23 +841,24 @@
lastBB->id = numBlocks++;
if (cUnit.printMe) {
- LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
+ char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype);
+ LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
compilationId,
(intptr_t) desc->method->insns,
desc->method->clazz->descriptor,
desc->method->name,
+ signature,
desc->trace[0].frag.startOffset,
traceSize,
dexCode->insnsSize,
numBlocks);
+ free(signature);
}
BasicBlock **blockList;
- cUnit.method = desc->method;
cUnit.traceDesc = desc;
cUnit.numBlocks = numBlocks;
- dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
blockList = cUnit.blockList =
dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
@@ -711,10 +871,17 @@
/* Make sure all blocks are added to the cUnit */
assert(curBB == NULL);
+ /* Set the instruction set to use (NOTE: later components may change it) */
+ cUnit.instructionSet = dvmCompilerInstructionSet();
+
+ /* Inline transformation @ the MIR level */
+ if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
+ dvmCompilerInlineMIR(&cUnit);
+ }
+
/* Preparation for SSA conversion */
dvmInitializeSSAConversion(&cUnit);
-
if (cUnit.hasLoop) {
dvmCompilerLoopOpt(&cUnit);
}
@@ -728,9 +895,6 @@
dvmCompilerDumpCompilationUnit(&cUnit);
}
- /* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet();
-
/* Allocate Registers */
dvmCompilerRegAlloc(&cUnit);
@@ -768,13 +932,112 @@
}
/*
+ * Since we are including instructions from possibly a cold method into the
+ * current trace, we need to make sure that all the associated information
+ * with the callee is properly initialized. If not, we punt on this inline
+ * target.
+ *
+ * TODO: volatile instructions will handled later.
+ */
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+ const DecodedInstruction *insn)
+{
+ switch (insn->opCode) {
+ case OP_NEW_INSTANCE:
+ case OP_CHECK_CAST: {
+ ClassObject *classPtr = (void*)
+ (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+ /* Class hasn't been initialized yet */
+ if (classPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_SGET_OBJECT:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_CHAR:
+ case OP_SGET_BYTE:
+ case OP_SGET_SHORT:
+ case OP_SGET:
+ case OP_SGET_WIDE:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_SHORT:
+ case OP_SPUT:
+ case OP_SPUT_WIDE: {
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[insn->vB]);
+
+ if (fieldPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE: {
+ int mIndex = method->clazz->pDvmDex->
+ pResMethods[insn->vB]->methodIndex;
+ const Method *calleeMethod = method->clazz->super->vtable[mIndex];
+ if (calleeMethod == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE: {
+ const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
+ if (calleeMethod == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE: {
+ const Method *calleeMethod =
+ method->clazz->pDvmDex->pResMethods[insn->vB];
+ if (calleeMethod == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_CONST_CLASS: {
+ void *classPtr = (void*)
+ (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+ if (classPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_STRING: {
+ void *strPtr = (void*)
+ (method->clazz->pDvmDex->pResStrings[insn->vB]);
+
+ if (strPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ default:
+ return true;
+ }
+}
+
+/*
* Similar to dvmCompileTrace, but the entity processed here is the whole
* method.
*
* TODO: implementation will be revisited when the trace builder can provide
* whole-method traces.
*/
-bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
+bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
+ JitTranslationInfo *info)
{
const DexCode *dexCode = dvmGetMethodCode(method);
const u2 *codePtr = dexCode->insns;
@@ -782,6 +1045,14 @@
int blockID = 0;
unsigned int curOffset = 0;
+ /* If we've already compiled this trace, just return success */
+ if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
+ return true;
+ }
+
+ /* Doing method-based compilation */
+ cUnit->wholeMethod = true;
+
BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
firstBlock->id = blockID++;
@@ -790,6 +1061,8 @@
false);
dvmCompilerSetBit(bbStartAddr, 0);
+ int numInvokeTargets = 0;
+
/*
* Sequentially go through every instruction first and put them in a single
* basic block. Identify block boundaries at the mean time.
@@ -805,6 +1078,12 @@
/* Terminate when the data section is seen */
if (width == 0)
break;
+
+ if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
+ &insn->dalvikInsn)) {
+ return false;
+ }
+
dvmCompilerAppendMIR(firstBlock, insn);
/*
* Check whether this is a block ending instruction and whether it
@@ -820,7 +1099,12 @@
if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
&callee)) {
dvmCompilerSetBit(bbStartAddr, curOffset + width);
- if (target != curOffset) {
+ /* Each invoke needs a chaining cell block */
+ if (isInvoke) {
+ numInvokeTargets++;
+ }
+ /* A branch will end the current block */
+ else if (target != curOffset && target != UNKNOWN_TARGET) {
dvmCompilerSetBit(bbStartAddr, target);
}
}
@@ -834,26 +1118,26 @@
* The number of blocks will be equal to the number of bits set to 1 in the
* bit vector minus 1, because the bit representing the location after the
* last instruction is set to one.
+ *
+ * We also add additional blocks for invoke chaining and the number is
+ * denoted by numInvokeTargets.
*/
int numBlocks = dvmCountSetBits(bbStartAddr);
if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
numBlocks--;
}
- CompilationUnit cUnit;
BasicBlock **blockList;
-
- memset(&cUnit, 0, sizeof(CompilationUnit));
- cUnit.method = method;
- blockList = cUnit.blockList =
- dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
+ blockList = cUnit->blockList =
+ dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
+ true);
/*
- * Register the first block onto the list and start split it into block
- * boundaries from there.
+ * Register the first block onto the list and start splitting it into
+ * sub-blocks.
*/
blockList[0] = firstBlock;
- cUnit.numBlocks = 1;
+ cUnit->numBlocks = 1;
int i;
for (i = 0; i < numBlocks; i++) {
@@ -865,13 +1149,13 @@
/* Found the beginning of a new block, see if it is created yet */
if (dvmIsBitSet(bbStartAddr, insn->offset)) {
int j;
- for (j = 0; j < cUnit.numBlocks; j++) {
+ for (j = 0; j < cUnit->numBlocks; j++) {
if (blockList[j]->firstMIRInsn->offset == insn->offset)
break;
}
/* Block not split yet - do it now */
- if (j == cUnit.numBlocks) {
+ if (j == cUnit->numBlocks) {
BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
newBB->id = blockID++;
newBB->firstMIRInsn = insn;
@@ -889,17 +1173,28 @@
curBB->fallThrough = newBB;
}
+ /*
+ * Fallthrough block of an invoke instruction needs to be
+ * aligned to 4-byte boundary (alignment instruction to be
+ * inserted later.
+ */
+ if (dexGetInstrFlags(gDvm.instrFlags,
+ curBB->lastMIRInsn->dalvikInsn.opCode) &
+ kInstrInvoke) {
+ newBB->isFallThroughFromInvoke = true;
+ }
+
/* enqueue the new block */
- blockList[cUnit.numBlocks++] = newBB;
+ blockList[cUnit->numBlocks++] = newBB;
break;
}
}
}
}
- if (numBlocks != cUnit.numBlocks) {
- LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
- dvmCompilerAbort(&cUnit);
+ if (numBlocks != cUnit->numBlocks) {
+ LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
+ dvmCompilerAbort(cUnit);
}
/* Connect the basic blocks through the taken links */
@@ -907,13 +1202,13 @@
BasicBlock *curBB = blockList[i];
MIR *insn = curBB->lastMIRInsn;
unsigned int target = insn->offset;
- bool isInvoke;
- const Method *callee;
+ bool isInvoke = false;
+ const Method *callee = NULL;
findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
- /* Found a block ended on a branch */
- if (target != insn->offset) {
+ /* Found a block ended on a branch (not invoke) */
+ if (isInvoke == false && target != insn->offset) {
int j;
/* Forward branch */
if (target > insn->offset) {
@@ -928,24 +1223,60 @@
break;
}
}
+ }
- /* Don't create dummy block for the callee yet */
- if (j == numBlocks && !isInvoke) {
- LOGE("Target not found for insn %x: expect target %x\n",
- curBB->lastMIRInsn->offset, target);
- dvmCompilerAbort(&cUnit);
+ if (isInvoke) {
+ BasicBlock *newBB;
+ /* Monomorphic callee */
+ if (callee) {
+ newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
+ newBB->startOffset = 0;
+ newBB->containingMethod = callee;
+ /* Will resolve at runtime */
+ } else {
+ newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
+ newBB->startOffset = 0;
}
+ newBB->id = blockID++;
+ curBB->taken = newBB;
+ /* enqueue the new block */
+ blockList[cUnit->numBlocks++] = newBB;
}
}
+ if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
+ LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
+ cUnit->numBlocks);
+ dvmCompilerDumpCompilationUnit(cUnit);
+ dvmCompilerAbort(cUnit);
+ }
+
/* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet();
+ cUnit->instructionSet = dvmCompilerInstructionSet();
- dvmCompilerMIR2LIR(&cUnit);
+ /* Preparation for SSA conversion */
+ dvmInitializeSSAConversion(cUnit);
- dvmCompilerAssembleLIR(&cUnit, info);
+ /* SSA analysis */
+ dvmCompilerNonLoopAnalysis(cUnit);
- dvmCompilerDumpCompilationUnit(&cUnit);
+ /* Needs to happen after SSA naming */
+ dvmCompilerInitializeRegAlloc(cUnit);
+
+ /* Allocate Registers */
+ dvmCompilerRegAlloc(cUnit);
+
+ /* Convert MIR to LIR, etc. */
+ dvmCompilerMIR2LIR(cUnit);
+
+ /* Convert LIR into machine code. */
+ dvmCompilerAssembleLIR(cUnit, info);
+
+ if (cUnit->halveInstCount) {
+ return false;
+ }
+
+ dvmCompilerDumpCompilationUnit(cUnit);
dvmCompilerArenaReset();
diff --git a/vm/compiler/InlineTransformation.c b/vm/compiler/InlineTransformation.c
new file mode 100644
index 0000000..790cc5d
--- /dev/null
+++ b/vm/compiler/InlineTransformation.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "Dataflow.h"
+#include "libdex/OpCodeNames.h"
+
+/* Convert the reg id from the callee to the original id passed by the caller */
+static inline u4 convertRegId(const DecodedInstruction *invoke,
+ const Method *calleeMethod,
+ int calleeRegId, bool isRange)
+{
+ /* The order in the original arg passing list */
+ int rank = calleeRegId -
+ (calleeMethod->registersSize - calleeMethod->insSize);
+ assert(rank >= 0);
+ if (!isRange) {
+ return invoke->arg[rank];
+ } else {
+ return invoke->vC + rank;
+ }
+}
+
+static void inlineGetter(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isPredicted,
+ bool isRange)
+{
+ BasicBlock *moveResultBB = invokeBB->fallThrough;
+ MIR *moveResultMIR = moveResultBB->firstMIRInsn;
+ MIR *newGetterMIR = dvmCompilerNew(sizeof(MIR), true);
+ DecodedInstruction getterInsn;
+
+ dexDecodeInstruction(gDvm.instrFormat, calleeMethod->insns, &getterInsn);
+
+ if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
+ return;
+
+ /*
+ * Some getters (especially invoked through interface) are not followed
+ * by a move result.
+ */
+ if ((moveResultMIR == NULL) ||
+ (moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT &&
+ moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT_OBJECT &&
+ moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT_WIDE)) {
+ return;
+ }
+
+ int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opCode];
+
+ /* Expecting vA to be the destination register */
+ if (dfFlags & (DF_UA | DF_UA_WIDE)) {
+ LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opCode);
+ dvmAbort();
+ }
+
+ if (dfFlags & DF_UB) {
+ getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ getterInsn.vB, isRange);
+ }
+
+ if (dfFlags & DF_UC) {
+ getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ getterInsn.vC, isRange);
+ }
+
+ getterInsn.vA = moveResultMIR->dalvikInsn.vA;
+
+ /* Now setup the Dalvik instruction with converted src/dst registers */
+ newGetterMIR->dalvikInsn = getterInsn;
+
+ newGetterMIR->width = gDvm.instrWidth[getterInsn.opCode];
+
+ newGetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+ /*
+ * If the getter instruction is about to raise any exception, punt to the
+ * interpreter and re-execute the invoke.
+ */
+ newGetterMIR->offset = invokeMIR->offset;
+
+ newGetterMIR->meta.calleeMethod = calleeMethod;
+
+ dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
+
+ if (isPredicted) {
+ MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+ *invokeMIRSlow = *invokeMIR;
+ invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+ /* Use vC to denote the first argument (ie this) */
+ if (!isRange) {
+ invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+ }
+
+ moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
+
+ dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
+ invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokePolyGetterInlined++;
+#endif
+ } else {
+ invokeMIR->OptimizationFlags |= MIR_INLINED;
+ moveResultMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokeMonoGetterInlined++;
+#endif
+ }
+
+ return;
+}
+
+static void inlineSetter(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isPredicted,
+ bool isRange)
+{
+ MIR *newSetterMIR = dvmCompilerNew(sizeof(MIR), true);
+ DecodedInstruction setterInsn;
+
+ dexDecodeInstruction(gDvm.instrFormat, calleeMethod->insns, &setterInsn);
+
+ if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
+ return;
+
+ int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opCode];
+
+ if (dfFlags & (DF_UA | DF_UA_WIDE)) {
+ setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ setterInsn.vA, isRange);
+
+ }
+
+ if (dfFlags & DF_UB) {
+ setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ setterInsn.vB, isRange);
+
+ }
+
+ if (dfFlags & DF_UC) {
+ setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ setterInsn.vC, isRange);
+ }
+
+ /* Now setup the Dalvik instruction with converted src/dst registers */
+ newSetterMIR->dalvikInsn = setterInsn;
+
+ newSetterMIR->width = gDvm.instrWidth[setterInsn.opCode];
+
+ newSetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+ /*
+ * If the setter instruction is about to raise any exception, punt to the
+ * interpreter and re-execute the invoke.
+ */
+ newSetterMIR->offset = invokeMIR->offset;
+
+ newSetterMIR->meta.calleeMethod = calleeMethod;
+
+ dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
+
+ if (isPredicted) {
+ MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+ *invokeMIRSlow = *invokeMIR;
+ invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+ /* Use vC to denote the first argument (ie this) */
+ if (!isRange) {
+ invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+ }
+
+ dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
+ invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokePolySetterInlined++;
+#endif
+ } else {
+ /*
+ * The invoke becomes no-op so it needs an explicit branch to jump to
+ * the chaining cell.
+ */
+ invokeBB->needFallThroughBranch = true;
+ invokeMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokeMonoSetterInlined++;
+#endif
+ }
+
+ return;
+}
+
+static void tryInlineSingletonCallsite(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isRange)
+{
+ /* Not a Java method */
+ if (dvmIsNativeMethod(calleeMethod)) return;
+
+ CompilerMethodStats *methodStats =
+ dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+
+ /* Empty callee - do nothing */
+ if (methodStats->attributes & METHOD_IS_EMPTY) {
+ /* The original invoke instruction is effectively turned into NOP */
+ invokeMIR->OptimizationFlags |= MIR_INLINED;
+ return;
+ }
+
+ if (methodStats->attributes & METHOD_IS_GETTER) {
+ inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
+ return;
+ } else if (methodStats->attributes & METHOD_IS_SETTER) {
+ inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
+ return;
+ }
+}
+
+static void inlineEmptyVirtualCallee(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB)
+{
+ MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+ *invokeMIRSlow = *invokeMIR;
+ invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+ dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
+ invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+}
+
+static void tryInlineVirtualCallsite(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isRange)
+{
+ /* Not a Java method */
+ if (dvmIsNativeMethod(calleeMethod)) return;
+
+ CompilerMethodStats *methodStats =
+ dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+
+ /* Empty callee - do nothing by checking the clazz pointer */
+ if (methodStats->attributes & METHOD_IS_EMPTY) {
+ inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR, invokeBB);
+ return;
+ }
+
+ if (methodStats->attributes & METHOD_IS_GETTER) {
+ inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
+ return;
+ } else if (methodStats->attributes & METHOD_IS_SETTER) {
+ inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
+ return;
+ }
+}
+
+
+void dvmCompilerInlineMIR(CompilationUnit *cUnit)
+{
+ int i;
+ bool isRange = false;
+
+ /*
+ * Analyze the basic block containing an invoke to see if it can be inlined
+ */
+ for (i = 0; i < cUnit->numBlocks; i++) {
+ BasicBlock *bb = cUnit->blockList[i];
+ if (bb->blockType != kDalvikByteCode)
+ continue;
+ MIR *lastMIRInsn = bb->lastMIRInsn;
+ int opCode = lastMIRInsn->dalvikInsn.opCode;
+ int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
+
+ /* No invoke - continue */
+ if ((flags & kInstrInvoke) == 0)
+ continue;
+
+ /* Not a real invoke - continue */
+ if (opCode == OP_INVOKE_DIRECT_EMPTY)
+ continue;
+
+ const Method *calleeMethod;
+
+ switch (opCode) {
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_SUPER_QUICK:
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ isRange = true;
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ default:
+ calleeMethod = NULL;
+ break;
+ }
+
+ if (calleeMethod) {
+ tryInlineSingletonCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
+ isRange);
+ return;
+ }
+
+ switch (opCode) {
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_INTERFACE:
+ isRange = false;
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ isRange = true;
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ default:
+ break;
+ }
+
+ if (calleeMethod) {
+ tryInlineVirtualCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
+ isRange);
+ return;
+ }
+ }
+}
diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c
index b3e6490..825a690 100644
--- a/vm/compiler/IntermediateRep.c
+++ b/vm/compiler/IntermediateRep.c
@@ -55,6 +55,22 @@
}
}
+/* Insert an MIR instruction after the specified MIR */
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR)
+{
+ newMIR->prev = currentMIR;
+ newMIR->next = currentMIR->next;
+ currentMIR->next = newMIR;
+
+ if (newMIR->next) {
+ /* Is not the last MIR in the block */
+ newMIR->next->prev = newMIR;
+ } else {
+ /* Is the last MIR in the block */
+ bb->lastMIRInsn = newMIR;
+ }
+}
+
/*
* Append an LIR instruction to the LIR list maintained by a compilation
* unit
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index ef76c50..dede0ee 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -86,6 +86,8 @@
}
+#if 0
+/* Debugging routines */
static void dumpConstants(CompilationUnit *cUnit)
{
int i;
@@ -126,6 +128,31 @@
}
}
+static void dumpHoistedChecks(CompilationUnit *cUnit)
+{
+ LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+ unsigned int i;
+
+ for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
+ ArrayAccessInfo *arrayAccessInfo =
+ GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+ ArrayAccessInfo*, i);
+ int arrayReg = DECODE_REG(
+ dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
+ int idxReg = DECODE_REG(
+ dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
+ LOGE("Array access %d", i);
+ LOGE(" arrayReg %d", arrayReg);
+ LOGE(" idxReg %d", idxReg);
+ LOGE(" endReg %d", loopAnalysis->endConditionReg);
+ LOGE(" maxC %d", arrayAccessInfo->maxC);
+ LOGE(" minC %d", arrayAccessInfo->minC);
+ LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
+ }
+}
+
+#endif
+
/*
* A loop is considered optimizable if:
* 1) It has one basic induction variable
@@ -263,11 +290,9 @@
/* Returns true if the loop body cannot throw any exceptions */
static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
{
- BasicBlock *entry = cUnit->blockList[0];
BasicBlock *loopBody = cUnit->blockList[1];
MIR *mir;
bool loopBodyCanThrow = false;
- int numDalvikRegs = cUnit->method->registersSize;
for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
DecodedInstruction *dInsn = &mir->dalvikInsn;
@@ -321,7 +346,6 @@
int useIdx = refIdx + 1;
int subNRegArray =
dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
- int arrayReg = DECODE_REG(subNRegArray);
int arraySub = DECODE_SUB(subNRegArray);
/*
@@ -350,36 +374,11 @@
return !loopBodyCanThrow;
}
-static void dumpHoistedChecks(CompilationUnit *cUnit)
-{
- ArrayAccessInfo *arrayAccessInfo;
- LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
- unsigned int i;
-
- for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
- ArrayAccessInfo *arrayAccessInfo =
- GET_ELEM_N(loopAnalysis->arrayAccessInfo,
- ArrayAccessInfo*, i);
- int arrayReg = DECODE_REG(
- dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
- int idxReg = DECODE_REG(
- dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
- LOGE("Array access %d", i);
- LOGE(" arrayReg %d", arrayReg);
- LOGE(" idxReg %d", idxReg);
- LOGE(" endReg %d", loopAnalysis->endConditionReg);
- LOGE(" maxC %d", arrayAccessInfo->maxC);
- LOGE(" minC %d", arrayAccessInfo->minC);
- LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
- }
-}
-
static void genHoistedChecks(CompilationUnit *cUnit)
{
unsigned int i;
BasicBlock *entry = cUnit->blockList[0];
LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
- ArrayAccessInfo *arrayAccessInfo;
int globalMaxC = 0;
int globalMinC = 0;
/* Should be loop invariant */
@@ -461,12 +460,11 @@
/* Main entry point to do loop optimization */
void dvmCompilerLoopOpt(CompilationUnit *cUnit)
{
- int numDalvikReg = cUnit->method->registersSize;
LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
- assert(cUnit->blockList[0]->blockType == kEntryBlock);
+ assert(cUnit->blockList[0]->blockType == kTraceEntryBlock);
assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
- assert(cUnit->blockList[3]->blockType == kExitBlock);
+ assert(cUnit->blockList[3]->blockType == kTraceExitBlock);
cUnit->loopAnalysis = loopAnalysis;
/*
diff --git a/vm/compiler/Ralloc.c b/vm/compiler/Ralloc.c
index 1a3e27e..f227527 100644
--- a/vm/compiler/Ralloc.c
+++ b/vm/compiler/Ralloc.c
@@ -31,7 +31,7 @@
int i;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock)
+ bb->blockType != kTraceEntryBlock)
return seqNum;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
@@ -64,7 +64,7 @@
{
MIR *mir;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock)
+ bb->blockType != kTraceEntryBlock)
return;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
@@ -124,7 +124,6 @@
int seqNum = 0;
LiveRange *ranges;
RegLocation *loc;
- int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
/* Allocate the location map */
loc = (RegLocation*)dvmCompilerNew(cUnit->numSSARegs * sizeof(*loc), true);
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index cbafb79..711d4cf 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -30,6 +30,7 @@
LOGE("No memory left to create compiler heap memory\n");
return false;
}
+ arenaHead->blockSize = ARENA_DEFAULT_SIZE;
currentArena = arenaHead;
currentArena->bytesAllocated = 0;
currentArena->next = NULL;
@@ -44,7 +45,7 @@
size = (size + 3) & ~3;
retry:
/* Normal case - space is available in the current page */
- if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) {
+ if (size + currentArena->bytesAllocated <= currentArena->blockSize) {
void *ptr;
ptr = ¤tArena->ptr[currentArena->bytesAllocated];
currentArena->bytesAllocated += size;
@@ -61,15 +62,17 @@
currentArena = currentArena->next;
goto retry;
}
- /*
- * If we allocate really large variable-sized data structures that
- * could go above the limit we need to enhance the allocation
- * mechanism.
- */
- assert(size <= ARENA_DEFAULT_SIZE);
+
+ size_t blockSize = (size < ARENA_DEFAULT_SIZE) ?
+ ARENA_DEFAULT_SIZE : size;
/* Time to allocate a new arena */
ArenaMemBlock *newArena = (ArenaMemBlock *)
- malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
+ malloc(sizeof(ArenaMemBlock) + blockSize);
+ if (newArena == NULL) {
+ LOGE("Arena allocation failure");
+ dvmAbort();
+ }
+ newArena->blockSize = blockSize;
newArena->bytesAllocated = 0;
newArena->next = NULL;
currentArena->next = newArena;
@@ -120,6 +123,7 @@
/* Insert a new element into the growable list */
void dvmInsertGrowableList(GrowableList *gList, void *elem)
{
+ assert(gList->numAllocated != 0);
if (gList->numUsed == gList->numAllocated) {
expandGrowableList(gList);
}
@@ -131,12 +135,34 @@
{
int i;
BasicBlock *bb;
- LOGD("%d blocks in total\n", cUnit->numBlocks);
+ char *blockTypeNames[] = {
+ "Normal Chaining Cell",
+ "Hot Chaining Cell",
+ "Singleton Chaining Cell",
+ "Predicted Chaining Cell",
+ "Backward Branch",
+ "Chaining Cell Gap",
+ "N/A",
+ "Method Entry Block",
+ "Trace Entry Block",
+ "Code Block",
+ "Trace Exit Block",
+ "Method Exit Block",
+ "PC Reconstruction",
+ "Exception Handling",
+ };
+
+ LOGD("Compiling %s %s", cUnit->method->clazz->descriptor,
+ cUnit->method->name);
+ LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method));
+ LOGD("%d blocks in total", cUnit->numBlocks);
for (i = 0; i < cUnit->numBlocks; i++) {
bb = cUnit->blockList[i];
- LOGD("Block %d (insn %04x - %04x%s)\n",
- bb->id, bb->startOffset,
+ LOGD("Block %d (%s) (insn %04x - %04x%s)\n",
+ bb->id,
+ blockTypeNames[bb->blockType],
+ bb->startOffset,
bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
bb->lastMIRInsn ? "" : " empty");
if (bb->taken) {
@@ -159,7 +185,6 @@
(CompilerMethodStats *) compilerMethodStats;
CompilerMethodStats *totalStats =
(CompilerMethodStats *) totalMethodStats;
- const Method *method = methodStats->method;
totalStats->dalvikSize += methodStats->dalvikSize;
totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
@@ -172,7 +197,8 @@
/* If over 3/4 of the Dalvik code is compiled, print something */
if (methodStats->compiledDalvikSize >= limit) {
LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)",
- method->clazz->descriptor, method->name,
+ methodStats->method->clazz->descriptor,
+ methodStats->method->name,
methodStats->compiledDalvikSize,
methodStats->dalvikSize,
methodStats->nativeSize);
@@ -203,11 +229,11 @@
if (gDvmJit.methodStatsTable) {
dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
&totalMethodStats);
+ LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
+ totalMethodStats.compiledDalvikSize,
+ totalMethodStats.dalvikSize,
+ totalMethodStats.nativeSize);
}
- LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
- totalMethodStats.compiledDalvikSize,
- totalMethodStats.dalvikSize,
- totalMethodStats.nativeSize);
}
/*
diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h
index 06fd410..7379d50 100644
--- a/vm/compiler/codegen/CompilerCodegen.h
+++ b/vm/compiler/codegen/CompilerCodegen.h
@@ -61,4 +61,7 @@
/* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
int dvmCompilerTargetOptHint(int key);
+/* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit);
+
#endif /* _DALVIK_VM_COMPILERCODEGEN_H_ */
diff --git a/vm/compiler/codegen/Optimizer.h b/vm/compiler/codegen/Optimizer.h
index 713aa41..d42fe87 100644
--- a/vm/compiler/codegen/Optimizer.h
+++ b/vm/compiler/codegen/Optimizer.h
@@ -28,6 +28,7 @@
kLoadHoisting,
kTrackLiveTemps,
kSuppressLoads,
+ kMethodInlining,
} optControlVector;
/* Forward declarations */
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index b0478f4..d5acd13 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -15,7 +15,7 @@
*/
#include "../../CompilerInternals.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include "ArmLIR.h"
/* Decode and print a ARM register name */
@@ -68,6 +68,7 @@
char *bufEnd = &buf[size-1];
char *fmtEnd = &fmt[strlen(fmt)];
char tbuf[256];
+ char *name;
char nc;
while (fmt < fmtEnd) {
int operand;
@@ -82,6 +83,32 @@
assert((unsigned)(nc-'0') < 4);
operand = lir->operands[nc-'0'];
switch(*fmt++) {
+ case 'B':
+ switch (operand) {
+ case kSY:
+ name = "sy";
+ break;
+ case kST:
+ name = "st";
+ break;
+ case kISH:
+ name = "ish";
+ break;
+ case kISHST:
+ name = "ishst";
+ break;
+ case kNSH:
+ name = "nsh";
+ break;
+ case kNSHST:
+ name = "shst";
+ break;
+ default:
+ name = "DecodeError";
+ break;
+ }
+ strcpy(tbuf, name);
+ break;
case 'b':
strcpy(tbuf,"0000");
for (i=3; i>= 0; i--) {
@@ -239,7 +266,6 @@
char opName[256];
int offset = lir->generic.offset;
int dest = lir->operands[0];
- u2 *cPtr = (u2*)baseAddr;
const bool dumpNop = false;
/* Handle pseudo-ops individually, and all regular insns as a group */
@@ -251,7 +277,8 @@
LOGD("-------- BARRIER");
break;
case kArmPseudoExtended:
- /* intentional fallthrough */
+ LOGD("-------- %s\n", (char *) dest);
+ break;
case kArmPseudoSSARep:
DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
break;
diff --git a/vm/compiler/codegen/arm/ArmLIR.h b/vm/compiler/codegen/arm/ArmLIR.h
index f7704ad..24f5240 100644
--- a/vm/compiler/codegen/arm/ArmLIR.h
+++ b/vm/compiler/codegen/arm/ArmLIR.h
@@ -622,10 +622,21 @@
rd[11-8] imm2[7-6] [0] msb[4-0] */
kThumb2Bfc, /* bfc [11110011011011110] [0] imm3[14-12]
rd[11-8] imm2[7-6] [0] msb[4-0] */
+ kThumb2Dmb, /* dmb [1111001110111111100011110101] option[3-0] */
kArmLast,
} ArmOpCode;
+/* DMB option encodings */
+typedef enum ArmOpDmbOptions {
+ kSY = 0xf,
+ kST = 0xe,
+ kISH = 0xb,
+ kISHST = 0xa,
+ kNSH = 0x7,
+ kNSHST = 0x6
+} ArmOpDmbOptions;
+
/* Bit flags describing the behavior of each native opcode */
typedef enum ArmOpFeatureFlags {
kIsBranch = 0,
@@ -762,18 +773,6 @@
/* Init values when a predicted chain is initially assembled */
/* E7FE is branch to self */
#define PREDICTED_CHAIN_BX_PAIR_INIT 0xe7fe
-#define PREDICTED_CHAIN_CLAZZ_INIT 0
-#define PREDICTED_CHAIN_METHOD_INIT 0
-#define PREDICTED_CHAIN_COUNTER_INIT 0
-
-/* Used when the callee is not compiled yet */
-#define PREDICTED_CHAIN_COUNTER_DELAY 512
-
-/* Rechain after this many mis-predictions have happened */
-#define PREDICTED_CHAIN_COUNTER_RECHAIN 1024
-
-/* Used if the resolved callee is a native method */
-#define PREDICTED_CHAIN_COUNTER_AVOID 0x7fffffff
/* Utility macros to traverse the LIR/ArmLIR list */
#define NEXT_LIR(lir) ((ArmLIR *) lir->generic.next)
@@ -784,4 +783,7 @@
#define CHAIN_CELL_OFFSET_TAG 0xcdab
+#define CHAIN_CELL_NORMAL_SIZE 12
+#define CHAIN_CELL_PREDICTED_SIZE 16
+
#endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H */
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 1951e07..c1b08a3 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -16,11 +16,12 @@
#include "Dalvik.h"
#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include "../../CompilerInternals.h"
#include "ArmLIR.h"
#include <unistd.h> /* for cacheflush */
+#include <sys/mman.h> /* for protection change */
/*
* opcode: ArmOpCode enum
@@ -69,6 +70,7 @@
* n -> complimented Thumb2 modified immediate
* M -> Thumb2 16-bit zero-extended immediate
* b -> 4-digit binary
+ * B -> dmb option string (sy, st, ish, ishst, nsh, hshst)
*
* [!] escape. To insert "!", use "!!"
*/
@@ -486,19 +488,19 @@
ENCODING_MAP(kThumb2StrRRI12, 0xf8c00000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
- "str", "r!0d,[r!1d, #!2d", 2),
+ "str", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2LdrRRI12, 0xf8d00000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldr", "r!0d,[r!1d, #!2d", 2),
+ "ldr", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2StrRRI8Predec, 0xf8400c00,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
- "str", "r!0d,[r!1d, #-!2d]", 2),
+ "str", "r!0d, [r!1d, #-!2d]", 2),
ENCODING_MAP(kThumb2LdrRRI8Predec, 0xf8500c00,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldr", "r!0d,[r!1d, #-!2d]", 2),
+ "ldr", "r!0d, [r!1d, #-!2d]", 2),
ENCODING_MAP(kThumb2Cbnz, 0xb900, /* Note: does not affect flags */
kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
@@ -579,59 +581,59 @@
ENCODING_MAP(kThumb2LdrRRR, 0xf8500000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
- "ldr", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "ldr", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2LdrhRRR, 0xf8300000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
- "ldrh", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "ldrh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2LdrshRRR, 0xf9300000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
- "ldrsh", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "ldrsh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2LdrbRRR, 0xf8100000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
- "ldrb", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "ldrb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2LdrsbRRR, 0xf9100000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
- "ldrsb", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "ldrsb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2StrRRR, 0xf8400000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
- "str", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "str", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2StrhRRR, 0xf8200000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
- "strh", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "strh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2StrbRRR, 0xf8000000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
- "strb", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
+ "strb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
ENCODING_MAP(kThumb2LdrhRRI12, 0xf8b00000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldrh", "r!0d,[r!1d, #!2d]", 2),
+ "ldrh", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2LdrshRRI12, 0xf9b00000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldrsh", "r!0d,[r!1d, #!2d]", 2),
+ "ldrsh", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2LdrbRRI12, 0xf8900000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldrb", "r!0d,[r!1d, #!2d]", 2),
+ "ldrb", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2LdrsbRRI12, 0xf9900000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldrsb", "r!0d,[r!1d, #!2d]", 2),
+ "ldrsb", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2StrhRRI12, 0xf8a00000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
- "strh", "r!0d,[r!1d, #!2d]", 2),
+ "strh", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2StrbRRI12, 0xf8800000,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
- "strb", "r!0d,[r!1d, #!2d]", 2),
+ "strb", "r!0d, [r!1d, #!2d]", 2),
ENCODING_MAP(kThumb2Pop, 0xe8bd0000,
kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1,
@@ -651,7 +653,7 @@
kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtShift, -1, -1,
IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
- "acds", "r!0d, r!1d, r!2d, shift !3d", 2),
+ "adcs", "r!0d, r!1d, r!2d, shift !3d", 2),
ENCODING_MAP(kThumb2AndRRR, 0xea000000,
kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
@@ -784,7 +786,7 @@
kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1,
IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
- "ldr", "r!0d,[rpc, #!1d]", 2),
+ "ldr", "r!0d, [rpc, #!1d]", 2),
ENCODING_MAP(kThumb2BCond, 0xf0008000,
kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1,
kFmtUnused, -1, -1,
@@ -851,7 +853,7 @@
ENCODING_MAP(kThumb2Ldrex, 0xe8500f00,
kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
- "ldrex", "r!0d,[r!1d, #!2E]", 2),
+ "ldrex", "r!0d, [r!1d, #!2E]", 2),
ENCODING_MAP(kThumb2Strex, 0xe8400000,
kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12 | IS_STORE,
@@ -868,6 +870,10 @@
kFmtBitBlt, 11, 8, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0,
"bfc", "r!0d,#!1d,#!2d", 2),
+ ENCODING_MAP(kThumb2Dmb, 0xf3bf8f50,
+ kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP,
+ "dmb","#!0B",2),
};
/*
@@ -877,6 +883,13 @@
*/
#define PADDING_MOV_R5_R5 0x1C2D
+/* Track the number of times that the code cache is patched */
+#if defined(WITH_JIT_TUNING)
+#define UPDATE_CODE_CACHE_PATCHES() (gDvmJit.codeCachePatches++)
+#else
+#define UPDATE_CODE_CACHE_PATCHES()
+#endif
+
/* Write the numbers in the literal pool to the codegen stream */
static void installDataContent(CompilationUnit *cUnit)
{
@@ -892,11 +905,13 @@
static int jitTraceDescriptionSize(const JitTraceDescription *desc)
{
int runCount;
+ /* Trace end is always of non-meta type (ie isCode == true) */
for (runCount = 0; ; runCount++) {
- if (desc->trace[runCount].frag.runEnd)
+ if (desc->trace[runCount].frag.isCode &&
+ desc->trace[runCount].frag.runEnd)
break;
}
- return sizeof(JitCodeDesc) + ((runCount+1) * sizeof(JitTraceRun));
+ return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
}
/* Return TRUE if error happens */
@@ -1152,7 +1167,7 @@
* | . .
* | | |
* | +----------------------------+
- * | | Chaining Cells | -> 8 bytes each, must be 4 byte aligned
+ * | | Chaining Cells | -> 12/16 bytes each, must be 4 byte aligned
* | . .
* | . .
* | | |
@@ -1182,7 +1197,8 @@
int offset = 0;
int i;
ChainCellCounts chainCellCounts;
- int descSize = jitTraceDescriptionSize(cUnit->traceDesc);
+ int descSize =
+ cUnit->wholeMethod ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
int chainingCellGap;
info->instructionSet = cUnit->instructionSet;
@@ -1286,6 +1302,8 @@
cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
gDvmJit.codeCacheByteUsed += offset;
+ UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset);
+
/* Install the code block */
memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
gDvmJit.numCompilations++;
@@ -1311,6 +1329,9 @@
/* Flush dcache and invalidate the icache to maintain coherence */
cacheflush((long)cUnit->baseAddr,
(long)((char *) cUnit->baseAddr + offset), 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
/* Record code entry point and instruction set */
info->codeAddress = (char*)cUnit->baseAddr + cUnit->headerSize;
@@ -1387,27 +1408,40 @@
* mix Arm & Thumb[2] translations, the following code should be
* generalized.
*/
- thumbTarget = (tgtAddr != gDvmJit.interpretTemplate);
+ thumbTarget = (tgtAddr != dvmCompilerGetInterpretTemplate());
newInst = assembleChainingBranch(branchOffset, thumbTarget);
+ /*
+ * The second half-word instruction of the chaining cell must
+ * either be a nop (which represents initial state), or is the
+ * same exact branch halfword that we are trying to install.
+ */
+ assert( ((*branchAddr >> 16) == getSkeleton(kThumbOrr)) ||
+ ((*branchAddr >> 16) == (newInst >> 16)));
+
+ UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
*branchAddr = newInst;
cacheflush((long)branchAddr, (long)branchAddr + 4, 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
gDvmJit.hasNewChain = true;
}
return tgtAddr;
}
+#if !defined(WITH_SELF_VERIFICATION)
/*
* Attempt to enqueue a work order to patch an inline cache for a predicted
* chaining cell for virtual/interface calls.
*/
-static bool inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
+static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
PredictedChainingCell *newContent)
{
- bool result = true;
-
/*
* Make sure only one thread gets here since updating the cell (ie fast
* path and queueing the request (ie the queued path) have to be done
@@ -1418,44 +1452,75 @@
/* Fast path for uninitialized chaining cell */
if (cellAddr->clazz == NULL &&
cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
+
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
cellAddr->method = newContent->method;
cellAddr->branch = newContent->branch;
- cellAddr->counter = newContent->counter;
/*
* The update order matters - make sure clazz is updated last since it
* will bring the uninitialized chaining cell to life.
*/
- MEM_BARRIER();
+ ANDROID_MEMBAR_FULL();
cellAddr->clazz = newContent->clazz;
cacheflush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
#if defined(WITH_JIT_TUNING)
- gDvmJit.icPatchFast++;
+ gDvmJit.icPatchInit++;
#endif
- }
+ /* Check if this is a frequently missed clazz */
+ } else if (cellAddr->stagedClazz != newContent->clazz) {
+ /* Not proven to be frequent yet - build up the filter cache */
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->stagedClazz = newContent->clazz;
+
+ UPDATE_CODE_CACHE_PATCHES();
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchRejected++;
+#endif
/*
- * Otherwise the patch request will be queued and handled in the next
- * GC cycle. At that time all other mutator threads are suspended so
- * there will be no partial update in the inline cache state.
+ * Different classes but same method implementation - it is safe to just
+ * patch the class value without the need to stop the world.
*/
- else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
+ } else if (cellAddr->method == newContent->method) {
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->clazz = newContent->clazz;
+ /* No need to flush the cache here since the branch is not patched */
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchLockFree++;
+#endif
+ /*
+ * Cannot patch the chaining cell inline - queue it until the next safe
+ * point.
+ */
+ } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
int index = gDvmJit.compilerICPatchIndex++;
gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr;
gDvmJit.compilerICPatchQueue[index].cellContent = *newContent;
#if defined(WITH_JIT_TUNING)
gDvmJit.icPatchQueued++;
#endif
- }
+ } else {
/* Queue is full - just drop this patch request */
- else {
- result = false;
#if defined(WITH_JIT_TUNING)
gDvmJit.icPatchDropped++;
#endif
}
dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
- return result;
}
+#endif
/*
* This method is called from the invoke templates for virtual and interface
@@ -1476,23 +1541,27 @@
* but wrong chain to invoke a different method.
*/
const Method *dvmJitToPatchPredictedChain(const Method *method,
- void *unused,
+ InterpState *interpState,
PredictedChainingCell *cell,
const ClassObject *clazz)
{
+ int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
#if defined(WITH_SELF_VERIFICATION)
- /* Disable chaining and prevent this from triggering again for a while */
- cell->counter = PREDICTED_CHAIN_COUNTER_AVOID;
- cacheflush((long) cell, (long) (cell+1), 0);
+ newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID;
goto done;
#else
- /* Don't come back here for a long time if the method is native */
if (dvmIsNativeMethod(method)) {
- cell->counter = PREDICTED_CHAIN_COUNTER_AVOID;
- cacheflush((long) cell, (long) (cell+1), 0);
- COMPILER_TRACE_CHAINING(
- LOGD("Jit Runtime: predicted chain %p to native method %s ignored",
- cell, method->name));
+ UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
+
+ /*
+ * Put a non-zero/bogus value in the clazz field so that it won't
+ * trigger immediate patching and will continue to fail to match with
+ * a real clazz pointer.
+ */
+ cell->clazz = (void *) PREDICTED_CHAIN_FAKE_CLAZZ;
+
+ UPDATE_CODE_CACHE_PATCHES();
+ PROTECT_CODE_CACHE(cell, sizeof(*cell));
goto done;
}
int tgtAddr = (int) dvmJitGetCodeAddr(method->insns);
@@ -1501,13 +1570,8 @@
* Compilation not made yet for the callee. Reset the counter to a small
* value and come back to check soon.
*/
- if ((tgtAddr == 0) || ((void*)tgtAddr == gDvmJit.interpretTemplate)) {
- /*
- * Wait for a few invocations (currently set to be 16) before trying
- * to setup the chain again.
- */
- cell->counter = PREDICTED_CHAIN_COUNTER_DELAY;
- cacheflush((long) cell, (long) (cell+1), 0);
+ if ((tgtAddr == 0) ||
+ ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
COMPILER_TRACE_CHAINING(
LOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
cell, method->clazz->descriptor, method->name));
@@ -1516,8 +1580,9 @@
PredictedChainingCell newCell;
- /* Avoid back-to-back orders to the same cell */
- cell->counter = PREDICTED_CHAIN_COUNTER_AVOID;
+ if (cell->clazz == NULL) {
+ newRechainCount = interpState->icRechainCount;
+ }
int baseAddr = (int) cell + 4; // PC is cur_addr + 4
int branchOffset = tgtAddr - baseAddr;
@@ -1525,7 +1590,6 @@
newCell.branch = assembleChainingBranch(branchOffset, true);
newCell.clazz = clazz;
newCell.method = method;
- newCell.counter = PREDICTED_CHAIN_COUNTER_RECHAIN;
/*
* Enter the work order to the queue and the chaining cell will be patched
@@ -1534,11 +1598,10 @@
* If the enqueuing fails reset the rechain count to a normal value so that
* it won't get indefinitely delayed.
*/
- if (!inlineCachePatchEnqueue(cell, &newCell)) {
- cell->counter = PREDICTED_CHAIN_COUNTER_RECHAIN;
- }
+ inlineCachePatchEnqueue(cell, &newCell);
#endif
done:
+ interpState->icRechainCount = newRechainCount;
return method;
}
@@ -1561,6 +1624,8 @@
*/
dvmLockMutex(&gDvmJit.compilerICPatchLock);
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
//LOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
/* Initialize the min/max address range */
@@ -1574,21 +1639,13 @@
PredictedChainingCell *cellContent =
&gDvmJit.compilerICPatchQueue[i].cellContent;
- if (cellAddr->clazz == NULL) {
- COMPILER_TRACE_CHAINING(
- LOGD("Jit Runtime: predicted chain %p to %s (%s) initialized",
- cellAddr,
- cellContent->clazz->descriptor,
- cellContent->method->name));
- } else {
- COMPILER_TRACE_CHAINING(
- LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
- "patched",
- cellAddr,
- cellAddr->clazz->descriptor,
- cellContent->clazz->descriptor,
- cellContent->method->name));
- }
+ COMPILER_TRACE_CHAINING(
+ LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
+ "patched",
+ cellAddr,
+ cellAddr->clazz->descriptor,
+ cellContent->clazz->descriptor,
+ cellContent->method->name));
/* Patch the chaining cell */
*cellAddr = *cellContent;
@@ -1598,6 +1655,9 @@
/* Then synchronize the I/D cache */
cacheflush((long) minAddr, (long) (maxAddr+1), 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
gDvmJit.compilerICPatchIndex = 0;
dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
@@ -1619,8 +1679,6 @@
int cellSize;
u4* pChainCells;
u4* pStart;
- u4 thumb1;
- u4 thumb2;
u4 newInst;
int i,j;
PredictedChainingCell *predChainCell;
@@ -1628,9 +1686,10 @@
/* Get total count of chain cells */
for (i = 0, cellSize = 0; i < kChainingCellGap; i++) {
if (i != kChainingCellInvokePredicted) {
- cellSize += pChainCellCounts->u.count[i] * 2;
+ cellSize += pChainCellCounts->u.count[i] * (CHAIN_CELL_NORMAL_SIZE >> 2);
} else {
- cellSize += pChainCellCounts->u.count[i] * 4;
+ cellSize += pChainCellCounts->u.count[i] *
+ (CHAIN_CELL_PREDICTED_SIZE >> 2);
}
}
@@ -1643,25 +1702,30 @@
/* The cells are sorted in order - walk through them and reset */
for (i = 0; i < kChainingCellGap; i++) {
- int elemSize = 2; /* Most chaining cell has two words */
+ int elemSize = CHAIN_CELL_NORMAL_SIZE >> 2; /* In 32-bit words */
if (i == kChainingCellInvokePredicted) {
- elemSize = 4;
+ elemSize = CHAIN_CELL_PREDICTED_SIZE >> 2;
}
for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
- int targetOffset;
switch(i) {
case kChainingCellNormal:
- targetOffset = offsetof(InterpState,
- jitToInterpEntries.dvmJitToInterpNormal);
- break;
case kChainingCellHot:
case kChainingCellInvokeSingleton:
- targetOffset = offsetof(InterpState,
- jitToInterpEntries.dvmJitToInterpTraceSelect);
+ case kChainingCellBackwardBranch:
+ /*
+ * Replace the 1st half-word of the cell with an
+ * unconditional branch, leaving the 2nd half-word
+ * untouched. This avoids problems with a thread
+ * that is suspended between the two halves when
+ * this unchaining takes place.
+ */
+ newInst = *pChainCells;
+ newInst &= 0xFFFF0000;
+ newInst |= getSkeleton(kThumbBUncond); /* b offset is 0 */
+ *pChainCells = newInst;
break;
case kChainingCellInvokePredicted:
- targetOffset = 0;
predChainCell = (PredictedChainingCell *) pChainCells;
/*
* There could be a race on another mutator thread to use
@@ -1672,37 +1736,12 @@
*/
predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
break;
-#if defined(WITH_SELF_VERIFICATION)
- case kChainingCellBackwardBranch:
- targetOffset = offsetof(InterpState,
- jitToInterpEntries.dvmJitToInterpBackwardBranch);
- break;
-#elif defined(WITH_JIT_TUNING)
- case kChainingCellBackwardBranch:
- targetOffset = offsetof(InterpState,
- jitToInterpEntries.dvmJitToInterpNormal);
- break;
-#endif
default:
- targetOffset = 0; // make gcc happy
LOGE("Unexpected chaining type: %d", i);
dvmAbort(); // dvmAbort OK here - can't safely recover
}
COMPILER_TRACE_CHAINING(
LOGD("Jit Runtime: unchaining 0x%x", (int)pChainCells));
- /*
- * Thumb code sequence for a chaining cell is:
- * ldr r0, rGLUE, #<word offset>
- * blx r0
- */
- if (i != kChainingCellInvokePredicted) {
- targetOffset = targetOffset >> 2; /* convert to word offset */
- thumb1 = 0x6800 | (targetOffset << 6) |
- (rGLUE << 3) | (r0 << 0);
- thumb2 = 0x4780 | (r0 << 3);
- newInst = thumb2<<16 | thumb1;
- *pChainCells = newInst;
- }
pChainCells += elemSize; /* Advance by a fixed number of words */
}
}
@@ -1718,11 +1757,14 @@
if (gDvmJit.pJitEntryTable != NULL) {
COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all"));
dvmLockMutex(&gDvmJit.tableLock);
+
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
for (i = 0; i < gDvmJit.jitTableSize; i++) {
if (gDvmJit.pJitEntryTable[i].dPC &&
gDvmJit.pJitEntryTable[i].codeAddress &&
(gDvmJit.pJitEntryTable[i].codeAddress !=
- gDvmJit.interpretTemplate)) {
+ dvmCompilerGetInterpretTemplate())) {
u4* lastAddress;
lastAddress =
dvmJitUnchain(gDvmJit.pJitEntryTable[i].codeAddress);
@@ -1734,6 +1776,10 @@
}
}
cacheflush((long)lowAddress, (long)highAddress, 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
dvmUnlockMutex(&gDvmJit.tableLock);
gDvmJit.translationChains = 0;
}
@@ -1758,7 +1804,7 @@
return 0;
}
-char *getTraceBase(const JitEntry *p)
+static char *getTraceBase(const JitEntry *p)
{
return (char*)p->codeAddress -
(6 + (p->u.info.instructionSet == DALVIK_JIT_ARM ? 0 : 1));
@@ -1783,7 +1829,7 @@
LOGD("TRACEPROFILE 0x%08x 0 NULL 0 0", (int)traceBase);
return 0;
}
- if (p->codeAddress == gDvmJit.interpretTemplate) {
+ if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
if (!silent)
LOGD("TRACEPROFILE 0x%08x 0 INTERPRET_ONLY 0 0", (int)traceBase);
return 0;
@@ -1860,8 +1906,10 @@
/* Handy function to retrieve the profile count */
static inline int getProfileCount(const JitEntry *entry)
{
- if (entry->dPC == 0 || entry->codeAddress == 0)
+ if (entry->dPC == 0 || entry->codeAddress == 0 ||
+ entry->codeAddress == dvmCompilerGetInterpretTemplate())
return 0;
+
u4 *pExecutionCount = (u4 *) getTraceBase(entry);
return *pExecutionCount;
@@ -1928,6 +1976,10 @@
}
for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
+ /* Stip interpreter stubs */
+ if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
+ continue;
+ }
JitTraceDescription* desc =
dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
@@ -2242,7 +2294,6 @@
//LOGD("*** THUMB2 - Addr: 0x%x Insn: 0x%x", lr, insn);
int opcode12 = (insn >> 20) & 0xFFF;
- int opcode6 = (insn >> 6) & 0x3F;
int opcode4 = (insn >> 8) & 0xF;
int imm2 = (insn >> 4) & 0x3;
int imm8 = insn & 0xFF;
diff --git a/vm/compiler/codegen/arm/CalloutHelper.h b/vm/compiler/codegen/arm/CalloutHelper.h
index f6d5f4e..d6eb421 100644
--- a/vm/compiler/codegen/arm/CalloutHelper.h
+++ b/vm/compiler/codegen/arm/CalloutHelper.h
@@ -80,9 +80,12 @@
bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
const u2* arrayData);
-/* Switch dispatch offset calculation for OP_PACKED_SWITCH & OP_SPARSE_SWITCH */
-static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc);
-static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc);
+/*
+ * Switch dispatch offset calculation for OP_PACKED_SWITCH & OP_SPARSE_SWITCH
+ * Used in CodegenDriver.c
+ * static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc);
+ * static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc);
+ */
/*
* Resolve interface callsites - OP_INVOKE_INTERFACE & OP_INVOKE_INTERFACE_RANGE
diff --git a/vm/compiler/codegen/arm/Codegen.h b/vm/compiler/codegen/arm/Codegen.h
index da65bb5..ca0a843 100644
--- a/vm/compiler/codegen/arm/Codegen.h
+++ b/vm/compiler/codegen/arm/Codegen.h
@@ -25,6 +25,7 @@
#include "compiler/CompilerIR.h"
#include "CalloutHelper.h"
+#if defined(_CODEGEN_C)
/*
* loadConstant() sometimes needs to add a small imm to a pre-existing constant
*/
@@ -44,10 +45,16 @@
static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
+#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) || \
+ defined(__ARM_ARCH_5__)
static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir);
+#endif
static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir);
+#endif
+
+
#if defined(WITH_SELF_VERIFICATION)
/* Self Verification memory instruction decoder */
void dvmSelfVerificationMemOpDecode(int lr, int* sp);
diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c
index 0cec99d..d8854ba 100644
--- a/vm/compiler/codegen/arm/CodegenCommon.c
+++ b/vm/compiler/codegen/arm/CodegenCommon.c
@@ -256,6 +256,7 @@
return insn;
}
+#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
int dest, int src1, int src2, int info)
{
@@ -271,6 +272,7 @@
dvmCompilerAppendLIR(cUnit, (LIR *) insn);
return insn;
}
+#endif
/*
* If the next instruction is a move-result or move-result-long,
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index e9f00dd..37425ad 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -24,6 +24,25 @@
* applicable directory below this one.
*/
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
+{
+ int regCardBase = dvmCompilerAllocTemp(cUnit);
+ int regCardNo = dvmCompilerAllocTemp(cUnit);
+ opRegImm(cUnit, kOpCmp, valReg, 0); /* storing null? */
+ ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
+ loadWordDisp(cUnit, rGLUE, offsetof(InterpState, cardTable),
+ regCardBase);
+ opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+ storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+ kUnsignedByte);
+ ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *)target;
+}
+
static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
int srcSize, int tgtSize)
{
@@ -58,7 +77,6 @@
return false;
}
-
static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
RegLocation rlDest, RegLocation rlSrc1,
RegLocation rlSrc2)
@@ -197,7 +215,6 @@
static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
{
ArmLIR *thisLIR;
- ArmLIR *branchLIR = dvmCompilerNew(sizeof(ArmLIR), true);
TemplateOpCode opCode = TEMPLATE_MEM_OP_DECODE;
for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
@@ -237,7 +254,6 @@
/* Load a wide field from an object instance */
static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
RegLocation rlResult;
@@ -262,7 +278,6 @@
/* Store a wide field to an object instance */
static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
@@ -285,15 +300,14 @@
*
*/
static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
- int fieldOffset)
+ int fieldOffset, bool isVolatile)
{
- int regPtr;
RegLocation rlResult;
- DecodedInstruction *dInsn = &mir->dalvikInsn;
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
- rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
NULL);/* null object? */
@@ -301,6 +315,9 @@
loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
size, rlObj.sRegLow);
HEAP_ACCESS_SHADOW(false);
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit);
+ }
storeValue(cUnit, rlDest, rlResult);
}
@@ -310,20 +327,26 @@
*
*/
static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
- int fieldOffset)
+ int fieldOffset, bool isObject, bool isVolatile)
{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
- rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
- int regPtr;
+ rlSrc = loadValue(cUnit, rlSrc, regClass);
genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
NULL);/* null object? */
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit);
+ }
HEAP_ACCESS_SHADOW(true);
storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
HEAP_ACCESS_SHADOW(false);
+ if (isObject) {
+ /* NOTE: marking card based on object head */
+ markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
+ }
}
@@ -334,6 +357,7 @@
RegLocation rlArray, RegLocation rlIndex,
RegLocation rlDest, int scale)
{
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
int lenOffset = offsetof(ArrayObject, length);
int dataOffset = offsetof(ArrayObject, contents);
RegLocation rlResult;
@@ -373,7 +397,7 @@
} else {
opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
}
- rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
HEAP_ACCESS_SHADOW(true);
loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
@@ -382,7 +406,7 @@
dvmCompilerFreeTemp(cUnit, regPtr);
storeValueWide(cUnit, rlDest, rlResult);
} else {
- rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
HEAP_ACCESS_SHADOW(true);
loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
@@ -402,6 +426,7 @@
RegLocation rlArray, RegLocation rlIndex,
RegLocation rlSrc, int scale)
{
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
int lenOffset = offsetof(ArrayObject, length);
int dataOffset = offsetof(ArrayObject, contents);
@@ -450,7 +475,7 @@
} else {
opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
}
- rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+ rlSrc = loadValueWide(cUnit, rlSrc, regClass);
HEAP_ACCESS_SHADOW(true);
storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
@@ -458,7 +483,7 @@
dvmCompilerFreeTemp(cUnit, regPtr);
} else {
- rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+ rlSrc = loadValue(cUnit, rlSrc, regClass);
HEAP_ACCESS_SHADOW(true);
storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
@@ -531,12 +556,14 @@
dvmCompilerLockTemp(cUnit, regPtr); // r4PC
dvmCompilerLockTemp(cUnit, regIndex); // r7
dvmCompilerLockTemp(cUnit, r0);
+ dvmCompilerLockTemp(cUnit, r1);
/* Bad? - roll back and re-execute if so */
genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel);
- /* Resume here - must reload element, regPtr & index preserved */
+ /* Resume here - must reload element & array, regPtr & index preserved */
loadValueDirectFixed(cUnit, rlSrc, r0);
+ loadValueDirectFixed(cUnit, rlArray, r1);
ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
@@ -546,6 +573,9 @@
storeBaseIndexed(cUnit, regPtr, regIndex, r0,
scale, kWord);
HEAP_ACCESS_SHADOW(false);
+
+ /* NOTE: marking card here based on object head */
+ markCard(cUnit, r0, r1);
}
static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
@@ -872,7 +902,7 @@
static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
{
genDispatchToHandler(cUnit, TEMPLATE_RETURN);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.returnOp++;
#endif
int dPC = (int) (cUnit->method->insns + mir->offset);
@@ -1042,12 +1072,12 @@
*/
if (dvmIsNativeMethod(calleeMethod)) {
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokeNative++;
#endif
} else {
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokeMonomorphic++;
#endif
/* Branch to the chaining cell */
@@ -1147,6 +1177,8 @@
loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
+ genRegCopy(cUnit, r1, rGLUE);
+
/*
* r0 = calleeMethod
* r2 = &predictedChainingCell
@@ -1169,73 +1201,13 @@
* r4PC = callsiteDPC,
*/
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokePolymorphic++;
#endif
/* Handle exceptions using the interpreter */
genTrap(cUnit, mir->offset, pcrLabel);
}
-/*
- * Up calling this function, "this" is stored in r0. The actual class will be
- * chased down off r0 and the predicted one will be retrieved through
- * predictedChainingCell then a comparison is performed to see whether the
- * previously established chaining is still valid.
- *
- * The return LIR is a branch based on the comparison result. The actual branch
- * target will be setup in the caller.
- */
-static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
- ArmLIR *predChainingCell,
- ArmLIR *retChainingCell,
- MIR *mir)
-{
- /*
- * Note: all Dalvik register state should be flushed to
- * memory by the point, so register usage restrictions no
- * longer apply. All temp & preserved registers may be used.
- */
- dvmCompilerLockAllTemps(cUnit);
-
- /* r3 now contains this->clazz */
- loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
-
- /*
- * r2 now contains predicted class. The starting offset of the
- * cached value is 4 bytes into the chaining cell.
- */
- ArmLIR *getPredictedClass =
- loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
- getPredictedClass->generic.target = (LIR *) predChainingCell;
-
- /*
- * r0 now contains predicted method. The starting offset of the
- * cached value is 8 bytes into the chaining cell.
- */
- ArmLIR *getPredictedMethod =
- loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
- getPredictedMethod->generic.target = (LIR *) predChainingCell;
-
- /* Load the stats counter to see if it is time to unchain and refresh */
- ArmLIR *getRechainingRequestCount =
- loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
- getRechainingRequestCount->generic.target =
- (LIR *) predChainingCell;
-
- /* r4PC = dalvikCallsite */
- loadConstant(cUnit, r4PC,
- (int) (cUnit->method->insns + mir->offset));
-
- /* r1 = &retChainingCell */
- ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
- addrRetChain->generic.target = (LIR *) retChainingCell;
-
- /* Check if r2 (predicted class) == r3 (actual class) */
- opRegReg(cUnit, kOpCmp, r2, r3);
-
- return opCondBranch(cUnit, kArmCondEq);
-}
-
/* Geneate a branch to go back to the interpreter */
static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
{
@@ -1279,6 +1251,8 @@
opReg(cUnit, kOpBlx, r2);
}
+#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) || \
+ defined(_ARMV5TE) || defined(_ARMV5TE_VFP)
/*
* To prevent a thread in a monitor wait from blocking the Jit from
* resetting the code cache, heavyweight monitor lock will not
@@ -1324,6 +1298,7 @@
dvmCompilerClobberCallRegs(cUnit);
}
}
+#endif
/*
* The following are the first-level codegen routines that analyze the format
@@ -1342,8 +1317,7 @@
static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
{
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
- if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
- ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EB))) {
+ if ((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) {
LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
return true;
}
@@ -1354,6 +1328,8 @@
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
+ case OP_UNUSED_F1:
+ case OP_UNUSED_FF:
LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
return true;
case OP_NOP:
@@ -1446,7 +1422,12 @@
case OP_CONST_STRING: {
void *strPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
- assert(strPtr != NULL);
+
+ if (strPtr == NULL) {
+ LOGE("Unexpected null string");
+ dvmAbort();
+ }
+
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
@@ -1456,13 +1437,20 @@
case OP_CONST_CLASS: {
void *classPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
- assert(classPtr != NULL);
+
+ if (classPtr == NULL) {
+ LOGE("Unexpected null class");
+ dvmAbort();
+ }
+
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
storeValue(cUnit, rlDest, rlResult);
break;
}
+ case OP_SGET_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
case OP_SGET_OBJECT:
case OP_SGET_BOOLEAN:
case OP_SGET_CHAR:
@@ -1471,13 +1459,28 @@
case OP_SGET: {
int valOffset = offsetof(StaticField, value);
int tReg = dvmCompilerAllocTemp(cUnit);
+ bool isVolatile;
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
- assert(fieldPtr != NULL);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
+ isVolatile = (mir->dalvikInsn.opCode == OP_SGET_VOLATILE) ||
+ (mir->dalvikInsn.opCode == OP_SGET_OBJECT_VOLATILE) ||
+ dvmIsVolatileField(fieldPtr);
+
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit);
+ }
HEAP_ACCESS_SHADOW(true);
loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
HEAP_ACCESS_SHADOW(false);
@@ -1487,10 +1490,17 @@
}
case OP_SGET_WIDE: {
int valOffset = offsetof(StaticField, value);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
int tReg = dvmCompilerAllocTemp(cUnit);
- assert(fieldPtr != NULL);
rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1510,10 +1520,21 @@
case OP_SPUT: {
int valOffset = offsetof(StaticField, value);
int tReg = dvmCompilerAllocTemp(cUnit);
+ bool isVolatile;
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
- assert(fieldPtr != NULL);
+ isVolatile = (mir->dalvikInsn.opCode == OP_SPUT_VOLATILE) ||
+ (mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE) ||
+ dvmIsVolatileField(fieldPtr);
+
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1521,16 +1542,29 @@
HEAP_ACCESS_SHADOW(true);
storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
HEAP_ACCESS_SHADOW(false);
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit);
+ }
+ if (mir->dalvikInsn.opCode == OP_SPUT_OBJECT) {
+ /* NOTE: marking card based on field address */
+ markCard(cUnit, rlSrc.lowReg, tReg);
+ }
break;
}
case OP_SPUT_WIDE: {
int tReg = dvmCompilerAllocTemp(cUnit);
int valOffset = offsetof(StaticField, value);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
- assert(fieldPtr != NULL);
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1547,8 +1581,12 @@
*/
ClassObject *classPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
- assert(classPtr != NULL);
- assert(classPtr->status & CLASS_INITIALIZED);
+
+ if (classPtr == NULL) {
+ LOGE("Unexpected null class");
+ dvmAbort();
+ }
+
/*
* If it is going to throw, it should not make to the trace to begin
* with. However, Alloc might throw, so we need to genExportPC()
@@ -1632,12 +1670,31 @@
branch2->generic.target = (LIR *)target;
break;
}
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
+ genInterpSingleStep(cUnit, mir);
+ break;
default:
return true;
}
return false;
}
+/*
+ * A typical example of inlined getter/setter from a monomorphic callsite:
+ *
+ * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ invoke-static (I)
+ * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ...
+ * D/dalvikvm( 289): 0x4427fc22 (0002): ldr r0, [pc, #56]
+ * D/dalvikvm( 289): 0x4427fc24 (0004): ldr r1, [r0, #0]
+ * D/dalvikvm( 289): 0x4427fc26 (0006): str r1, [r5, #0]
+ * D/dalvikvm( 289): 0x4427fc28 (0008): .align4
+ * D/dalvikvm( 289): L0x0003:
+ * D/dalvikvm( 289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0
+ *
+ * Note the invoke-static and move-result-object with the (I) notation are
+ * turned into no-op.
+ */
static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
{
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
@@ -1659,6 +1716,9 @@
}
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_OBJECT: {
+ /* An inlined move result is effectively no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ break;
RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
rlSrc.fp = rlDest.fp;
@@ -1666,6 +1726,9 @@
break;
}
case OP_MOVE_RESULT_WIDE: {
+ /* An inlined move result is effectively no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ break;
RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
rlSrc.fp = rlDest.fp;
@@ -1898,6 +1961,57 @@
return bit_posn;
}
+// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
+// and store the result in 'rlDest'.
+static bool handleEasyDivide(CompilationUnit *cUnit, OpCode dalvikOpCode,
+ RegLocation rlSrc, RegLocation rlDest, int lit)
+{
+ if (lit < 2 || !isPowerOfTwo(lit)) {
+ return false;
+ }
+ int k = lowestSetBit(lit);
+ if (k >= 30) {
+ // Avoid special cases.
+ return false;
+ }
+ bool div = (dalvikOpCode == OP_DIV_INT_LIT8 || dalvikOpCode == OP_DIV_INT_LIT16);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (div) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ if (lit == 2) {
+ // Division by 2 is by far the most common division by constant.
+ opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+ opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+ } else {
+ opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
+ opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+ opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+ }
+ } else {
+ int cReg = dvmCompilerAllocTemp(cUnit);
+ loadConstant(cUnit, cReg, lit - 1);
+ int tReg1 = dvmCompilerAllocTemp(cUnit);
+ int tReg2 = dvmCompilerAllocTemp(cUnit);
+ if (lit == 2) {
+ opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+ opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+ } else {
+ opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
+ opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+ opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+ }
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ return true;
+}
+
// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
// and store the result in 'rlDest'.
static bool handleEasyMultiply(CompilationUnit *cUnit,
@@ -2019,6 +2133,9 @@
genInterpSingleStep(cUnit, mir);
return false;
}
+ if (handleEasyDivide(cUnit, dalvikOpCode, rlSrc, rlDest, lit)) {
+ return false;
+ }
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
loadValueDirectFixed(cUnit, rlSrc, r0);
dvmCompilerClobber(cUnit, r0);
@@ -2058,18 +2175,50 @@
static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
{
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
- int fieldOffset;
+ int fieldOffset = -1;
+ bool isVolatile = false;
+ switch (dalvikOpCode) {
+ /*
+ * Wide volatiles currently handled via single step.
+ * Add them here if generating in-line code.
+ * case OP_IGET_WIDE_VOLATILE:
+ * case OP_IPUT_WIDE_VOLATILE:
+ */
+ case OP_IGET:
+ case OP_IGET_VOLATILE:
+ case OP_IGET_WIDE:
+ case OP_IGET_OBJECT:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IPUT:
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT: {
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ Field *fieldPtr =
+ method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
- if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
- InstField *pInstField = (InstField *)
- cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
-
- assert(pInstField != NULL);
- fieldOffset = pInstField->byteOffset;
- } else {
- /* Deliberately break the code while make the compiler happy */
- fieldOffset = -1;
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null instance field");
+ dvmAbort();
+ }
+ isVolatile = dvmIsVolatileField(fieldPtr);
+ fieldOffset = ((InstField *)fieldPtr)->byteOffset;
+ break;
+ }
+ default:
+ break;
}
+
switch (dalvikOpCode) {
case OP_NEW_ARRAY: {
// Generates a call - use explicit registers
@@ -2078,7 +2227,12 @@
RegLocation rlResult;
void *classPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
- assert(classPtr != NULL);
+
+ if (classPtr == NULL) {
+ LOGE("Unexpected null class");
+ dvmAbort();
+ }
+
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
genExportPC(cUnit, mir);
loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
@@ -2088,8 +2242,7 @@
* "len < 0": bail to the interpreter to re-execute the
* instruction
*/
- ArmLIR *pcrLabel =
- genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
+ genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
opReg(cUnit, kOpBlx, r3);
dvmCompilerClobberCallRegs(cUnit);
@@ -2161,36 +2314,52 @@
case OP_IGET_WIDE:
genIGetWide(cUnit, mir, fieldOffset);
break;
+ case OP_IGET_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ isVolatile = true;
+ // NOTE: intentional fallthrough
case OP_IGET:
case OP_IGET_OBJECT:
- genIGet(cUnit, mir, kWord, fieldOffset);
+ genIGet(cUnit, mir, kWord, fieldOffset, isVolatile);
break;
case OP_IGET_BOOLEAN:
- genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
+ genIGet(cUnit, mir, kUnsignedByte, fieldOffset, isVolatile);
break;
case OP_IGET_BYTE:
- genIGet(cUnit, mir, kSignedByte, fieldOffset);
+ genIGet(cUnit, mir, kSignedByte, fieldOffset, isVolatile);
break;
case OP_IGET_CHAR:
- genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
+ genIGet(cUnit, mir, kUnsignedHalf, fieldOffset, isVolatile);
break;
case OP_IGET_SHORT:
- genIGet(cUnit, mir, kSignedHalf, fieldOffset);
+ genIGet(cUnit, mir, kSignedHalf, fieldOffset, isVolatile);
break;
case OP_IPUT_WIDE:
genIPutWide(cUnit, mir, fieldOffset);
break;
case OP_IPUT:
+ genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile);
+ break;
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ isVolatile = true;
+ // NOTE: intentional fallthrough
case OP_IPUT_OBJECT:
- genIPut(cUnit, mir, kWord, fieldOffset);
+ genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile);
break;
case OP_IPUT_SHORT:
case OP_IPUT_CHAR:
- genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
+ genIPut(cUnit, mir, kUnsignedHalf, fieldOffset, false, isVolatile);
break;
case OP_IPUT_BYTE:
+ genIPut(cUnit, mir, kSignedByte, fieldOffset, false, isVolatile);
+ break;
case OP_IPUT_BOOLEAN:
- genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
+ genIPut(cUnit, mir, kUnsignedByte, fieldOffset, false, isVolatile);
+ break;
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ genInterpSingleStep(cUnit, mir);
break;
default:
return true;
@@ -2205,11 +2374,13 @@
switch (dalvikOpCode) {
case OP_IGET_QUICK:
case OP_IGET_OBJECT_QUICK:
- genIGet(cUnit, mir, kWord, fieldOffset);
+ genIGet(cUnit, mir, kWord, fieldOffset, false);
break;
case OP_IPUT_QUICK:
+ genIPut(cUnit, mir, kWord, fieldOffset, false, false);
+ break;
case OP_IPUT_OBJECT_QUICK:
- genIPut(cUnit, mir, kWord, fieldOffset);
+ genIPut(cUnit, mir, kWord, fieldOffset, true, false);
break;
case OP_IGET_WIDE_QUICK:
genIGetWide(cUnit, mir, fieldOffset);
@@ -2400,10 +2571,10 @@
* blx &findPackedSwitchIndex
* mov pc, r0
* .align4
- * chaining cell for case 0 [8 bytes]
- * chaining cell for case 1 [8 bytes]
+ * chaining cell for case 0 [12 bytes]
+ * chaining cell for case 1 [12 bytes]
* :
- * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
+ * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes]
* chaining cell for case default [8 bytes]
* noChain exit
*/
@@ -2454,7 +2625,7 @@
jumpIndex = index;
}
- chainingPC += jumpIndex * 8;
+ chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
}
@@ -2505,13 +2676,14 @@
/* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
i : MAX_CHAINED_SWITCH_CASES + 1;
- chainingPC += jumpIndex * 8;
+ chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
return (((s8) entries[i]) << 32) | (u8) chainingPC;
} else if (k > testVal) {
break;
}
}
- return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
+ return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) *
+ CHAIN_CELL_NORMAL_SIZE;
}
static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
@@ -2551,10 +2723,6 @@
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
loadValueDirectFixed(cUnit, rlSrc, r1);
dvmCompilerLockAllTemps(cUnit);
- const u2 *switchData =
- cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
- u2 size = switchData[1];
-
if (dalvikOpCode == OP_PACKED_SWITCH) {
LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex);
} else {
@@ -2577,12 +2745,47 @@
return false;
}
+/*
+ * See the example of predicted inlining listed before the
+ * genValidationForPredictedInline function. The function here takes care the
+ * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
+ */
+static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb,
+ ArmLIR *labelList)
+{
+ BasicBlock *fallThrough = bb->fallThrough;
+
+ /* Bypass the move-result block if there is one */
+ if (fallThrough->firstMIRInsn) {
+ assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
+ fallThrough = fallThrough->fallThrough;
+ }
+ /* Generate a branch over if the predicted inlining is correct */
+ genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
+
+ /* Reset the register state */
+ dvmCompilerResetRegPool(cUnit);
+ dvmCompilerClobberAllRegs(cUnit);
+ dvmCompilerResetNullCheck(cUnit);
+
+ /* Target for the slow invoke path */
+ ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ /* Hook up the target to the verification branch */
+ mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
+}
+
static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
ArmLIR *labelList)
{
ArmLIR *retChainingCell = NULL;
ArmLIR *pcrLabel = NULL;
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ return false;
+
if (bb->fallThrough != NULL)
retChainingCell = &labelList[bb->fallThrough->id];
@@ -2600,6 +2803,15 @@
cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
methodIndex;
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
else
@@ -2617,10 +2829,11 @@
*/
case OP_INVOKE_SUPER:
case OP_INVOKE_SUPER_RANGE: {
- int mIndex = cUnit->method->clazz->pDvmDex->
- pResMethods[dInsn->vB]->methodIndex;
- const Method *calleeMethod =
- cUnit->method->clazz->super->vtable[mIndex];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod == cUnit->method->clazz->super->vtable[
+ cUnit->method->clazz->pDvmDex->
+ pResMethods[dInsn->vB]->methodIndex]);
if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2637,8 +2850,10 @@
/* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
case OP_INVOKE_DIRECT:
case OP_INVOKE_DIRECT_RANGE: {
- const Method *calleeMethod =
- cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2655,8 +2870,10 @@
/* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
case OP_INVOKE_STATIC:
case OP_INVOKE_STATIC_RANGE: {
- const Method *calleeMethod =
- cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
genProcessArgsNoRange(cUnit, mir, dInsn,
@@ -2746,10 +2963,15 @@
case OP_INVOKE_INTERFACE:
case OP_INVOKE_INTERFACE_RANGE: {
ArmLIR *predChainingCell = &labelList[bb->taken->id];
- int methodIndex = dInsn->vB;
- /* Ensure that nothing is both live and dirty */
- dvmCompilerFlushAllRegs(cUnit);
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2851,6 +3073,7 @@
loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
+ genRegCopy(cUnit, r1, rGLUE);
genRegCopy(cUnit, r2, r9);
genRegCopy(cUnit, r3, r10);
@@ -2877,7 +3100,7 @@
* r4PC = callsiteDPC,
*/
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokePolymorphic++;
#endif
/* Handle exceptions using the interpreter */
@@ -2907,12 +3130,26 @@
ArmLIR *predChainingCell = &labelList[bb->taken->id];
ArmLIR *pcrLabel = NULL;
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ return false;
+
DecodedInstruction *dInsn = &mir->dalvikInsn;
switch (mir->dalvikInsn.opCode) {
/* calleeMethod = this->clazz->vtable[BBBB] */
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_VIRTUAL_QUICK: {
int methodIndex = dInsn->vB;
+
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
else
@@ -2927,8 +3164,10 @@
/* calleeMethod = method->clazz->super->vtable[BBBB] */
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE: {
- const Method *calleeMethod =
- cUnit->method->clazz->super->vtable[dInsn->vB];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->super->vtable[dInsn->vB]);
if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2940,8 +3179,6 @@
genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
calleeMethod);
- /* Handle exceptions using the interpreter */
- genTrap(cUnit, mir->offset, pcrLabel);
break;
}
default:
@@ -2982,7 +3219,7 @@
#endif
}
-static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
+static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
{
#if defined(USE_GLOBAL_STRING_DEFS)
return false;
@@ -2992,12 +3229,8 @@
loadValueDirectFixed(cUnit, rlThis, r0);
loadValueDirectFixed(cUnit, rlChar, r1);
- if (!singleI) {
- RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
- loadValueDirectFixed(cUnit, rlStart, r2);
- } else {
- loadConstant(cUnit, r2, 0);
- }
+ RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
+ loadValueDirectFixed(cUnit, rlStart, r2);
/* Test objects for NULL */
genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
@@ -3007,8 +3240,11 @@
#endif
}
-static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+// Generates an inlined String.isEmpty or String.length.
+static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
+ bool isEmpty)
{
+ // dst = src.length();
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlDest = inlinedTarget(cUnit, mir, false);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
@@ -3016,10 +3252,26 @@
genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
rlResult.lowReg);
+ if (isEmpty) {
+ // dst = (dst == 0);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg);
+ opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg);
+ }
storeValue(cUnit, rlDest, rlResult);
return false;
}
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+ return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
+}
+
+static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
+{
+ return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
+}
+
static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
{
int contents = offsetof(ArrayObject, contents);
@@ -3102,13 +3354,13 @@
const InlineOperation* inLineTable = dvmGetInlineOpsTable();
int offset = offsetof(InterpState, retval);
int operation = dInsn->vB;
- int tReg1;
- int tReg2;
switch (operation) {
case INLINE_EMPTYINLINEMETHOD:
return false; /* Nop */
case INLINE_STRING_LENGTH:
return genInlinedStringLength(cUnit, mir);
+ case INLINE_STRING_IS_EMPTY:
+ return genInlinedStringIsEmpty(cUnit, mir);
case INLINE_MATH_ABS_INT:
return genInlinedAbsInt(cUnit, mir);
case INLINE_MATH_ABS_LONG:
@@ -3139,13 +3391,8 @@
return false;
else
break;
- case INLINE_STRING_INDEXOF_I:
- if (genInlinedIndexOf(cUnit, mir, true /* I */))
- return false;
- else
- break;
- case INLINE_STRING_INDEXOF_II:
- if (genInlinedIndexOf(cUnit, mir, false /* I */))
+ case INLINE_STRING_FASTINDEXOF_II:
+ if (genInlinedFastIndexOf(cUnit, mir))
return false;
else
break;
@@ -3204,6 +3451,27 @@
* Dalvik PC and special-purpose registers are reconstructed here.
*/
+/*
+ * Insert a
+ * b .+4
+ * nop
+ * pair at the beginning of a chaining cell. This serves as the
+ * switch branch that selects between reverting to the interpreter or
+ * not. Once the cell is chained to a translation, the cell will
+ * contain a 32-bit branch. Subsequent chain/unchain operations will
+ * then only alter that first 16-bits - the "b .+4" for unchaining,
+ * and the restoration of the first half of the 32-bit branch for
+ * rechaining.
+ */
+static void insertChainingSwitch(CompilationUnit *cUnit)
+{
+ ArmLIR *branch = newLIR0(cUnit, kThumbBUncond);
+ newLIR2(cUnit, kThumbOrr, r0, r0);
+ ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branch->generic.target = (LIR *) target;
+}
+
/* Chaining cell for code that may need warmup. */
static void handleNormalChainingCell(CompilationUnit *cUnit,
unsigned int offset)
@@ -3212,6 +3480,7 @@
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
jitToInterpEntries.dvmJitToInterpNormal) >> 2);
@@ -3230,6 +3499,7 @@
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
@@ -3246,6 +3516,7 @@
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
#if defined(WITH_SELF_VERIFICATION)
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
@@ -3267,6 +3538,7 @@
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
@@ -3313,6 +3585,7 @@
"kMirOpNullNRangeDownCheck",
"kMirOpLowerBound",
"kMirOpPunt",
+ "kMirOpCheckInlinePrediction",
};
/*
@@ -3334,7 +3607,6 @@
DecodedInstruction *dInsn = &mir->dalvikInsn;
const int lenOffset = offsetof(ArrayObject, length);
const int maxC = dInsn->arg[0];
- const int minC = dInsn->arg[1];
int regLength;
RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
@@ -3383,7 +3655,6 @@
const int lenOffset = offsetof(ArrayObject, length);
const int regLength = dvmCompilerAllocTemp(cUnit);
const int maxC = dInsn->arg[0];
- const int minC = dInsn->arg[1];
RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
@@ -3426,6 +3697,110 @@
(ArmLIR *) cUnit->loopAnalysis->branchToPCR);
}
+/*
+ * vC = this
+ *
+ * A predicted inlining target looks like the following, where instructions
+ * between 0x4858de66 and 0x4858de72 are checking if the predicted class
+ * matches "this", and the verificaion code is generated by this routine.
+ *
+ * (C) means the instruction is inlined from the callee, and (PI) means the
+ * instruction is the predicted inlined invoke, whose corresponding
+ * instructions are still generated to handle the mispredicted case.
+ *
+ * D/dalvikvm( 86): -------- kMirOpCheckInlinePrediction
+ * D/dalvikvm( 86): 0x4858de66 (0002): ldr r0, [r5, #68]
+ * D/dalvikvm( 86): 0x4858de68 (0004): ldr r1, [pc, #140]
+ * D/dalvikvm( 86): 0x4858de6a (0006): cmp r0, #0
+ * D/dalvikvm( 86): 0x4858de6c (0008): beq 0x4858deb2
+ * D/dalvikvm( 86): 0x4858de6e (000a): ldr r2, [r0, #0]
+ * D/dalvikvm( 86): 0x4858de70 (000c): cmp r1, r2
+ * D/dalvikvm( 86): 0x4858de72 (000e): bne 0x4858de7a
+ * D/dalvikvm( 86): -------- dalvik offset: 0x004c @ +iget-object-quick (C)
+ * v4, v17, (#8)
+ * D/dalvikvm( 86): 0x4858de74 (0010): ldr r3, [r0, #8]
+ * D/dalvikvm( 86): 0x4858de76 (0012): str r3, [r5, #16]
+ * D/dalvikvm( 86): -------- dalvik offset: 0x004c @
+ * +invoke-virtual-quick/range (PI) v17..v17
+ * D/dalvikvm( 86): 0x4858de78 (0014): b 0x4858debc
+ * D/dalvikvm( 86): 0x4858de7a (0016): add r4,r5,#68
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de7e (001a): ldmia r4, <r0>
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de80 (001c): sub r7,r5,#24
+ * D/dalvikvm( 86): 0x4858de84 (0020): cmp r0, #0
+ * D/dalvikvm( 86): 0x4858de86 (0022): beq 0x4858deb6
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de88 (0024): stmia r7, <r0>
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de8a (0026): ldr r4, [pc, #104]
+ * D/dalvikvm( 86): 0x4858de8c (0028): add r1, pc, #28
+ * D/dalvikvm( 86): 0x4858de8e (002a): add r2, pc, #56
+ * D/dalvikvm( 86): 0x4858de90 (002c): blx_1 0x48589198
+ * D/dalvikvm( 86): 0x4858de92 (002e): blx_2 see above
+ * D/dalvikvm( 86): 0x4858de94 (0030): b 0x4858dec8
+ * D/dalvikvm( 86): 0x4858de96 (0032): b 0x4858deb6
+ * D/dalvikvm( 86): 0x4858de98 (0034): ldr r0, [r7, #72]
+ * D/dalvikvm( 86): 0x4858de9a (0036): cmp r1, #0
+ * D/dalvikvm( 86): 0x4858de9c (0038): bgt 0x4858dea4
+ * D/dalvikvm( 86): 0x4858de9e (003a): ldr r7, [r6, #116]
+ * D/dalvikvm( 86): 0x4858dea0 (003c): movs r1, r6
+ * D/dalvikvm( 86): 0x4858dea2 (003e): blx r7
+ * D/dalvikvm( 86): 0x4858dea4 (0040): add r1, pc, #4
+ * D/dalvikvm( 86): 0x4858dea6 (0042): blx_1 0x485890a0
+ * D/dalvikvm( 86): 0x4858dea8 (0044): blx_2 see above
+ * D/dalvikvm( 86): 0x4858deaa (0046): b 0x4858deb6
+ * D/dalvikvm( 86): 0x4858deac (0048): .align4
+ * D/dalvikvm( 86): L0x004f:
+ * D/dalvikvm( 86): -------- dalvik offset: 0x004f @ move-result-object (PI)
+ * v4, (#0), (#0)
+ * D/dalvikvm( 86): 0x4858deac (0048): ldr r4, [r6, #8]
+ * D/dalvikvm( 86): 0x4858deae (004a): str r4, [r5, #16]
+ * D/dalvikvm( 86): 0x4858deb0 (004c): b 0x4858debc
+ * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm( 86): 0x4858deb2 (004e): ldr r0, [pc, #64]
+ * D/dalvikvm( 86): 0x4858deb4 (0050): b 0x4858deb8
+ * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm( 86): 0x4858deb6 (0052): ldr r0, [pc, #60]
+ * D/dalvikvm( 86): Exception_Handling:
+ * D/dalvikvm( 86): 0x4858deb8 (0054): ldr r1, [r6, #100]
+ * D/dalvikvm( 86): 0x4858deba (0056): blx r1
+ * D/dalvikvm( 86): 0x4858debc (0058): .align4
+ * D/dalvikvm( 86): -------- chaining cell (hot): 0x0050
+ * D/dalvikvm( 86): 0x4858debc (0058): b 0x4858dec0
+ * D/dalvikvm( 86): 0x4858debe (005a): orrs r0, r0
+ * D/dalvikvm( 86): 0x4858dec0 (005c): ldr r0, [r6, #112]
+ * D/dalvikvm( 86): 0x4858dec2 (005e): blx r0
+ * D/dalvikvm( 86): 0x4858dec4 (0060): data 0xefd4(61396)
+ * D/dalvikvm( 86): 0x4858dec6 (0062): data 0x42be(17086)
+ * D/dalvikvm( 86): 0x4858dec8 (0064): .align4
+ * D/dalvikvm( 86): -------- chaining cell (predicted)
+ * D/dalvikvm( 86): 0x4858dec8 (0064): data 0xe7fe(59390)
+ * D/dalvikvm( 86): 0x4858deca (0066): data 0x0000(0)
+ * D/dalvikvm( 86): 0x4858decc (0068): data 0x0000(0)
+ * D/dalvikvm( 86): 0x4858dece (006a): data 0x0000(0)
+ * :
+ */
+static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
+{
+ CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+ RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
+
+ rlThis = loadValue(cUnit, rlThis, kCoreReg);
+ int regPredictedClass = dvmCompilerAllocTemp(cUnit);
+ loadConstant(cUnit, regPredictedClass, (int) callsiteInfo->clazz);
+ genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
+ NULL);/* null object? */
+ int regActualClass = dvmCompilerAllocTemp(cUnit);
+ loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
+ opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
+ /*
+ * Set the misPredBranchOver target so that it will be generated when the
+ * code for the non-optimized invoke is generated.
+ */
+ callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe);
+}
+
/* Extended MIR instructions like PHI */
static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
{
@@ -3458,6 +3833,10 @@
(ArmLIR *) cUnit->loopAnalysis->branchToPCR);
break;
}
+ case kMirOpCheckInlinePrediction: {
+ genValidationForPredictedInline(cUnit, mir);
+ break;
+ }
default:
break;
}
@@ -3504,7 +3883,7 @@
{
DecodedInstruction *decInsn = &mir->dalvikInsn;
OpCode op = decInsn->opCode;
- int flags = dexGetInstrFlags(gDvm.instrFlags, op);
+
/*
* All opcodes that can throw exceptions and use the
* TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
@@ -3514,8 +3893,7 @@
op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY ||
op == OP_CHECK_CAST || op == OP_MOVE_EXCEPTION ||
op == OP_FILL_ARRAY_DATA || op == OP_EXECUTE_INLINE ||
- op == OP_EXECUTE_INLINE_RANGE ||
- (flags & kInstrInvoke));
+ op == OP_EXECUTE_INLINE_RANGE);
}
#endif
@@ -3578,6 +3956,10 @@
labelList[i].operands[0] = blockList[i]->startOffset;
if (blockList[i]->blockType >= kChainingCellGap) {
+ if (blockList[i]->isFallThroughFromInvoke == true) {
+ /* Align this block first since it is a return chaining cell */
+ newLIR0(cUnit, kArmPseudoPseudoAlign4);
+ }
/*
* Append the label pseudo LIR first. Chaining cells will be handled
* separately afterwards.
@@ -3585,7 +3967,7 @@
dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
}
- if (blockList[i]->blockType == kEntryBlock) {
+ if (blockList[i]->blockType == kTraceEntryBlock) {
labelList[i].opCode = kArmPseudoEntryBlock;
if (blockList[i]->firstMIRInsn == NULL) {
continue;
@@ -3593,7 +3975,7 @@
setupLoopEntryBlock(cUnit, blockList[i],
&labelList[blockList[i]->fallThrough->id]);
}
- } else if (blockList[i]->blockType == kExitBlock) {
+ } else if (blockList[i]->blockType == kTraceExitBlock) {
labelList[i].opCode = kArmPseudoExitBlock;
goto gen_fallthrough;
} else if (blockList[i]->blockType == kDalvikByteCode) {
@@ -3690,11 +4072,22 @@
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
InstructionFormat dalvikFormat =
dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
+ char *note;
+ if (mir->OptimizationFlags & MIR_INLINED) {
+ note = " (I)";
+ } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
+ note = " (PI)";
+ } else if (mir->OptimizationFlags & MIR_CALLEE) {
+ note = " (C)";
+ } else {
+ note = NULL;
+ }
+
ArmLIR *boundaryLIR =
newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
mir->offset,
- (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
- );
+ (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn,
+ note));
if (mir->ssaRep) {
char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
@@ -3813,14 +4206,14 @@
if (notHandled) {
LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
mir->offset,
- dalvikOpCode, getOpcodeName(dalvikOpCode),
+ dalvikOpCode, dexGetOpcodeName(dalvikOpCode),
dalvikFormat);
dvmCompilerAbort(cUnit);
break;
}
}
- if (blockList[i]->blockType == kEntryBlock) {
+ if (blockList[i]->blockType == kTraceEntryBlock) {
dvmCompilerAppendLIR(cUnit,
(LIR *) cUnit->loopAnalysis->branchToBody);
dvmCompilerAppendLIR(cUnit,
@@ -3914,7 +4307,7 @@
jitToInterpEntries.dvmJitToInterpNoChain), r2);
opRegReg(cUnit, kOpAdd, r1, r1);
opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
loadConstant(cUnit, r0, kSwitchOverflow);
#endif
opReg(cUnit, kOpBlx, r2);
@@ -3937,9 +4330,6 @@
}
switch (work->kind) {
- case kWorkOrderMethod:
- res = dvmCompileMethod(work->info, &work->result);
- break;
case kWorkOrderTrace:
/* Start compilation with maximally allowed trace length */
res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
@@ -3951,13 +4341,13 @@
/* Start compilation with maximally allowed trace length */
res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
work->bailPtr);
- gDvmJit.printMe = oldPrintMe;;
+ gDvmJit.printMe = oldPrintMe;
break;
}
default:
res = false;
LOGE("Jit: unknown work order type");
- assert(0); // Bail if debug build, discard oteherwise
+ assert(0); // Bail if debug build, discard otherwise
}
return res;
}
diff --git a/vm/compiler/codegen/arm/CodegenFactory.c b/vm/compiler/codegen/arm/CodegenFactory.c
index 824e1a0..157bd1f 100644
--- a/vm/compiler/codegen/arm/CodegenFactory.c
+++ b/vm/compiler/codegen/arm/CodegenFactory.c
@@ -112,7 +112,6 @@
static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
RegisterClass opKind)
{
- RegisterInfo *pReg;
rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
if (rlSrc.location == kLocDalvikFrame) {
loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
@@ -129,7 +128,6 @@
static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
RegLocation rlSrc)
{
- RegisterInfo *pRegLo;
LIR *defStart;
LIR *defEnd;
assert(!rlDest.wide);
@@ -179,8 +177,6 @@
static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
RegisterClass opKind)
{
- RegisterInfo *pRegLo;
- RegisterInfo *pRegHi;
assert(rlSrc.wide);
rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
if (rlSrc.location == kLocDalvikFrame) {
@@ -202,11 +198,8 @@
static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
RegLocation rlSrc)
{
- RegisterInfo *pRegLo;
- RegisterInfo *pRegHi;
LIR *defStart;
LIR *defEnd;
- bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
assert(rlDest.wide);
assert(rlSrc.wide);
diff --git a/vm/compiler/codegen/arm/FP/Thumb2VFP.c b/vm/compiler/codegen/arm/FP/Thumb2VFP.c
index 9149646..b5bcf99 100644
--- a/vm/compiler/codegen/arm/FP/Thumb2VFP.c
+++ b/vm/compiler/codegen/arm/FP/Thumb2VFP.c
@@ -183,7 +183,6 @@
static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
{
ArmLIR *branch;
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
@@ -212,7 +211,6 @@
{
bool isDouble;
int defaultResult;
- bool ltNaNBias;
RegLocation rlResult;
switch(mir->dalvikInsn.opCode) {
diff --git a/vm/compiler/codegen/arm/LocalOptimizations.c b/vm/compiler/codegen/arm/LocalOptimizations.c
index 85dfa8e..724fdb7 100644
--- a/vm/compiler/codegen/arm/LocalOptimizations.c
+++ b/vm/compiler/codegen/arm/LocalOptimizations.c
@@ -50,6 +50,8 @@
return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
}
+#if 0
+/* Debugging utility routine */
static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
const char *optimization)
{
@@ -57,6 +59,7 @@
dvmDumpLIRInsn((LIR *) thisLIR, 0);
dvmDumpLIRInsn((LIR *) checkLIR, 0);
}
+#endif
/*
* Perform a pass of top-down walk to
@@ -78,8 +81,6 @@
continue;
}
if (isDalvikStore(thisLIR)) {
- int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
- int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
int nativeRegId = thisLIR->operands[0];
ArmLIR *checkLIR;
int sinkDistance = 0;
@@ -208,7 +209,6 @@
if (isDalvikLoad(thisLIR)) {
int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
- int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
int nativeRegId = thisLIR->operands[0];
ArmLIR *checkLIR;
int hoistDistance = 0;
diff --git a/vm/compiler/codegen/arm/README.txt b/vm/compiler/codegen/arm/README.txt
index 6698ac3..a49eef8 100644
--- a/vm/compiler/codegen/arm/README.txt
+++ b/vm/compiler/codegen/arm/README.txt
@@ -46,4 +46,3 @@
In this way the dependency between generic and specific code tied to
particular architectures can be explicitly represented.
-
diff --git a/vm/compiler/codegen/arm/Ralloc.h b/vm/compiler/codegen/arm/Ralloc.h
index 6c7dfaa..cc3e605 100644
--- a/vm/compiler/codegen/arm/Ralloc.h
+++ b/vm/compiler/codegen/arm/Ralloc.h
@@ -27,6 +27,20 @@
#include "compiler/Dataflow.h"
#include "compiler/codegen/arm/ArmLIR.h"
+/*
+ * Return most flexible allowed register class based on size.
+ * Bug: 2813841
+ * Must use a core register for data types narrower than word (due
+ * to possible unaligned load/store.
+ */
+static inline RegisterClass dvmCompilerRegClassBySize(OpSize size)
+{
+ return (size == kUnsignedHalf ||
+ size == kSignedHalf ||
+ size == kUnsignedByte ||
+ size == kSignedByte ) ? kCoreReg : kAnyReg;
+}
+
static inline int dvmCompilerS2VReg(CompilationUnit *cUnit, int sReg)
{
assert(sReg != INVALID_SREG);
diff --git a/vm/compiler/codegen/arm/RallocUtil.c b/vm/compiler/codegen/arm/RallocUtil.c
index e357ba6..e917995 100644
--- a/vm/compiler/codegen/arm/RallocUtil.c
+++ b/vm/compiler/codegen/arm/RallocUtil.c
@@ -463,14 +463,6 @@
dvmCompilerAbort(cUnit);
}
-static void lockArgRegs(CompilationUnit *cUnit)
-{
- dvmCompilerLockTemp(cUnit, r0);
- dvmCompilerLockTemp(cUnit, r1);
- dvmCompilerLockTemp(cUnit, r2);
- dvmCompilerLockTemp(cUnit, r3);
-}
-
/* Clobber all regs that might be used by an external C call */
extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
{
@@ -490,6 +482,8 @@
//TUNING: reduce the set of regs used by handlers. Only a few need lots.
dvmCompilerClobberCallRegs(cUnit);
dvmCompilerClobber(cUnit, r4PC);
+ dvmCompilerClobber(cUnit, r7);
+ dvmCompilerClobber(cUnit, r8);
dvmCompilerClobber(cUnit, r9);
dvmCompilerClobber(cUnit, r10);
}
@@ -698,12 +692,6 @@
infoHi->partner = lowReg;
}
-static void markRegSingle(CompilationUnit *cUnit, int reg)
-{
- RegisterInfo *info = getRegInfo(cUnit, reg);
- info->pair = false;
-}
-
extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
@@ -722,13 +710,6 @@
info->inUse = true;
}
-/* Return true if live & dirty */
-static bool isDirty(CompilationUnit *cUnit, int reg)
-{
- RegisterInfo *info = getRegInfo(cUnit, reg);
- return (info && info->live && info->dirty);
-}
-
void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
{
RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
@@ -870,7 +851,6 @@
extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
int regClass, bool update)
{
- RegisterInfo *infoLo = NULL;
int newReg;
if (loc.wide)
return evalLocWide(cUnit, loc, regClass, update);
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.c b/vm/compiler/codegen/arm/Thumb/Factory.c
index 4c010c6..85f612e 100644
--- a/vm/compiler/codegen/arm/Thumb/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb/Factory.c
@@ -23,7 +23,6 @@
*/
static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
-static int corePreserved[] = {};
static void storePair(CompilationUnit *cUnit, int base, int lowReg,
int highReg);
@@ -569,7 +568,6 @@
ArmLIR *load2 = NULL;
ArmOpCode opCode = kThumbBkpt;
bool shortForm = false;
- int shortMax = 128;
int encodedDisp = displacement;
bool pair = false;
@@ -700,7 +698,6 @@
ArmLIR *store2 = NULL;
ArmOpCode opCode = kThumbBkpt;
bool shortForm = false;
- int shortMax = 128;
int encodedDisp = displacement;
bool pair = false;
diff --git a/vm/compiler/codegen/arm/Thumb/Gen.c b/vm/compiler/codegen/arm/Thumb/Gen.c
index e014795..37cc18d 100644
--- a/vm/compiler/codegen/arm/Thumb/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb/Gen.c
@@ -112,7 +112,6 @@
void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
{
- int i;
int numTemps = sizeof(coreTemps)/sizeof(int);
RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
cUnit->regPool = pool;
diff --git a/vm/compiler/codegen/arm/Thumb2/Factory.c b/vm/compiler/codegen/arm/Thumb2/Factory.c
index 360b2c1..c7b52fd 100644
--- a/vm/compiler/codegen/arm/Thumb2/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb2/Factory.c
@@ -23,10 +23,8 @@
*/
static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
-static int corePreserved[] = {};
static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
-static int fpPreserved[] = {};
static int encodeImmSingle(int value)
{
@@ -579,7 +577,6 @@
static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
int value)
{
- ArmLIR *res;
bool neg = (value < 0);
int absValue = (neg) ? -value : value;
bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
@@ -751,15 +748,9 @@
if (FPREG(rSrc)) {
assert(SINGLEREG(rSrc));
- if ((size != kWord) && (size != kSingle)) {
- /* Move float value into core register */
- int tReg = dvmCompilerAllocTemp(cUnit);
- dvmCompilerRegCopy(cUnit, tReg, rSrc);
- rSrc = tReg;
- } else {
- opCode = kThumb2Vstrs;
- size = kSingle;
- }
+ assert((size == kWord) || (size == kSingle));
+ opCode = kThumb2Vstrs;
+ size = kSingle;
} else {
if (size == kSingle)
size = kWord;
@@ -819,7 +810,6 @@
ArmOpCode opCode = kThumbBkpt;
bool shortForm = false;
bool thumb2Form = (displacement < 4092 && displacement >= 0);
- int shortMax = 128;
bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
int encodedDisp = displacement;
@@ -954,7 +944,6 @@
ArmOpCode opCode = kThumbBkpt;
bool shortForm = false;
bool thumb2Form = (displacement < 4092 && displacement >= 0);
- int shortMax = 128;
bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
int encodedDisp = displacement;
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
index 1782bec..de75be7 100644
--- a/vm/compiler/codegen/arm/Thumb2/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.c
@@ -87,7 +87,6 @@
void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
{
- int i;
int numTemps = sizeof(coreTemps)/sizeof(int);
int numFPTemps = sizeof(fpTemps)/sizeof(int);
RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
@@ -193,7 +192,6 @@
static void genMonitorEnter(CompilationUnit *cUnit, MIR *mir)
{
RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
- bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
ArmLIR *target;
ArmLIR *hopTarget;
ArmLIR *branch;
diff --git a/vm/compiler/codegen/arm/Thumb2/Ralloc.c b/vm/compiler/codegen/arm/Thumb2/Ralloc.c
index bfd7f3f..6adfd62 100644
--- a/vm/compiler/codegen/arm/Thumb2/Ralloc.c
+++ b/vm/compiler/codegen/arm/Thumb2/Ralloc.c
@@ -22,6 +22,9 @@
*
*/
+/* Stress mode for testing: if defined will reverse corereg/floatreg hint */
+//#define REGCLASS_STRESS_MODE
+
/*
* Alloc a pair of core registers, or a double. Low reg in low byte,
* high reg in next byte.
@@ -32,6 +35,11 @@
int highReg;
int lowReg;
int res = 0;
+
+#if defined(REGCLASS_STRESS_MODE)
+ fpHint = !fpHint;
+#endif
+
if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
lowReg = dvmCompilerAllocTempDouble(cUnit);
highReg = lowReg + 1;
@@ -46,6 +54,9 @@
int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint,
int regClass)
{
+#if defined(REGCLASS_STRESS_MODE)
+ fpHint = !fpHint;
+#endif
if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
return dvmCompilerAllocTempFloat(cUnit);
return dvmCompilerAllocTemp(cUnit);
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
index 7f9fa3b..6511eac 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
@@ -92,3 +92,10 @@
}
return res;
}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit)
+{
+#if ANDROID_SMP != 0
+#error armv5+smp not supported
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
index 04bb3a2..eda243f 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define _CODEGEN_C
+#define _ARMV5TE_VFP
#include "Dalvik.h"
#include "interp/InterpDefs.h"
#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include "compiler/CompilerInternals.h"
#include "compiler/codegen/arm/ArmLIR.h"
#include "mterp/common/FindInterface.h"
diff --git a/vm/compiler/codegen/arm/armv5te/ArchVariant.c b/vm/compiler/codegen/arm/armv5te/ArchVariant.c
index e018ea1..814f410 100644
--- a/vm/compiler/codegen/arm/armv5te/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv5te/ArchVariant.c
@@ -92,3 +92,10 @@
}
return res;
}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit)
+{
+#if ANDROID_SMP != 0
+#error armv5+smp not supported
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv5te/Codegen.c b/vm/compiler/codegen/arm/armv5te/Codegen.c
index 5e53ae4..f953390 100644
--- a/vm/compiler/codegen/arm/armv5te/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te/Codegen.c
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define _CODEGEN_C
+#define _ARMV5TE
#include "Dalvik.h"
#include "interp/InterpDefs.h"
#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include "compiler/CompilerInternals.h"
#include "compiler/codegen/arm/ArmLIR.h"
#include "mterp/common/FindInterface.h"
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
index 5a14774..f1727c6 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
@@ -87,3 +87,11 @@
}
return res;
}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit)
+{
+#if ANDROID_SMP != 0
+ ArmLIR *dmb = newLIR1(cUnit, kThumb2Dmb, kSY); // Full system DMB
+ dmb->defMask = ENCODE_ALL;
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
index baa9632..1edc25b 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define _CODEGEN_C
+#define _ARMV7_A_NEON
#include "Dalvik.h"
#include "interp/InterpDefs.h"
#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include "compiler/CompilerInternals.h"
#include "compiler/codegen/arm/ArmLIR.h"
#include "mterp/common/FindInterface.h"
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
index 5a14774..f1727c6 100644
--- a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
@@ -87,3 +87,11 @@
}
return res;
}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit)
+{
+#if ANDROID_SMP != 0
+ ArmLIR *dmb = newLIR1(cUnit, kThumb2Dmb, kSY); // Full system DMB
+ dmb->defMask = ENCODE_ALL;
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a/Codegen.c b/vm/compiler/codegen/arm/armv7-a/Codegen.c
index baa9632..1514d55 100644
--- a/vm/compiler/codegen/arm/armv7-a/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a/Codegen.c
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define _CODEGEN_C
+#define _ARMV7_A
#include "Dalvik.h"
#include "interp/InterpDefs.h"
#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include "compiler/CompilerInternals.h"
#include "compiler/codegen/arm/ArmLIR.h"
#include "mterp/common/FindInterface.h"
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S
index 1b143a9..992c894 100644
--- a/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S
@@ -31,4 +31,3 @@
mvnmi r0, #0 @ (less than) r0<- -1
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
index 01772b4..15988f6 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
@@ -34,4 +34,3 @@
bxcc r11
$naninst @ r1<- 1 or -1 for NaN
bx r11
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
index b63780f..eb1c7e1 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
@@ -52,5 +52,3 @@
bxcc r11
$naninst @ r1<- 1 or -1 for NaN
bx r11
-
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
index 5f1e16b..e5e8196 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
@@ -31,4 +31,3 @@
.L${opcode}_greater:
mov r0, #1 @ r0<- 1
bx lr
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INTERPRET.S b/vm/compiler/template/armv5te/TEMPLATE_INTERPRET.S
index 5484400..2b0c730 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INTERPRET.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INTERPRET.S
@@ -3,17 +3,17 @@
* any lookups. It may be called either as part of a normal chaining
* operation, or from the transition code in header.S. We distinquish
* the two cases by looking at the link register. If called from a
- * translation chain, it will point to the chaining Dalvik PC + 1.
+ * translation chain, it will point to the chaining Dalvik PC -3.
* On entry:
* lr - if NULL:
* r1 - the Dalvik PC to begin interpretation.
* else
- * [lr, #-1] contains Dalvik PC to begin interpretation
+ * [lr, #3] contains Dalvik PC to begin interpretation
* rGLUE - pointer to interpState
* rFP - Dalvik frame pointer
*/
cmp lr, #0
- ldrne r1,[lr, #-1]
+ ldrne r1,[lr, #3]
ldr r2, .LinterpPunt
mov r0, r1 @ set Dalvik PC
bx r2
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
index d6e6763..a137d22 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
@@ -18,7 +18,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt r12 @ return to raise stack overflow excep.
+ bxlo r12 @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
@@ -43,5 +43,3 @@
str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
bx lr @ return to the callee-chaining cell
-
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
index 0dbd6c0..2557863 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
@@ -8,7 +8,7 @@
SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
ldr r8, [r8] @ r3<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
@@ -64,10 +64,7 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
-
-
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
index facce51..5be6978 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
@@ -15,7 +15,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
ldr r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
@@ -48,7 +48,7 @@
str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
@ Start executing the callee
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
index 9ee49a8..c3085b9 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
@@ -25,12 +25,20 @@
ldr r3, [r0, #offObject_clazz] @ r3 <- this->class
ldr r8, [r2, #4] @ r8 <- predictedChainCell->clazz
ldr r0, [r2, #8] @ r0 <- predictedChainCell->method
- ldr r9, [r2, #12] @ r9 <- predictedChainCell->counter
+ ldr r9, [rGLUE, #offGlue_icRechainCount] @ r1 <- shared rechainCount
cmp r3, r8 @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+ ldr r7, .LdvmICHitCount
+ ldreq r10, [r7, #0]
+ add r10, r10, #1
+ streq r10, [r7, #0]
+#endif
beq .LinvokeChain @ predicted chain is valid
ldr r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
- sub r1, r9, #1 @ count--
- str r1, [r2, #12] @ write back to PredictedChainingCell->counter
+ cmp r8, #0 @ initialized class or not
+ moveq r1, #0
+ subne r1, r9, #1 @ count--
+ strne r1, [rGLUE, #offGlue_icRechainCount] @ write back to InterpState
add lr, lr, #4 @ return to fully-resolve landing pad
/*
* r1 <- count
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S
index b1ab44e..8e7f728 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S
@@ -19,8 +19,7 @@
ldr r2, .LdvmJitToInterpNoChain
str r0, [rGLUE, #offGlue_pJitProfTable]
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
bx r2
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S
index 6acf992..5cf26e7 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S
@@ -26,7 +26,7 @@
bx r2
1:
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
ldr pc, .LdvmJitToInterpNoChain
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
index 502c493..b7ab971 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
@@ -23,7 +23,7 @@
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -38,7 +38,7 @@
str r9, [r3, #offThread_inJitCodeCache] @ in code cache or not
cmp r9, #0 @ chaining cell exists?
blxne r9 @ jump to the chaining cell
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1 @ callsite is interpreted
diff --git a/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S
index ca7545a..c737840 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S
@@ -13,4 +13,3 @@
movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S
index 75b6a90..54bde47 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S
@@ -131,4 +131,3 @@
.Lmemcmp16:
.word __memcmp16
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S
index 84c4880..bdfdf28 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S
@@ -110,4 +110,3 @@
sub r0, r7
asr r0, r0, #1
bx lr
-
diff --git a/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S
index d7c71d9..8a48df2 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S
@@ -13,4 +13,3 @@
movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
index b93eee3..73fc3d7 100644
--- a/vm/compiler/template/armv5te/footer.S
+++ b/vm/compiler/template/armv5te/footer.S
@@ -50,7 +50,7 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
@@ -76,6 +76,8 @@
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -86,6 +88,10 @@
.word dvmMterpCommonExceptionThrown
.LdvmLockObject:
.word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
#if defined(WITH_SELF_VERIFICATION)
.LdvmSelfVerificationMemOpDecode:
.word dvmSelfVerificationMemOpDecode
diff --git a/vm/compiler/template/armv5te/header.S b/vm/compiler/template/armv5te/header.S
index c257105..e6b3362 100644
--- a/vm/compiler/template/armv5te/header.S
+++ b/vm/compiler/template/armv5te/header.S
@@ -93,4 +93,3 @@
* to expand the macros into assembler assignment statements.
*/
#include "../../../mterp/common/asm-constants.h"
-
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index d8a2784..60664fa 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -101,7 +101,6 @@
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te-vfp/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -212,7 +210,7 @@
str r9, [r3, #offThread_inJitCodeCache] @ in code cache or not
cmp r9, #0 @ chaining cell exists?
blxne r9 @ jump to the chaining cell
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1 @ callsite is interpreted
@@ -245,7 +243,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
ldr r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
@@ -278,7 +276,7 @@
str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
@ Start executing the callee
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
@@ -308,7 +306,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt r12 @ return to raise stack overflow excep.
+ bxlo r12 @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
@@ -334,8 +332,6 @@
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -368,12 +364,20 @@
ldr r3, [r0, #offObject_clazz] @ r3 <- this->class
ldr r8, [r2, #4] @ r8 <- predictedChainCell->clazz
ldr r0, [r2, #8] @ r0 <- predictedChainCell->method
- ldr r9, [r2, #12] @ r9 <- predictedChainCell->counter
+ ldr r9, [rGLUE, #offGlue_icRechainCount] @ r1 <- shared rechainCount
cmp r3, r8 @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+ ldr r7, .LdvmICHitCount
+ ldreq r10, [r7, #0]
+ add r10, r10, #1
+ streq r10, [r7, #0]
+#endif
beq .LinvokeChain @ predicted chain is valid
ldr r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
- sub r1, r9, #1 @ count--
- str r1, [r2, #12] @ write back to PredictedChainingCell->counter
+ cmp r8, #0 @ initialized class or not
+ moveq r1, #0
+ subne r1, r9, #1 @ count--
+ strne r1, [rGLUE, #offGlue_icRechainCount] @ write back to InterpState
add lr, lr, #4 @ return to fully-resolve landing pad
/*
* r1 <- count
@@ -399,7 +403,7 @@
SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
ldr r8, [r8] @ r3<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
@@ -455,14 +459,11 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -539,7 +540,6 @@
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -561,7 +561,6 @@
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -911,7 +910,6 @@
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1218,7 +1216,6 @@
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1337,7 +1334,6 @@
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1348,17 +1344,17 @@
* any lookups. It may be called either as part of a normal chaining
* operation, or from the transition code in header.S. We distinquish
* the two cases by looking at the link register. If called from a
- * translation chain, it will point to the chaining Dalvik PC + 1.
+ * translation chain, it will point to the chaining Dalvik PC -3.
* On entry:
* lr - if NULL:
* r1 - the Dalvik PC to begin interpretation.
* else
- * [lr, #-1] contains Dalvik PC to begin interpretation
+ * [lr, #3] contains Dalvik PC to begin interpretation
* rGLUE - pointer to interpState
* rFP - Dalvik frame pointer
*/
cmp lr, #0
- ldrne r1,[lr, #-1]
+ ldrne r1,[lr, #3]
ldr r2, .LinterpPunt
mov r0, r1 @ set Dalvik PC
bx r2
@@ -1393,12 +1389,11 @@
ldr r2, .LdvmJitToInterpNoChain
str r0, [rGLUE, #offGlue_pJitProfTable]
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1432,7 +1427,7 @@
bx r2
1:
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
ldr pc, .LdvmJitToInterpNoChain
@@ -1491,7 +1486,7 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
@@ -1517,6 +1512,8 @@
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1527,6 +1524,10 @@
.word dvmMterpCommonExceptionThrown
.LdvmLockObject:
.word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
#if defined(WITH_SELF_VERIFICATION)
.LdvmSelfVerificationMemOpDecode:
.word dvmSelfVerificationMemOpDecode
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index eab49cf..ccdbcca 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -101,7 +101,6 @@
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -212,7 +210,7 @@
str r9, [r3, #offThread_inJitCodeCache] @ in code cache or not
cmp r9, #0 @ chaining cell exists?
blxne r9 @ jump to the chaining cell
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1 @ callsite is interpreted
@@ -245,7 +243,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
ldr r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
@@ -278,7 +276,7 @@
str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
@ Start executing the callee
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
@@ -308,7 +306,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt r12 @ return to raise stack overflow excep.
+ bxlo r12 @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
@@ -334,8 +332,6 @@
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -368,12 +364,20 @@
ldr r3, [r0, #offObject_clazz] @ r3 <- this->class
ldr r8, [r2, #4] @ r8 <- predictedChainCell->clazz
ldr r0, [r2, #8] @ r0 <- predictedChainCell->method
- ldr r9, [r2, #12] @ r9 <- predictedChainCell->counter
+ ldr r9, [rGLUE, #offGlue_icRechainCount] @ r1 <- shared rechainCount
cmp r3, r8 @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+ ldr r7, .LdvmICHitCount
+ ldreq r10, [r7, #0]
+ add r10, r10, #1
+ streq r10, [r7, #0]
+#endif
beq .LinvokeChain @ predicted chain is valid
ldr r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
- sub r1, r9, #1 @ count--
- str r1, [r2, #12] @ write back to PredictedChainingCell->counter
+ cmp r8, #0 @ initialized class or not
+ moveq r1, #0
+ subne r1, r9, #1 @ count--
+ strne r1, [rGLUE, #offGlue_icRechainCount] @ write back to InterpState
add lr, lr, #4 @ return to fully-resolve landing pad
/*
* r1 <- count
@@ -399,7 +403,7 @@
SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
ldr r8, [r8] @ r3<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
@@ -455,14 +459,11 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPG_DOUBLE
@@ -506,7 +507,6 @@
bx r11
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE
@@ -548,7 +548,6 @@
mvn r0, #0 @ r1<- 1 or -1 for NaN
bx r11
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPG_FLOAT
@@ -610,8 +609,6 @@
bx r11
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_FLOAT
@@ -671,8 +668,6 @@
mvn r0, #0 @ r1<- 1 or -1 for NaN
bx r11
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -749,7 +744,6 @@
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -771,7 +765,6 @@
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
@@ -946,7 +939,6 @@
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1065,7 +1057,6 @@
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1076,17 +1067,17 @@
* any lookups. It may be called either as part of a normal chaining
* operation, or from the transition code in header.S. We distinquish
* the two cases by looking at the link register. If called from a
- * translation chain, it will point to the chaining Dalvik PC + 1.
+ * translation chain, it will point to the chaining Dalvik PC -3.
* On entry:
* lr - if NULL:
* r1 - the Dalvik PC to begin interpretation.
* else
- * [lr, #-1] contains Dalvik PC to begin interpretation
+ * [lr, #3] contains Dalvik PC to begin interpretation
* rGLUE - pointer to interpState
* rFP - Dalvik frame pointer
*/
cmp lr, #0
- ldrne r1,[lr, #-1]
+ ldrne r1,[lr, #3]
ldr r2, .LinterpPunt
mov r0, r1 @ set Dalvik PC
bx r2
@@ -1121,12 +1112,11 @@
ldr r2, .LdvmJitToInterpNoChain
str r0, [rGLUE, #offGlue_pJitProfTable]
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1160,7 +1150,7 @@
bx r2
1:
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
ldr pc, .LdvmJitToInterpNoChain
@@ -1219,7 +1209,7 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
@@ -1245,6 +1235,8 @@
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1255,6 +1247,10 @@
.word dvmMterpCommonExceptionThrown
.LdvmLockObject:
.word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
#if defined(WITH_SELF_VERIFICATION)
.LdvmSelfVerificationMemOpDecode:
.word dvmSelfVerificationMemOpDecode
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
index cb00858..e520056 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
@@ -101,7 +101,6 @@
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te-vfp/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -212,7 +210,7 @@
str r9, [r3, #offThread_inJitCodeCache] @ in code cache or not
cmp r9, #0 @ chaining cell exists?
blxne r9 @ jump to the chaining cell
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1 @ callsite is interpreted
@@ -245,7 +243,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
ldr r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
@@ -278,7 +276,7 @@
str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
@ Start executing the callee
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
@@ -308,7 +306,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt r12 @ return to raise stack overflow excep.
+ bxlo r12 @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
@@ -334,8 +332,6 @@
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -368,12 +364,20 @@
ldr r3, [r0, #offObject_clazz] @ r3 <- this->class
ldr r8, [r2, #4] @ r8 <- predictedChainCell->clazz
ldr r0, [r2, #8] @ r0 <- predictedChainCell->method
- ldr r9, [r2, #12] @ r9 <- predictedChainCell->counter
+ ldr r9, [rGLUE, #offGlue_icRechainCount] @ r1 <- shared rechainCount
cmp r3, r8 @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+ ldr r7, .LdvmICHitCount
+ ldreq r10, [r7, #0]
+ add r10, r10, #1
+ streq r10, [r7, #0]
+#endif
beq .LinvokeChain @ predicted chain is valid
ldr r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
- sub r1, r9, #1 @ count--
- str r1, [r2, #12] @ write back to PredictedChainingCell->counter
+ cmp r8, #0 @ initialized class or not
+ moveq r1, #0
+ subne r1, r9, #1 @ count--
+ strne r1, [rGLUE, #offGlue_icRechainCount] @ write back to InterpState
add lr, lr, #4 @ return to fully-resolve landing pad
/*
* r1 <- count
@@ -399,7 +403,7 @@
SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
ldr r8, [r8] @ r3<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
@@ -455,14 +459,11 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -539,7 +540,6 @@
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -561,7 +561,6 @@
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -911,7 +910,6 @@
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1218,7 +1216,6 @@
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1337,7 +1334,6 @@
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1348,17 +1344,17 @@
* any lookups. It may be called either as part of a normal chaining
* operation, or from the transition code in header.S. We distinquish
* the two cases by looking at the link register. If called from a
- * translation chain, it will point to the chaining Dalvik PC + 1.
+ * translation chain, it will point to the chaining Dalvik PC -3.
* On entry:
* lr - if NULL:
* r1 - the Dalvik PC to begin interpretation.
* else
- * [lr, #-1] contains Dalvik PC to begin interpretation
+ * [lr, #3] contains Dalvik PC to begin interpretation
* rGLUE - pointer to interpState
* rFP - Dalvik frame pointer
*/
cmp lr, #0
- ldrne r1,[lr, #-1]
+ ldrne r1,[lr, #3]
ldr r2, .LinterpPunt
mov r0, r1 @ set Dalvik PC
bx r2
@@ -1393,12 +1389,11 @@
ldr r2, .LdvmJitToInterpNoChain
str r0, [rGLUE, #offGlue_pJitProfTable]
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1432,7 +1427,7 @@
bx r2
1:
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
ldr pc, .LdvmJitToInterpNoChain
@@ -1491,7 +1486,7 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
@@ -1517,6 +1512,8 @@
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1527,6 +1524,10 @@
.word dvmMterpCommonExceptionThrown
.LdvmLockObject:
.word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
#if defined(WITH_SELF_VERIFICATION)
.LdvmSelfVerificationMemOpDecode:
.word dvmSelfVerificationMemOpDecode
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index cf6fff9..87a0691 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -101,7 +101,6 @@
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te-vfp/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -212,7 +210,7 @@
str r9, [r3, #offThread_inJitCodeCache] @ in code cache or not
cmp r9, #0 @ chaining cell exists?
blxne r9 @ jump to the chaining cell
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1 @ callsite is interpreted
@@ -245,7 +243,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
ldr r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
@@ -278,7 +276,7 @@
str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
@ Start executing the callee
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
@@ -308,7 +306,7 @@
sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
ldr r8, [r8] @ r8<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt r12 @ return to raise stack overflow excep.
+ bxlo r12 @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
ldr r9, [r0, #offMethod_clazz] @ r9<- method->clazz
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
@@ -334,8 +332,6 @@
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -368,12 +364,20 @@
ldr r3, [r0, #offObject_clazz] @ r3 <- this->class
ldr r8, [r2, #4] @ r8 <- predictedChainCell->clazz
ldr r0, [r2, #8] @ r0 <- predictedChainCell->method
- ldr r9, [r2, #12] @ r9 <- predictedChainCell->counter
+ ldr r9, [rGLUE, #offGlue_icRechainCount] @ r1 <- shared rechainCount
cmp r3, r8 @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+ ldr r7, .LdvmICHitCount
+ ldreq r10, [r7, #0]
+ add r10, r10, #1
+ streq r10, [r7, #0]
+#endif
beq .LinvokeChain @ predicted chain is valid
ldr r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
- sub r1, r9, #1 @ count--
- str r1, [r2, #12] @ write back to PredictedChainingCell->counter
+ cmp r8, #0 @ initialized class or not
+ moveq r1, #0
+ subne r1, r9, #1 @ count--
+ strne r1, [rGLUE, #offGlue_icRechainCount] @ write back to InterpState
add lr, lr, #4 @ return to fully-resolve landing pad
/*
* r1 <- count
@@ -399,7 +403,7 @@
SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
ldr r8, [r8] @ r3<- suspendCount (int)
cmp r10, r9 @ bottom < interpStackEnd?
- bxlt lr @ return to raise stack overflow excep.
+ bxlo lr @ return to raise stack overflow excep.
@ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
@@ -455,14 +459,11 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -539,7 +540,6 @@
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -561,7 +561,6 @@
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -911,7 +910,6 @@
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1218,7 +1216,6 @@
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1337,7 +1334,6 @@
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1348,17 +1344,17 @@
* any lookups. It may be called either as part of a normal chaining
* operation, or from the transition code in header.S. We distinquish
* the two cases by looking at the link register. If called from a
- * translation chain, it will point to the chaining Dalvik PC + 1.
+ * translation chain, it will point to the chaining Dalvik PC -3.
* On entry:
* lr - if NULL:
* r1 - the Dalvik PC to begin interpretation.
* else
- * [lr, #-1] contains Dalvik PC to begin interpretation
+ * [lr, #3] contains Dalvik PC to begin interpretation
* rGLUE - pointer to interpState
* rFP - Dalvik frame pointer
*/
cmp lr, #0
- ldrne r1,[lr, #-1]
+ ldrne r1,[lr, #3]
ldr r2, .LinterpPunt
mov r0, r1 @ set Dalvik PC
bx r2
@@ -1393,12 +1389,11 @@
ldr r2, .LdvmJitToInterpNoChain
str r0, [rGLUE, #offGlue_pJitProfTable]
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1432,7 +1427,7 @@
bx r2
1:
@ Bail to interpreter - no chain [note - r4 still contains rPC]
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kHeavyweightMonitor
#endif
ldr pc, .LdvmJitToInterpNoChain
@@ -1491,7 +1486,7 @@
@ continue executing the next instruction through the interpreter
ldr r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
add rPC, r0, #6 @ reconstruct new rPC (advance 6 bytes)
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
mov pc, r1
@@ -1517,6 +1512,8 @@
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1527,6 +1524,10 @@
.word dvmMterpCommonExceptionThrown
.LdvmLockObject:
.word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
#if defined(WITH_SELF_VERIFICATION)
.LdvmSelfVerificationMemOpDecode:
.word dvmSelfVerificationMemOpDecode
diff --git a/vm/compiler/template/rebuild.sh b/vm/compiler/template/rebuild.sh
index 78ff84f..8c47dd7 100755
--- a/vm/compiler/template/rebuild.sh
+++ b/vm/compiler/template/rebuild.sh
@@ -20,4 +20,3 @@
#
set -e
for arch in armv5te armv5te-vfp armv7-a armv7-a-neon; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
-
diff --git a/vm/hprof/Hprof.c b/vm/hprof/Hprof.c
index 8380fd8..bcad8b1 100644
--- a/vm/hprof/Hprof.c
+++ b/vm/hprof/Hprof.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
@@ -33,35 +34,8 @@
#define kHeadSuffix "-hptemp"
hprof_context_t *
-hprofStartup(const char *outputFileName, bool directToDdms)
+hprofStartup(const char *outputFileName, int fd, bool directToDdms)
{
- FILE* fp = NULL;
-
- if (!directToDdms) {
- int len = strlen(outputFileName);
- char fileName[len + sizeof(kHeadSuffix)];
-
- /* Construct the temp file name. This wasn't handed to us by the
- * application, so we need to be careful about stomping on it.
- */
- sprintf(fileName, "%s" kHeadSuffix, outputFileName);
- if (access(fileName, F_OK) == 0) {
- LOGE("hprof: temp file %s exists, bailing\n", fileName);
- return NULL;
- }
-
- fp = fopen(fileName, "w+");
- if (fp == NULL) {
- LOGE("hprof: can't open %s: %s.\n", fileName, strerror(errno));
- return NULL;
- }
- if (unlink(fileName) != 0) {
- LOGW("hprof: WARNING: unable to remove temp file %s\n", fileName);
- /* keep going */
- }
- LOGI("hprof: dumping VM heap to \"%s\".\n", fileName);
- }
-
hprofStartup_String();
hprofStartup_Class();
#if WITH_HPROF_STACK
@@ -72,70 +46,26 @@
hprof_context_t *ctx = malloc(sizeof(*ctx));
if (ctx == NULL) {
LOGE("hprof: can't allocate context.\n");
- if (fp != NULL)
- fclose(fp);
return NULL;
}
- /* pass in "fp" for the temp file, and the name of the output file */
- hprofContextInit(ctx, strdup(outputFileName), fp, false, directToDdms);
+ /* pass in name or descriptor of the output file */
+ hprofContextInit(ctx, strdup(outputFileName), fd, false, directToDdms);
- assert(ctx->fp != NULL);
+ assert(ctx->memFp != NULL);
return ctx;
}
/*
- * Copy the entire contents of "srcFp" to "dstFp".
- *
- * Returns "true" on success.
- */
-static bool
-copyFileToFile(FILE *dstFp, FILE *srcFp)
-{
- char buf[65536];
- size_t dataRead, dataWritten;
-
- while (true) {
- dataRead = fread(buf, 1, sizeof(buf), srcFp);
- if (dataRead > 0) {
- dataWritten = fwrite(buf, 1, dataRead, dstFp);
- if (dataWritten != dataRead) {
- LOGE("hprof: failed writing data (%d of %d): %s\n",
- dataWritten, dataRead, strerror(errno));
- return false;
- }
- } else {
- if (feof(srcFp))
- return true;
- LOGE("hprof: failed reading data (res=%d): %s\n",
- dataRead, strerror(errno));
- return false;
- }
- }
-}
-
-/*
* Finish up the hprof dump. Returns true on success.
*/
bool
hprofShutdown(hprof_context_t *tailCtx)
{
- FILE *fp = NULL;
-
- /* flush output to the temp file, then prepare the output file */
+ /* flush the "tail" portion of the output */
hprofFlushCurrentRecord(tailCtx);
- LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName);
- if (!tailCtx->directToDdms) {
- fp = fopen(tailCtx->fileName, "w");
- if (fp == NULL) {
- LOGE("can't open %s: %s\n", tailCtx->fileName, strerror(errno));
- hprofFreeContext(tailCtx);
- return false;
- }
- }
-
/*
* Create a new context struct for the start of the file. We
* heap-allocate it so we can share the "free" function.
@@ -143,14 +73,13 @@
hprof_context_t *headCtx = malloc(sizeof(*headCtx));
if (headCtx == NULL) {
LOGE("hprof: can't allocate context.\n");
- if (fp != NULL)
- fclose(fp);
hprofFreeContext(tailCtx);
- return NULL;
+ return false;
}
- hprofContextInit(headCtx, strdup(tailCtx->fileName), fp, true,
+ hprofContextInit(headCtx, strdup(tailCtx->fileName), tailCtx->fd, true,
tailCtx->directToDdms);
+ LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName);
hprofDumpStrings(headCtx);
hprofDumpClasses(headCtx);
@@ -176,11 +105,11 @@
hprofShutdown_StackFrame();
#endif
- if (tailCtx->directToDdms) {
- /* flush to ensure memstream pointer and size are updated */
- fflush(headCtx->fp);
- fflush(tailCtx->fp);
+ /* flush to ensure memstream pointer and size are updated */
+ fflush(headCtx->memFp);
+ fflush(tailCtx->memFp);
+ if (tailCtx->directToDdms) {
/* send the data off to DDMS */
struct iovec iov[2];
iov[0].iov_base = headCtx->fileDataPtr;
@@ -190,22 +119,50 @@
dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
} else {
/*
- * Append the contents of the temp file to the output file. The temp
- * file was removed immediately after being opened, so it will vanish
- * when we close it.
+ * Open the output file, and copy the head and tail to it.
*/
- rewind(tailCtx->fp);
- if (!copyFileToFile(headCtx->fp, tailCtx->fp)) {
- LOGW("hprof: file copy failed, hprof data may be incomplete\n");
- /* finish up anyway */
+ assert(headCtx->fd == tailCtx->fd);
+
+ int outFd;
+ if (headCtx->fd >= 0) {
+ outFd = dup(headCtx->fd);
+ if (outFd < 0) {
+ LOGE("dup(%d) failed: %s\n", headCtx->fd, strerror(errno));
+ /* continue to fail-handler below */
+ }
+ } else {
+ outFd = open(tailCtx->fileName, O_WRONLY|O_CREAT, 0644);
+ if (outFd < 0) {
+ LOGE("can't open %s: %s\n", headCtx->fileName, strerror(errno));
+ /* continue to fail-handler below */
+ }
+ }
+ if (outFd < 0) {
+ hprofFreeContext(headCtx);
+ hprofFreeContext(tailCtx);
+ return false;
+ }
+
+ int result;
+ result = sysWriteFully(outFd, headCtx->fileDataPtr,
+ headCtx->fileDataSize, "hprof-head");
+ result |= sysWriteFully(outFd, tailCtx->fileDataPtr,
+ tailCtx->fileDataSize, "hprof-tail");
+ close(outFd);
+ if (result != 0) {
+ hprofFreeContext(headCtx);
+ hprofFreeContext(tailCtx);
+ return false;
}
}
+ /* throw out a log message for the benefit of "runhat" */
+ LOGI("hprof: heap dump completed (%dKB)\n",
+ (headCtx->fileDataSize + tailCtx->fileDataSize + 1023) / 1024);
+
hprofFreeContext(headCtx);
hprofFreeContext(tailCtx);
- /* throw out a log message for the benefit of "runhat" */
- LOGI("hprof: heap dump completed, temp file removed\n");
return true;
}
@@ -217,11 +174,12 @@
{
assert(ctx != NULL);
- if (ctx->fp != NULL)
- fclose(ctx->fp);
+ /* we don't own ctx->fd, do not close */
+
+ if (ctx->memFp != NULL)
+ fclose(ctx->memFp);
free(ctx->curRec.body);
free(ctx->fileName);
free(ctx->fileDataPtr);
free(ctx);
}
-
diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h
index db5049f..18f4102 100644
--- a/vm/hprof/Hprof.h
+++ b/vm/hprof/Hprof.h
@@ -92,7 +92,7 @@
HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,
HPROF_ROOT_VM_INTERNAL = 0x8d,
HPROF_ROOT_JNI_MONITOR = 0x8e,
- HPROF_UNREACHABLE = 0x90,
+ HPROF_UNREACHABLE = 0x90, /* deprecated */
HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
} hprof_heap_tag_t;
@@ -133,15 +133,16 @@
size_t objectsInSegment;
/*
- * If "directToDdms" is not set, "fileName" is valid, and "fileDataPtr"
- * and "fileDataSize" are not used. If "directToDdms" is not set,
- * it's the other way around.
+ * If directToDdms is set, "fileName" and "fd" will be ignored.
+ * Otherwise, "fileName" must be valid, though if "fd" >= 0 it will
+ * only be used for debug messages.
*/
bool directToDdms;
char *fileName;
char *fileDataPtr; // for open_memstream
size_t fileDataSize; // for open_memstream
- FILE *fp;
+ FILE *memFp;
+ int fd;
} hprof_context_t;
@@ -187,7 +188,7 @@
* HprofOutput.c functions
*/
-void hprofContextInit(hprof_context_t *ctx, char *fileName, FILE *fp,
+void hprofContextInit(hprof_context_t *ctx, char *fileName, int fd,
bool writeHeader, bool directToDdms);
int hprofFlushRecord(hprof_record_t *rec, FILE *fp);
@@ -244,7 +245,8 @@
* Hprof.c functions
*/
-hprof_context_t* hprofStartup(const char *outputFileName, bool directToDdms);
+hprof_context_t* hprofStartup(const char *outputFileName, int fd,
+ bool directToDdms);
bool hprofShutdown(hprof_context_t *ctx);
void hprofFreeContext(hprof_context_t *ctx);
@@ -255,7 +257,7 @@
* the heap implementation; these functions require heap knowledge,
* so they are implemented in Heap.c.
*/
-int hprofDumpHeap(const char* fileName, bool directToDdms);
+int hprofDumpHeap(const char* fileName, int fd, bool directToDdms);
void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber);
#endif // _DALVIK_HPROF_HPROF
diff --git a/vm/hprof/HprofClass.c b/vm/hprof/HprofClass.c
index 5043beb..f76f159 100644
--- a/vm/hprof/HprofClass.c
+++ b/vm/hprof/HprofClass.c
@@ -74,7 +74,7 @@
{
hprof_string_id classNameId;
char *dotName = dvmDescriptorToDot(descriptor);
-
+
/* Hprof suggests that array class names be converted from, e.g.,
* "[[[I" to "int[][][]" and "[Lorg.blort.Spaz;" to
* "org.blort.Spaz[]".
@@ -205,7 +205,7 @@
* ID: class object ID
* u4: stack trace serial number
* ID: class name string ID
- *
+ *
* We use the address of the class object structure as its ID.
*/
hprofAddU4ToRecord(rec, clazz->serialNumber);
diff --git a/vm/hprof/HprofHeap.c b/vm/hprof/HprofHeap.c
index a69e3c6..75a1d2b 100644
--- a/vm/hprof/HprofHeap.c
+++ b/vm/hprof/HprofHeap.c
@@ -30,6 +30,15 @@
#define OBJECTS_PER_SEGMENT ((size_t)128)
#define BYTES_PER_SEGMENT ((size_t)4096)
+/* The static field-name for the synthetic object generated to account
+ * for class Static overhead.
+ */
+#define STATIC_OVERHEAD_NAME "$staticOverhead"
+/* The ID for the synthetic object generated to account for class
+ * Static overhead.
+ */
+#define CLASS_STATICS_ID(clazz) ((hprof_object_id)(((u4)(clazz)) | 1))
+
int
hprofStartHeapDump(hprof_context_t *ctx)
{
@@ -146,7 +155,6 @@
case HPROF_ROOT_DEBUGGER:
case HPROF_ROOT_REFERENCE_CLEANUP:
case HPROF_ROOT_VM_INTERNAL:
- case HPROF_UNREACHABLE:
hprofAddU1ToRecord(rec, heapTag);
hprofAddIdToRecord(rec, (hprof_object_id)obj);
break;
@@ -223,10 +231,10 @@
hprof_record_t *rec = &ctx->curRec;
HprofHeapId desiredHeap;
- desiredHeap =
- dvmHeapSourceGetPtrFlag(ptr2chunk(obj), HS_ALLOCATED_IN_ZYGOTE) ?
+ desiredHeap =
+ dvmHeapSourceGetPtrFlag(obj, HS_ALLOCATED_IN_ZYGOTE) ?
HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP;
-
+
if (ctx->objectsInSegment >= OBJECTS_PER_SEGMENT ||
rec->length >= BYTES_PER_SEGMENT)
{
@@ -268,34 +276,11 @@
clazz = obj->clazz;
if (clazz == NULL) {
- /* This object was probably just allocated and hasn't been
- * initialized yet. Add an instance entry to make a note of
- * it; there's not much else that we can do.
+ /* This object will bother HprofReader, because it has a NULL
+ * class, so just don't dump it. It could be
+ * gDvm.unlinkedJavaLangClass or it could be an object just
+ * allocated which hasn't been initialized yet.
*/
- hprofAddU1ToRecord(rec, HPROF_INSTANCE_DUMP);
-
- hprofAddIdToRecord(rec, (hprof_object_id)obj);
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
- hprofAddIdToRecord(rec, (hprof_class_object_id)clazz); // NULL
- hprofAddIdToRecord(rec, 0); // no instance data
- } else if (clazz == gDvm.unlinkedJavaLangClass) {
- /* obj is a ClassObject that hasn't been linked yet.
- */
- hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
-
- //TODO: use hprofLookupClassId() for this:
- hprofAddIdToRecord(rec, (hprof_class_object_id)obj);
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
- hprofAddIdToRecord(rec, (hprof_class_object_id)0); // no super class
- hprofAddIdToRecord(rec, (hprof_object_id)0); // no class loader
- hprofAddIdToRecord(rec, (hprof_object_id)0); // no signer
- hprofAddIdToRecord(rec, (hprof_object_id)0); // no prot domain
- hprofAddIdToRecord(rec, (hprof_id)0); // reserved
- hprofAddIdToRecord(rec, (hprof_id)0); // reserved
- hprofAddU4ToRecord(rec, 0); // zero instance size
- hprofAddU2ToRecord(rec, 0); // empty const pool
- hprofAddU2ToRecord(rec, 0); // no statics
- hprofAddU2ToRecord(rec, 0); // no instance fields
} else {
hprof_class_object_id clazzId;
@@ -303,11 +288,26 @@
if (clazz == gDvm.classJavaLangClass) {
const ClassObject *thisClass = (const ClassObject *)obj;
- int i, n;
+ int i, sFieldCount, iFieldCount;
/* obj is a ClassObject.
*/
- hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
+ sFieldCount = thisClass->sfieldCount;
+ if (sFieldCount != 0) {
+ int byteLength = sFieldCount*sizeof(StaticField);
+ /* Create a byte array to reflect the allocation of the
+ * StaticField array at the end of this class.
+ */
+ hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
+ hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+ hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+ hprofAddU4ToRecord(rec, byteLength);
+ hprofAddU1ToRecord(rec, hprof_basic_byte);
+ for (i = 0; i < byteLength; i++) {
+ hprofAddU1ToRecord(rec, 0);
+ }
+ }
+ hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
hprofAddIdToRecord(rec, hprofLookupClassId(thisClass));
hprofAddU4ToRecord(rec, stackTraceSerialNumber(thisClass));
hprofAddIdToRecord(rec, hprofLookupClassId(thisClass->super));
@@ -317,6 +317,9 @@
hprofAddIdToRecord(rec, (hprof_id)0); // reserved
hprofAddIdToRecord(rec, (hprof_id)0); // reserved
if (obj == (Object *)gDvm.classJavaLangClass) {
+ // ClassObjects have their static fields appended, so
+ // aren't all the same size. But they're at least this
+ // size.
hprofAddU4ToRecord(rec, sizeof(ClassObject)); // instance size
} else {
hprofAddU4ToRecord(rec, thisClass->objectSize); // instance size
@@ -326,34 +329,41 @@
/* Static fields
*/
- n = thisClass->sfieldCount;
- hprofAddU2ToRecord(rec, (u2)n);
- for (i = 0; i < n; i++) {
- const StaticField *f = &thisClass->sfields[i];
- hprof_basic_type t;
- size_t size;
+ if (sFieldCount == 0) {
+ hprofAddU2ToRecord(rec, (u2)0);
+ } else {
+ hprofAddU2ToRecord(rec, (u2)(sFieldCount+1));
+ hprofAddIdToRecord(rec,
+ hprofLookupStringId(STATIC_OVERHEAD_NAME));
+ hprofAddU1ToRecord(rec, hprof_basic_object);
+ hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+ for (i = 0; i < sFieldCount; i++) {
+ hprof_basic_type t;
+ size_t size;
+ const StaticField *f = &thisClass->sfields[i];
- t = signatureToBasicTypeAndSize(f->field.signature, &size);
- hprofAddIdToRecord(rec, hprofLookupStringId(f->field.name));
- hprofAddU1ToRecord(rec, t);
- if (size == 1) {
- hprofAddU1ToRecord(rec, (u1)f->value.b);
- } else if (size == 2) {
- hprofAddU2ToRecord(rec, (u2)f->value.c);
- } else if (size == 4) {
- hprofAddU4ToRecord(rec, (u4)f->value.i);
- } else if (size == 8) {
- hprofAddU8ToRecord(rec, (u8)f->value.j);
- } else {
- assert(false);
+ t = signatureToBasicTypeAndSize(f->field.signature, &size);
+ hprofAddIdToRecord(rec, hprofLookupStringId(f->field.name));
+ hprofAddU1ToRecord(rec, t);
+ if (size == 1) {
+ hprofAddU1ToRecord(rec, (u1)f->value.b);
+ } else if (size == 2) {
+ hprofAddU2ToRecord(rec, (u2)f->value.c);
+ } else if (size == 4) {
+ hprofAddU4ToRecord(rec, (u4)f->value.i);
+ } else if (size == 8) {
+ hprofAddU8ToRecord(rec, (u8)f->value.j);
+ } else {
+ assert(false);
+ }
}
}
/* Instance fields for this class (no superclass fields)
*/
- n = thisClass->ifieldCount;
- hprofAddU2ToRecord(rec, (u2)n);
- for (i = 0; i < n; i++) {
+ iFieldCount = thisClass->ifieldCount;
+ hprofAddU2ToRecord(rec, (u2)iFieldCount);
+ for (i = 0; i < iFieldCount; i++) {
const InstField *f = &thisClass->ifields[i];
hprof_basic_type t;
diff --git a/vm/hprof/HprofOutput.c b/vm/hprof/HprofOutput.c
index 0677c85..25512b2 100644
--- a/vm/hprof/HprofOutput.c
+++ b/vm/hprof/HprofOutput.c
@@ -59,32 +59,30 @@
/*
* Initialize an hprof context struct.
*
- * This will take ownership of "fileName" and "fp".
+ * This will take ownership of "fileName".
*/
void
-hprofContextInit(hprof_context_t *ctx, char *fileName, FILE *fp,
+hprofContextInit(hprof_context_t *ctx, char *fileName, int fd,
bool writeHeader, bool directToDdms)
{
memset(ctx, 0, sizeof (*ctx));
- if (directToDdms) {
- /*
- * Have to do this here, because it must happen after we
- * memset the struct (want to treat fileDataPtr/fileDataSize
- * as read-only while the file is open).
- */
- assert(fp == NULL);
- fp = open_memstream(&ctx->fileDataPtr, &ctx->fileDataSize);
- if (fp == NULL) {
- /* not expected */
- LOGE("hprof: open_memstream failed: %s\n", strerror(errno));
- dvmAbort();
- }
+ /*
+ * Have to do this here, because it must happen after we
+ * memset the struct (want to treat fileDataPtr/fileDataSize
+ * as read-only while the file is open).
+ */
+ FILE* fp = open_memstream(&ctx->fileDataPtr, &ctx->fileDataSize);
+ if (fp == NULL) {
+ /* not expected */
+ LOGE("hprof: open_memstream failed: %s\n", strerror(errno));
+ dvmAbort();
}
ctx->directToDdms = directToDdms;
ctx->fileName = fileName;
- ctx->fp = fp;
+ ctx->memFp = fp;
+ ctx->fd = fd;
ctx->curRec.allocLen = 128;
ctx->curRec.body = malloc(ctx->curRec.allocLen);
@@ -158,7 +156,7 @@
int
hprofFlushCurrentRecord(hprof_context_t *ctx)
{
- return hprofFlushRecord(&ctx->curRec, ctx->fp);
+ return hprofFlushRecord(&ctx->curRec, ctx->memFp);
}
int
@@ -167,7 +165,7 @@
hprof_record_t *rec = &ctx->curRec;
int err;
- err = hprofFlushRecord(rec, ctx->fp);
+ err = hprofFlushRecord(rec, ctx->memFp);
if (err != 0) {
return err;
} else if (rec->dirty) {
diff --git a/vm/hprof/HprofStack.c b/vm/hprof/HprofStack.c
index 241e01e..04641ef 100644
--- a/vm/hprof/HprofStack.c
+++ b/vm/hprof/HprofStack.c
@@ -171,7 +171,7 @@
int i;
hprofStartNewRecord(ctx, HPROF_TAG_STACK_TRACE, HPROF_TIME);
-
+
stackTraceEntry = (const StackTraceEntry *) dvmHashIterData(&iter);
assert(stackTraceEntry != NULL);
@@ -184,7 +184,7 @@
*/
hprofAddU4ToRecord(rec, stackTraceEntry->trace.serialNumber);
hprofAddU4ToRecord(rec, stackTraceEntry->trace.threadSerialNumber);
-
+
count = 0;
while ((count < STACK_DEPTH) &&
(stackTraceEntry->trace.frameIds[count] != 0)) {
@@ -210,7 +210,7 @@
Thread* self;
void* fp;
int i;
-
+
if (objectPtr == NULL) {
return;
}
diff --git a/vm/hprof/HprofStackFrame.c b/vm/hprof/HprofStackFrame.c
index b1ade43..f9c789e 100644
--- a/vm/hprof/HprofStackFrame.c
+++ b/vm/hprof/HprofStackFrame.c
@@ -66,7 +66,7 @@
descriptor = dexProtoGetMethodDescriptor(&method->prototype, &cache);
hprofLookupStringId(descriptor);
dexStringCacheRelease(&cache);
-
+
const char* sourceFile = dvmGetMethodSourceFile(method);
if (sourceFile) {
hprofLookupStringId(sourceFile);
@@ -76,7 +76,7 @@
hprofLookupClassId(method->clazz);
}
}
-
+
return 0;
}
@@ -114,7 +114,7 @@
u4 hash = 0;
const char *cp = (char *) &stackFrameEntry->frame;
int i;
-
+
for (i = 0; i < (int) sizeof(StackFrame); i++) {
hash = 31 * hash + cp[i];
}
@@ -192,12 +192,12 @@
const char *sourceFile;
ClassObject *clazz;
int lineNum;
-
+
hprofStartNewRecord(ctx, HPROF_TAG_STACK_FRAME, HPROF_TIME);
-
+
stackFrameEntry = (const StackFrameEntry *) dvmHashIterData(&iter);
assert(stackFrameEntry != NULL);
-
+
method = stackFrameEntry->frame.method;
pc = stackFrameEntry->frame.pc;
sourceFile = dvmGetMethodSourceFile(method);
diff --git a/vm/hprof/HprofString.c b/vm/hprof/HprofString.c
index 4e14efb..3f697f5 100644
--- a/vm/hprof/HprofString.c
+++ b/vm/hprof/HprofString.c
@@ -102,7 +102,7 @@
* ID: ID for this string
* [u1]*: UTF8 characters for string (NOT NULL terminated)
* (the record format encodes the length)
- *
+ *
* We use the address of the string data as its ID.
*/
err = hprofAddU4ToRecord(rec, (u4)str);
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index 6ec505d..ab61882 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -127,7 +127,7 @@
{
if (dvmTryLockMutex(&pSet->lock) != 0) {
Thread* self = dvmThreadSelf();
- int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
dvmLockMutex(&pSet->lock);
dvmChangeStatus(self, oldStatus);
}
@@ -261,10 +261,9 @@
* but since we don't execute unverified code we don't need to
* alter the bytecode yet.
*
- * The class init code will "flush" all relevant breakpoints when
- * verification completes.
+ * The class init code will "flush" all pending opcode writes
+ * before verification completes.
*/
- MEM_BARRIER();
assert(*(u1*)addr != OP_BREAKPOINT);
if (dvmIsClassVerified(method->clazz)) {
LOGV("Class %s verified, adding breakpoint at %p\n",
@@ -274,6 +273,7 @@
*addr, method->clazz->descriptor, method->name,
instrOffset);
} else {
+ ANDROID_MEMBAR_FULL();
dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
OP_BREAKPOINT);
}
@@ -282,14 +282,11 @@
method->clazz->descriptor, addr);
}
} else {
+ /*
+ * Breakpoint already exists, just increase the count.
+ */
pBreak = &pSet->breakpoints[idx];
pBreak->setCount++;
-
- /*
- * Instruction stream may not have breakpoint opcode yet -- flush
- * may be pending during verification of class.
- */
- //assert(*(u1*)addr == OP_BREAKPOINT);
}
return true;
@@ -331,7 +328,7 @@
*/
dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
pBreak->originalOpCode);
- MEM_BARRIER();
+ ANDROID_MEMBAR_FULL();
if (idx != pSet->count-1) {
/* shift down */
@@ -369,10 +366,9 @@
LOGV("Flushing breakpoint at %p for %s\n",
pBreak->addr, clazz->descriptor);
if (instructionIsMagicNop(pBreak->addr)) {
- const Method* method = pBreak->method;
LOGV("Refusing to flush breakpoint on %04x at %s.%s + 0x%x\n",
- *pBreak->addr, method->clazz->descriptor,
- method->name, pBreak->addr - method->insns);
+ *pBreak->addr, pBreak->method->clazz->descriptor,
+ pBreak->method->name, pBreak->addr - pBreak->method->insns);
} else {
dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr,
OP_BREAKPOINT);
@@ -710,8 +706,8 @@
break;
}
const char* name = "";
- int j;
#if 0 // "locals" structure has changed -- need to rewrite this
+ int j;
DexFile* pDexFile = method->clazz->pDexFile;
const DexCode* pDexCode = dvmGetMethodCode(method);
int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
@@ -818,7 +814,7 @@
s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
{
const int kInstrLen = 3;
- u2 ident, size;
+ u2 size;
const s4* keys;
const s4* entries;
@@ -950,6 +946,8 @@
dvmThrowException("Ljava/lang/NullPointerException;", NULL);
return false;
}
+ assert (!IS_CLASS_FLAG_SET(((Object *)arrayObj)->clazz,
+ CLASS_ISOBJECTARRAY));
/*
* Array data table format:
@@ -1287,7 +1285,13 @@
#endif
};
- assert(self->inJitCodeCache == NULL);
+ /*
+ * If the previous VM left the code cache through single-stepping the
+ * inJitCodeCache flag will be set when the VM is re-entered (for example,
+ * in self-verification mode we single-step NEW_INSTANCE which may re-enter
+ * the VM through findClassFromLoaderNoInit). Because of that, we cannot
+ * assert that self->inJitCodeCache is NULL here.
+ */
#endif
@@ -1312,6 +1316,8 @@
* false positive is acceptible.
*/
interpState.lastThreshFilter = 0;
+
+ interpState.icRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
#endif
/*
@@ -1377,6 +1383,8 @@
}
}
+ /* Never on the heap, so no write barrier needed. */
+ assert(!dvmIsValidObjectAddress(pResult));
*pResult = interpState.retval;
#if defined(WITH_JIT)
dvmJitCalleeRestore(interpState.calleeSave);
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 826c6d2..6ba9e12 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -91,8 +91,8 @@
/* Number of entries in the 2nd level JIT profiler filter cache */
#define JIT_TRACE_THRESH_FILTER_SIZE 32
-/* Granularity of coverage (power of 2) by each cached entry */
-#define JIT_TRACE_THRESH_FILTER_GRAN_LOG2 6
+/* Number of low dalvik pc address bits to include in 2nd level filter key */
+#define JIT_TRACE_THRESH_FILTER_PC_BITS 4
#endif
/*
@@ -124,12 +124,18 @@
* These are available globally, from gDvm, or from another glue field
* (self/method). They're copied in here for speed.
*/
+ /* copy of self->interpStackEnd */
const u1* interpStackEnd;
+ /* points at self->suspendCount */
volatile int* pSelfSuspendCount;
+ /* Biased base of GC's card table */
+ u1* cardTable;
#if defined(WITH_DEBUGGER)
+ /* points at gDvm.debuggerActive, or NULL if debugger not enabled */
volatile u1* pDebuggerActive;
#endif
#if defined(WITH_PROFILER)
+ /* points at gDvm.activeProfilers */
volatile int* pActiveProfilers;
#endif
/* ----------------------------------------------------------------------
@@ -147,8 +153,8 @@
*/
unsigned char* pJitProfTable;
JitState jitState;
- const void* jitResumeNPC; // Native PC of compiled code
- const u2* jitResumeDPC; // Dalvik PC corresponding to NPC
+ const void* jitResumeNPC; // Native PC of compiled code
+ const u2* jitResumeDPC; // Dalvik PC corresponding to NPC
int jitThreshold;
/*
* ppJitProfTable holds the address of gDvmJit.pJitProfTable, which
@@ -158,6 +164,7 @@
* ppJitProfTable is used for that purpose.
*/
unsigned char** ppJitProfTable; // Used to refresh pJitProfTable
+ int icRechainCount; // Count down to next rechain request
#endif
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index f475773..4129e8a 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -23,7 +23,7 @@
#include "Jit.h"
-#include "dexdump/OpCodeNames.h"
+#include "libdex/OpCodeNames.h"
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
@@ -135,7 +135,7 @@
* Return a pointer to the shadow space for JIT to restore state.
*/
void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
- SelfVerificationState exitPoint)
+ SelfVerificationState exitState)
{
Thread *self = dvmThreadSelf();
ShadowSpace *shadowSpace = self->shadowSpace;
@@ -143,6 +143,7 @@
InterpState *realGlue = shadowSpace->glue;
shadowSpace->endPC = pc;
shadowSpace->endShadowFP = fp;
+ shadowSpace->jitExitState = exitState;
//LOGD("### selfVerificationRestoreState(%d) pc: 0x%x fp: 0x%x endPC: 0x%x",
// self->threadId, (int)shadowSpace->startPC, (int)shadowSpace->fp,
@@ -161,7 +162,7 @@
// Move the resume [ND]PC from the shadow space to the real space so that
// the debug interpreter can return to the translation
- if (exitPoint == kSVSSingleStep) {
+ if (exitState == kSVSSingleStep) {
realGlue->jitResumeNPC = shadowSpace->interpState.jitResumeNPC;
realGlue->jitResumeDPC = shadowSpace->interpState.jitResumeDPC;
} else {
@@ -170,10 +171,10 @@
}
// Special case when punting after a single instruction
- if (exitPoint == kSVSPunt && pc == shadowSpace->startPC) {
+ if (exitState == kSVSPunt && pc == shadowSpace->startPC) {
shadowSpace->selfVerificationState = kSVSIdle;
} else {
- shadowSpace->selfVerificationState = exitPoint;
+ shadowSpace->selfVerificationState = exitState;
}
return shadowSpace;
@@ -235,7 +236,8 @@
offset = (int)((u2*)addr - stackSave->method->insns);
decInsn = &(shadowSpace->trace[i].decInsn);
/* Not properly decoding instruction, some registers may be garbage */
- LOGD("0x%x: (0x%04x) %s", addr, offset, getOpcodeName(decInsn->opCode));
+ LOGD("0x%x: (0x%04x) %s",
+ addr, offset, dexGetOpcodeName(decInsn->opCode));
}
}
@@ -267,7 +269,7 @@
//LOGD("### DbgIntp(%d): PC: 0x%x endPC: 0x%x state: %d len: %d %s",
// self->threadId, (int)pc, (int)shadowSpace->endPC, state,
- // shadowSpace->traceLength, getOpcodeName(decInsn.opCode));
+ // shadowSpace->traceLength, dexGetOpcodeName(decInsn.opCode));
if (state == kSVSIdle || state == kSVSStart) {
LOGD("~~~ DbgIntrp: INCORRECT PREVIOUS STATE(%d): %d",
@@ -404,7 +406,7 @@
gDvmJit.pProfTable = NULL;
}
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
/* Convenience function to increment counter from assembly code */
void dvmBumpNoChain(int from)
{
@@ -439,7 +441,7 @@
if (gDvmJit.pJitEntryTable[i].dPC != 0) {
hit++;
if (gDvmJit.pJitEntryTable[i].codeAddress ==
- gDvmJit.interpretTemplate)
+ dvmCompilerGetInterpretTemplate())
stubs++;
} else
not_hit++;
@@ -452,24 +454,33 @@
hit, not_hit + hit, chains, gDvmJit.threshold,
gDvmJit.blockingMode ? "Blocking" : "Non-blocking");
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
+ LOGD("JIT: Code cache patches: %d", gDvmJit.codeCachePatches);
+
LOGD("JIT: Lookups: %d hits, %d misses; %d normal, %d punt",
gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
gDvmJit.normalExit, gDvmJit.puntExit);
+ LOGD("JIT: ICHits: %d", gDvmICHitCount);
+
LOGD("JIT: noChainExit: %d IC miss, %d interp callsite, "
"%d switch overflow",
gDvmJit.noChainExit[kInlineCacheMiss],
gDvmJit.noChainExit[kCallsiteInterpreted],
gDvmJit.noChainExit[kSwitchOverflow]);
- LOGD("JIT: ICPatch: %d fast, %d queued; %d dropped",
- gDvmJit.icPatchFast, gDvmJit.icPatchQueued,
+ LOGD("JIT: ICPatch: %d init, %d rejected, %d lock-free, %d queued, "
+ "%d dropped",
+ gDvmJit.icPatchInit, gDvmJit.icPatchRejected,
+ gDvmJit.icPatchLockFree, gDvmJit.icPatchQueued,
gDvmJit.icPatchDropped);
LOGD("JIT: Invoke: %d mono, %d poly, %d native, %d return",
gDvmJit.invokeMonomorphic, gDvmJit.invokePolymorphic,
gDvmJit.invokeNative, gDvmJit.returnOp);
+ LOGD("JIT: Inline: %d mgetter, %d msetter, %d pgetter, %d psetter",
+ gDvmJit.invokeMonoGetterInlined, gDvmJit.invokeMonoSetterInlined,
+ gDvmJit.invokePolyGetterInlined, gDvmJit.invokePolySetterInlined);
LOGD("JIT: Total compilation time: %llu ms", gDvmJit.jitTime / 1000);
LOGD("JIT: Avg unit compilation time: %llu us",
gDvmJit.jitTime / gDvmJit.numCompilations);
@@ -493,13 +504,13 @@
oldValue = slot->u;
newValue = oldValue;
newValue.info.traceConstruction = value;
- } while (!ATOMIC_CMP_SWAP( &slot->u.infoWord,
- oldValue.infoWord, newValue.infoWord));
+ } while (android_atomic_release_cas(oldValue.infoWord, newValue.infoWord,
+ &slot->u.infoWord) != 0);
}
void resetTracehead(InterpState* interpState, JitEntry *slot)
{
- slot->codeAddress = gDvmJit.interpretTemplate;
+ slot->codeAddress = dvmCompilerGetInterpretTemplate();
setTraceConstruction(slot, false);
}
@@ -540,7 +551,7 @@
* (the simple, and common case). Otherwise we're going
* to have to find a free slot and chain it.
*/
- MEM_BARRIER(); /* Make sure we reload [].dPC after lock */
+ ANDROID_MEMBAR_FULL(); /* Make sure we reload [].dPC after lock */
if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
u4 prev;
while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
@@ -577,9 +588,9 @@
oldValue = gDvmJit.pJitEntryTable[prev].u;
newValue = oldValue;
newValue.info.chain = idx;
- } while (!ATOMIC_CMP_SWAP(
- &gDvmJit.pJitEntryTable[prev].u.infoWord,
- oldValue.infoWord, newValue.infoWord));
+ } while (android_atomic_release_cas(oldValue.infoWord,
+ newValue.infoWord,
+ &gDvmJit.pJitEntryTable[prev].u.infoWord) != 0);
}
}
if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
@@ -600,6 +611,62 @@
}
/*
+ * Append the class ptr of "this" and the current method ptr to the current
+ * trace. That is, the trace runs will contain the following components:
+ * + trace run that ends with an invoke (existing entry)
+ * + thisClass (new)
+ * + calleeMethod (new)
+ */
+static void insertClassMethodInfo(InterpState* interpState,
+ const ClassObject* thisClass,
+ const Method* calleeMethod,
+ const DecodedInstruction* insn)
+{
+ int currTraceRun = ++interpState->currTraceRun;
+ interpState->trace[currTraceRun].meta = (void *) thisClass;
+ currTraceRun = ++interpState->currTraceRun;
+ interpState->trace[currTraceRun].meta = (void *) calleeMethod;
+}
+
+/*
+ * Check if the next instruction following the invoke is a move-result and if
+ * so add it to the trace. That is, this will add the trace run that includes
+ * the move-result to the trace list.
+ *
+ * + trace run that ends with an invoke (existing entry)
+ * + thisClass (existing entry)
+ * + calleeMethod (existing entry)
+ * + move result (new)
+ *
+ * lastPC, len, offset are all from the preceding invoke instruction
+ */
+static void insertMoveResult(const u2 *lastPC, int len, int offset,
+ InterpState *interpState)
+{
+ DecodedInstruction nextDecInsn;
+ const u2 *moveResultPC = lastPC + len;
+
+ dexDecodeInstruction(gDvm.instrFormat, moveResultPC, &nextDecInsn);
+ if ((nextDecInsn.opCode != OP_MOVE_RESULT) &&
+ (nextDecInsn.opCode != OP_MOVE_RESULT_WIDE) &&
+ (nextDecInsn.opCode != OP_MOVE_RESULT_OBJECT))
+ return;
+
+ /* We need to start a new trace run */
+ int currTraceRun = ++interpState->currTraceRun;
+ interpState->currRunHead = moveResultPC;
+ interpState->trace[currTraceRun].frag.startOffset = offset + len;
+ interpState->trace[currTraceRun].frag.numInsts = 1;
+ interpState->trace[currTraceRun].frag.runEnd = false;
+ interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+ interpState->trace[currTraceRun].frag.isCode = true;
+ interpState->totalTraceLen++;
+
+ interpState->currRunLen = dexGetInstrOrTableWidthAbs(gDvm.instrWidth,
+ moveResultPC);
+}
+
+/*
* Adds to the current trace request one instruction at a time, just
* before that instruction is interpreted. This is the primary trace
* selection function. NOTE: return instruction are handled a little
@@ -615,19 +682,28 @@
* because returns cannot throw in a way that causes problems for the
* translated code.
*/
-int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState,
+ const ClassObject* thisClass, const Method* curMethod)
{
- int flags,i,len;
+ int flags, len;
int switchInterp = false;
bool debugOrProfile = dvmDebuggerOrProfilerActive();
+ /* Stay in the dbg interpreter for the next instruction */
+ bool stayOneMoreInst = false;
+
+ /*
+ * Bug 2710533 - dalvik crash when disconnecting debugger
+ *
+ * Reset the entry point to the default value. If needed it will be set to a
+ * specific value in the corresponding case statement (eg kJitSingleStepEnd)
+ */
+ interpState->entryPoint = kInterpEntryInstr;
/* Prepare to handle last PC and stage the current PC */
const u2 *lastPC = interpState->lastPC;
interpState->lastPC = pc;
switch (interpState->jitState) {
- char* nopStr;
- int target;
int offset;
DecodedInstruction decInsn;
case kJitTSelect:
@@ -650,7 +726,7 @@
#if defined(SHOW_TRACE)
- LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
+ LOGD("TraceGen: adding %s", dexGetOpcodeName(decInsn.opCode));
#endif
flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, lastPC);
@@ -667,13 +743,21 @@
interpState->trace[currTraceRun].frag.numInsts = 0;
interpState->trace[currTraceRun].frag.runEnd = false;
interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+ interpState->trace[currTraceRun].frag.isCode = true;
}
interpState->trace[interpState->currTraceRun].frag.numInsts++;
interpState->totalTraceLen++;
interpState->currRunLen += len;
+ /*
+ * If the last instruction is an invoke, we will try to sneak in
+ * the move-result* (if existent) into a separate trace run.
+ */
+ int needReservedRun = (flags & kInstrInvoke) ? 1 : 0;
+
/* Will probably never hit this with the current trace buildier */
- if (interpState->currTraceRun == (MAX_JIT_RUN_LEN - 1)) {
+ if (interpState->currTraceRun ==
+ (MAX_JIT_RUN_LEN - 1 - needReservedRun)) {
interpState->jitState = kJitTSelectEnd;
}
@@ -686,9 +770,21 @@
kInstrInvoke)) != 0)) {
interpState->jitState = kJitTSelectEnd;
#if defined(SHOW_TRACE)
- LOGD("TraceGen: ending on %s, basic block end",
- getOpcodeName(decInsn.opCode));
+ LOGD("TraceGen: ending on %s, basic block end",
+ dexGetOpcodeName(decInsn.opCode));
#endif
+
+ /*
+ * If the current invoke is a {virtual,interface}, get the
+ * current class/method pair into the trace as well.
+ * If the next instruction is a variant of move-result, insert
+ * it to the trace too.
+ */
+ if (flags & kInstrInvoke) {
+ insertClassMethodInfo(interpState, thisClass, curMethod,
+ &decInsn);
+ insertMoveResult(lastPC, len, offset, interpState);
+ }
}
/* Break on throw or self-loop */
if ((decInsn.opCode == OP_THROW) || (lastPC == pc)){
@@ -705,6 +801,18 @@
if ((flags & kInstrCanReturn) != kInstrCanReturn) {
break;
}
+ else {
+ /*
+ * Last instruction is a return - stay in the dbg interpreter
+ * for one more instruction if it is a non-void return, since
+ * we don't want to start a trace with move-result as the first
+ * instruction (which is already included in the trace
+ * containing the invoke.
+ */
+ if (decInsn.opCode != OP_RETURN_VOID) {
+ stayOneMoreInst = true;
+ }
+ }
/* NOTE: intentional fallthrough for returns */
case kJitTSelectEnd:
{
@@ -715,9 +823,25 @@
switchInterp = true;
break;
}
+
+ int lastTraceDesc = interpState->currTraceRun;
+
+ /* Extend a new empty desc if the last slot is meta info */
+ if (!interpState->trace[lastTraceDesc].frag.isCode) {
+ lastTraceDesc = ++interpState->currTraceRun;
+ interpState->trace[lastTraceDesc].frag.startOffset = 0;
+ interpState->trace[lastTraceDesc].frag.numInsts = 0;
+ interpState->trace[lastTraceDesc].frag.hint = kJitHintNone;
+ interpState->trace[lastTraceDesc].frag.isCode = true;
+ }
+
+ /* Mark the end of the trace runs */
+ interpState->trace[lastTraceDesc].frag.runEnd = true;
+
JitTraceDescription* desc =
(JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
sizeof(JitTraceRun) * (interpState->currTraceRun+1));
+
if (desc == NULL) {
LOGE("Out of memory in trace selection");
dvmJitStopTranslationRequests();
@@ -725,8 +849,7 @@
switchInterp = true;
break;
}
- interpState->trace[interpState->currTraceRun].frag.runEnd =
- true;
+
desc->method = interpState->method;
memcpy((char*)&(desc->trace[0]),
(char*)&(interpState->trace[0]),
@@ -785,16 +908,8 @@
}
break;
#endif
- /*
- * If the debug interpreter was entered for non-JIT reasons, check if
- * the original reason still holds. If not, we have to force the
- * interpreter switch here and use dvmDebuggerOrProfilerActive instead
- * of dvmJitDebuggerOrProfilerActive since the latter will alwasy
- * return true when the debugger/profiler is already detached and the
- * JIT profiling table is restored.
- */
case kJitNot:
- switchInterp = !dvmDebuggerOrProfilerActive();
+ switchInterp = !debugOrProfile;
break;
default:
LOGE("Unexpected JIT state: %d entry point: %d",
@@ -808,7 +923,7 @@
*/
assert(switchInterp == false || interpState->jitState == kJitDone ||
interpState->jitState == kJitNot);
- return switchInterp && !debugOrProfile;
+ return switchInterp && !debugOrProfile && !stayOneMoreInst;
}
JitEntry *dvmFindJitEntry(const u2* pc)
@@ -843,7 +958,7 @@
(gDvmJit.pProfTable == NULL);
if (npc == dPC) {
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.addrLookupsFound++;
#endif
return hideTranslation ?
@@ -853,7 +968,7 @@
while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.addrLookupsFound++;
#endif
return hideTranslation ?
@@ -862,7 +977,7 @@
}
}
}
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.addrLookupsNotFound++;
#endif
return NULL;
@@ -885,9 +1000,9 @@
oldValue = jitEntry->u;
newValue = oldValue;
newValue.info.instructionSet = set;
- } while (!ATOMIC_CMP_SWAP(
- &jitEntry->u.infoWord,
- oldValue.infoWord, newValue.infoWord));
+ } while (android_atomic_release_cas(
+ oldValue.infoWord, newValue.infoWord,
+ &jitEntry->u.infoWord) != 0);
jitEntry->codeAddress = nPC;
}
@@ -900,8 +1015,59 @@
{
bool switchInterp = false; /* Assume success */
int i;
- intptr_t filterKey = ((intptr_t) interpState->pc) >>
- JIT_TRACE_THRESH_FILTER_GRAN_LOG2;
+ /*
+ * A note on trace "hotness" filtering:
+ *
+ * Our first level trigger is intentionally loose - we need it to
+ * fire easily not just to identify potential traces to compile, but
+ * also to allow re-entry into the code cache.
+ *
+ * The 2nd level filter (done here) exists to be selective about
+ * what we actually compile. It works by requiring the same
+ * trace head "key" (defined as filterKey below) to appear twice in
+ * a relatively short period of time. The difficulty is defining the
+ * shape of the filterKey. Unfortunately, there is no "one size fits
+ * all" approach.
+ *
+ * For spiky execution profiles dominated by a smallish
+ * number of very hot loops, we would want the second-level filter
+ * to be very selective. A good selective filter is requiring an
+ * exact match of the Dalvik PC. In other words, defining filterKey as:
+ * intptr_t filterKey = (intptr_t)interpState->pc
+ *
+ * However, for flat execution profiles we do best when aggressively
+ * translating. A heuristically decent proxy for this is to use
+ * the value of the method pointer containing the trace as the filterKey.
+ * Intuitively, this is saying that once any trace in a method appears hot,
+ * immediately translate any other trace from that same method that
+ * survives the first-level filter. Here, filterKey would be defined as:
+ * intptr_t filterKey = (intptr_t)interpState->method
+ *
+ * The problem is that we can't easily detect whether we're dealing
+ * with a spiky or flat profile. If we go with the "pc" match approach,
+ * flat profiles perform poorly. If we go with the loose "method" match,
+ * we end up generating a lot of useless translations. Probably the
+ * best approach in the future will be to retain profile information
+ * across runs of each application in order to determine it's profile,
+ * and then choose once we have enough history.
+ *
+ * However, for now we've decided to chose a compromise filter scheme that
+ * includes elements of both. The high order bits of the filter key
+ * are drawn from the enclosing method, and are combined with a slice
+ * of the low-order bits of the Dalvik pc of the trace head. The
+ * looseness of the filter can be adjusted by changing with width of
+ * the Dalvik pc slice (JIT_TRACE_THRESH_FILTER_PC_BITS). The wider
+ * the slice, the tighter the filter.
+ *
+ * Note: the fixed shifts in the function below reflect assumed word
+ * alignment for method pointers, and half-word alignment of the Dalvik pc.
+ * for method pointers and half-word alignment for dalvik pc.
+ */
+ u4 methodKey = (u4)interpState->method <<
+ (JIT_TRACE_THRESH_FILTER_PC_BITS - 2);
+ u4 pcKey = ((u4)interpState->pc >> 1) &
+ ((1 << JIT_TRACE_THRESH_FILTER_PC_BITS) - 1);
+ intptr_t filterKey = (intptr_t)(methodKey | pcKey);
bool debugOrProfile = dvmDebuggerOrProfilerActive();
/* Check if the JIT request can be handled now */
@@ -912,6 +1078,7 @@
/* Two-level filtering scheme */
for (i=0; i< JIT_TRACE_THRESH_FILTER_SIZE; i++) {
if (filterKey == interpState->threshFilter[i]) {
+ interpState->threshFilter[i] = 0; // Reset filter entry
break;
}
}
@@ -992,6 +1159,7 @@
interpState->trace[0].frag.numInsts = 0;
interpState->trace[0].frag.runEnd = false;
interpState->trace[0].frag.hint = kJitHintNone;
+ interpState->trace[0].frag.isCode = true;
interpState->lastPC = 0;
break;
/*
diff --git a/vm/interp/Jit.h b/vm/interp/Jit.h
index 9d17a52..6101f54 100644
--- a/vm/interp/Jit.h
+++ b/vm/interp/Jit.h
@@ -43,7 +43,8 @@
const u2* startPC; /* starting pc of jitted region */
const void* fp; /* starting fp of jitted region */
void* glue; /* starting glue of jitted region */
- SelfVerificationState selfVerificationState; /* self verification state */
+ SelfVerificationState jitExitState; /* exit point for JIT'ed code */
+ SelfVerificationState selfVerificationState; /* current SV running state */
const u2* endPC; /* ending pc of jitted region */
void* shadowFP; /* pointer to fp in shadow space */
InterpState interpState; /* copy of interpState */
@@ -108,7 +109,8 @@
void* codeAddress; /* Code address of native translation */
} JitEntry;
-int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState);
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState,
+ const ClassObject *callsiteClass, const Method* curMethod);
void* dvmJitGetCodeAddr(const u2* dPC);
bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState);
void dvmJitStopTranslationRequests(void);
diff --git a/vm/interp/README.txt b/vm/interp/README.txt
index 76d47a7..170d2b1 100644
--- a/vm/interp/README.txt
+++ b/vm/interp/README.txt
@@ -1,4 +1,3 @@
Dalvik interpreter entry point.
The "mterp" directory now holds the interpreter implementation.
-
diff --git a/vm/interp/Stack.c b/vm/interp/Stack.c
index 1ebbcf0..673dc14 100644
--- a/vm/interp/Stack.c
+++ b/vm/interp/Stack.c
@@ -429,8 +429,6 @@
void dvmCallMethod(Thread* self, const Method* method, Object* obj,
JValue* pResult, ...)
{
- JValue result;
-
va_list args;
va_start(args, pResult);
dvmCallMethodV(self, method, obj, false, pResult, args);
@@ -535,7 +533,9 @@
dvmInterpret(self, method, pResult);
}
+#ifndef NDEBUG
bail:
+#endif
dvmPopFrame(self);
}
@@ -790,7 +790,7 @@
{
LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
- // We know that this callback will be called in
+ // We know that this callback will be called in
// ascending address order, so keep going until we find
// a match or we've just gone past it.
@@ -834,7 +834,7 @@
method->prototype.protoIdx,
method->accessFlags,
lineNumForPcCb, NULL, &context);
-
+
return context.lineNum;
}
@@ -867,9 +867,9 @@
int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
{
const u1* interpStackStart = thread->interpStackStart;
- const u1* interpStackBottom = interpStackStart - thread->interpStackSize;
- assert((u1*) fp >= interpStackBottom && (u1*) fp < interpStackStart);
+ assert((u1*) fp >= interpStackStart - thread->interpStackSize);
+ assert((u1*) fp < interpStackStart);
return interpStackStart - (u1*) fp;
}
@@ -966,7 +966,7 @@
if (caller == NULL)
return NULL;
}
-
+
return SAVEAREA_FROM_FP(caller)->method->clazz;
}
@@ -1380,4 +1380,3 @@
dumpFrames(target, stackCopy + fpOffset, thread);
free(stackCopy);
}
-
diff --git a/vm/jdwp/ExpandBuf.c b/vm/jdwp/ExpandBuf.c
index 50c3035..ade239c 100644
--- a/vm/jdwp/ExpandBuf.c
+++ b/vm/jdwp/ExpandBuf.c
@@ -173,4 +173,3 @@
setUtf8String(pBuf->storage + pBuf->curLen, str);
pBuf->curLen += sizeof(u4) + strLen;
}
-
diff --git a/vm/jdwp/JdwpAdb.c b/vm/jdwp/JdwpAdb.c
index dfc7bd7..c3a1a72 100644
--- a/vm/jdwp/JdwpAdb.c
+++ b/vm/jdwp/JdwpAdb.c
@@ -101,13 +101,13 @@
netState->controlAddrLen =
sizeof(netState->controlAddr.controlAddrUn.sun_family) +
kJdwpControlNameLen;
-
- memcpy(netState->controlAddr.controlAddrUn.sun_path,
+
+ memcpy(netState->controlAddr.controlAddrUn.sun_path,
kJdwpControlName, kJdwpControlNameLen);
-
+
netState->wakeFds[0] = -1;
netState->wakeFds[1] = -1;
-
+
return netState;
}
@@ -122,7 +122,7 @@
JdwpNetState* netState;
LOGV("ADB transport startup\n");
-
+
state->netState = netState = adbStateAlloc();
if (netState == NULL)
return false;
@@ -158,13 +158,13 @@
msg.msg_flags = 0;
msg.msg_control = cm_un.buffer;
msg.msg_controllen = sizeof(cm_un.buffer);
-
+
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = msg.msg_controllen;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
((int*)CMSG_DATA(cmsg))[0] = -1;
-
+
do {
ret = recvmsg(netState->controlSock, &msg, 0);
} while (ret < 0 && errno == EINTR);
@@ -197,7 +197,7 @@
int retryCount = 0;
/* first, ensure that we get a connection to the ADB daemon */
-
+
retry:
if (netState->shuttingDown)
return false;
@@ -340,7 +340,7 @@
shutdown(controlSock, SHUT_RDWR);
netState->controlSock = -1;
}
-
+
if (netState->wakeFds[1] >= 0) {
LOGV("+++ writing to wakePipe\n");
(void) write(netState->wakeFds[1], "", 1);
@@ -759,4 +759,3 @@
{
return &socketTransport;
}
-
diff --git a/vm/jdwp/JdwpConstants.c b/vm/jdwp/JdwpConstants.c
index e089afa..898fe2c 100644
--- a/vm/jdwp/JdwpConstants.c
+++ b/vm/jdwp/JdwpConstants.c
@@ -237,4 +237,3 @@
default: return "?UNKNOWN?";
}
};
-
diff --git a/vm/jdwp/JdwpEvent.c b/vm/jdwp/JdwpEvent.c
index 996d7ad..69d2237 100644
--- a/vm/jdwp/JdwpEvent.c
+++ b/vm/jdwp/JdwpEvent.c
@@ -206,7 +206,6 @@
state->eventList = pEvent;
state->numEvents++;
-bail:
unlockEventMutex(state);
return err;
@@ -425,8 +424,6 @@
return false;
return strcmp(pattern+1, target + (targetLen-patLen)) == 0;
} else if (pattern[patLen-1] == '*') {
- int i;
-
return strncmp(pattern, target, patLen-1) == 0;
} else {
return strcmp(pattern, target) == 0;
@@ -748,7 +745,7 @@
{
enum JdwpSuspendPolicy suspendPolicy;
ObjectId threadId = dvmDbgGetThreadSelfId();
-
+
if (suspend)
suspendPolicy = SP_ALL;
else
@@ -1293,4 +1290,3 @@
dvmJdwpSendBufferedRequest(state, wrapiov, iovcnt+1);
}
-
diff --git a/vm/jdwp/JdwpHandler.c b/vm/jdwp/JdwpHandler.c
index 53b5d26..d2a657d 100644
--- a/vm/jdwp/JdwpHandler.c
+++ b/vm/jdwp/JdwpHandler.c
@@ -240,7 +240,6 @@
u4 numClasses;
size_t strLen;
RefTypeId refTypeId;
- int i;
classDescriptor = readNewUtf8String(&buf, &strLen);
LOGV(" Req for class by signature '%s'\n", classDescriptor);
@@ -430,8 +429,6 @@
static JdwpError handleVM_Capabilities(JdwpState* state,
const u1* buf, int dataLen, ExpandBuf* pReply)
{
- int i;
-
expandBufAdd1(pReply, false); /* canWatchFieldModification */
expandBufAdd1(pReply, false); /* canWatchFieldAccess */
expandBufAdd1(pReply, false); /* canGetBytecodes */
@@ -745,7 +742,6 @@
const u1* buf, int dataLen, ExpandBuf* pReply)
{
RefTypeId refTypeId;
- ObjectId classLoaderId;
refTypeId = dvmReadRefTypeId(&buf);
@@ -762,7 +758,6 @@
const u1* buf, int dataLen, ExpandBuf* pReply)
{
RefTypeId refTypeId;
- int i, numFields;
refTypeId = dvmReadRefTypeId(&buf);
LOGV(" Req for fields in refTypeId=0x%llx\n", refTypeId);
@@ -785,7 +780,6 @@
const u1* buf, int dataLen, ExpandBuf* pReply)
{
RefTypeId refTypeId;
- int i;
refTypeId = dvmReadRefTypeId(&buf);
@@ -887,7 +881,6 @@
ObjectId threadId;
MethodId methodId;
ObjectId objectId;
- u4 numArgs;
classId = dvmReadRefTypeId(&buf);
threadId = dvmReadObjectId(&buf);
@@ -903,6 +896,30 @@
}
/*
+ * Create a new array object of the requested type and length.
+ */
+static JdwpError handleAT_newInstance(JdwpState* state,
+ const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+ RefTypeId arrayTypeId;
+ u4 length;
+ ObjectId objectId;
+
+ arrayTypeId = dvmReadRefTypeId(&buf);
+ length = read4BE(&buf);
+
+ LOGV("Creating array %s[%u]\n",
+ dvmDbgGetClassDescriptor(arrayTypeId), length);
+ objectId = dvmDbgCreateArrayObject(arrayTypeId, length);
+ if (objectId == 0)
+ return ERR_OUT_OF_MEMORY;
+
+ expandBufAdd1(pReply, JT_ARRAY);
+ expandBufAddObjectId(pReply, objectId);
+ return ERR_NONE;
+}
+
+/*
* Return line number information for the method, if present.
*/
static JdwpError handleM_LineTable(JdwpState* state,
@@ -997,7 +1014,6 @@
u1 fieldTag;
int width;
u1* ptr;
- const char* fieldName;
fieldId = dvmReadFieldId(&buf);
@@ -1420,7 +1436,6 @@
{
ObjectId threadGroupId;
u4 threadCount;
- ObjectId threadId;
ObjectId* pThreadIds;
ObjectId* walker;
int i;
@@ -1510,8 +1525,6 @@
ObjectId arrayId;
u4 firstIndex;
u4 values;
- u1 tag;
- int i;
arrayId = dvmReadObjectId(&buf);
firstIndex = read4BE(&buf);
@@ -2023,7 +2036,7 @@
{ 3, 4, handleCT_NewInstance, "ClassType.NewInstance" },
/* ArrayType command set (4) */
- //4, 1, NewInstance
+ { 4, 1, handleAT_newInstance, "ArrayType.NewInstance" },
/* InterfaceType command set (5) */
@@ -2117,15 +2130,14 @@
JdwpError result = ERR_NONE;
int i, respLen;
- /*
- * Activity from a debugger, not merely ddms. Mark us as having an
- * active debugger session, and zero out the last-activity timestamp.
- */
if (pHeader->cmdSet != kJDWPDdmCmdSet) {
+ /*
+ * Activity from a debugger, not merely ddms. Mark us as having an
+ * active debugger session, and zero out the last-activity timestamp
+ * so waitForDebugger() doesn't return if we stall for a bit here.
+ */
dvmDbgActive();
-
- state->lastActivitySec = 0;
- MEM_BARRIER();
+ dvmQuasiAtomicSwap64(0, &state->lastActivityWhen);
}
/*
@@ -2203,15 +2215,9 @@
* the initial setup. Only update if this is a non-DDMS packet.
*/
if (pHeader->cmdSet != kJDWPDdmCmdSet) {
- long lastSec, lastMsec;
-
- dvmJdwpGetNowMsec(&lastSec, &lastMsec);
- state->lastActivityMsec = lastMsec;
- MEM_BARRIER(); // updating a 64-bit value
- state->lastActivitySec = lastSec;
+ dvmQuasiAtomicSwap64(dvmJdwpGetNowMsec(), &state->lastActivityWhen);
}
/* tell the VM that GC is okay again */
dvmDbgThreadWaiting();
}
-
diff --git a/vm/jdwp/JdwpMain.c b/vm/jdwp/JdwpMain.c
index ef24618..1688e5e 100644
--- a/vm/jdwp/JdwpMain.c
+++ b/vm/jdwp/JdwpMain.c
@@ -40,8 +40,6 @@
JdwpState* dvmJdwpStartup(const JdwpStartupParams* pParams)
{
JdwpState* state = NULL;
- int i, sleepIter;
- u8 startWhen;
/* comment this out when debugging JDWP itself */
android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
@@ -211,7 +209,7 @@
/*
* Are we talking to a debugger?
- */
+ */
bool dvmJdwpIsActive(JdwpState* state)
{
return dvmJdwpIsConnected(state);
@@ -233,7 +231,7 @@
*/
state->debugThreadHandle = dvmThreadSelf()->handle;
state->run = true;
- MEM_BARRIER();
+ ANDROID_MEMBAR_FULL();
state->debugThreadStarted = true; // touch this last
dvmDbgLockMutex(&state->threadStartLock);
@@ -253,7 +251,6 @@
*/
while (state->run) {
bool first;
- int cc;
if (state->params.server) {
/*
@@ -352,59 +349,40 @@
return state->debugThreadHandle;
}
-#if 0
+
/*
- * Wait until the debugger attaches. Returns immediately if the debugger
- * is already attached.
+ * Support routines for waitForDebugger().
*
- * If we return the instant the debugger connects, we run the risk of
- * executing code before the debugger has had a chance to configure
- * breakpoints or issue suspend calls. It would be nice to just sit in
- * the suspended state, but most debuggers don't expect any threads to be
- * suspended when they attach.
+ * We can't have a trivial "waitForDebugger" function that returns the
+ * instant the debugger connects, because we run the risk of executing code
+ * before the debugger has had a chance to configure breakpoints or issue
+ * suspend calls. It would be nice to just sit in the suspended state, but
+ * most debuggers don't expect any threads to be suspended when they attach.
*
- * There's no event we can post to tell the debugger "we've stopped, and
- * we like it that way". We could send a fake breakpoint, which should
+ * There's no JDWP event we can post to tell the debugger, "we've stopped,
+ * and we like it that way". We could send a fake breakpoint, which should
* cause the debugger to immediately send a resume, but the debugger might
* send the resume immediately or might throw an exception of its own upon
* receiving a breakpoint event that it didn't ask for.
*
* What we really want is a "wait until the debugger is done configuring
- * stuff" event. We can get close with a "wait until the debugger has
- * been idle for a brief period", and we can do a mild approximation with
- * "just sleep for a second after it connects".
- *
- * We should be in THREAD_VMWAIT here, so we're not allowed to do anything
- * with objects because a GC could be in progress.
- *
- * NOTE: this trips as soon as something connects to the socket. This
- * is no longer appropriate -- we don't want to return when DDMS connects.
- * We could fix this by polling for the first debugger packet, but we have
- * to watch out for disconnects. If we're going to do polling, it's
- * probably best to do it at a higher level.
+ * stuff" event. We can approximate this with a "wait until the debugger
+ * has been idle for a brief period".
*/
-void dvmJdwpWaitForDebugger(JdwpState* state)
-{
- // no more
-}
-#endif
/*
- * Get a notion of the current time, in milliseconds. We leave it in
- * two 32-bit pieces.
+ * Get a notion of the current time, in milliseconds.
*/
-void dvmJdwpGetNowMsec(long* pSec, long* pMsec)
+s8 dvmJdwpGetNowMsec(void)
{
#ifdef HAVE_POSIX_CLOCKS
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- *pSec = now.tv_sec;
- *pMsec = now.tv_nsec / 1000000;
+ return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
#else
struct timeval now;
gettimeofday(&now, NULL);
- *pSec = now.tv_sec;
- *pMsec = now.tv_usec / 1000;
+ return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
#endif
}
@@ -416,30 +394,23 @@
*/
s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
{
- long lastSec, lastMsec;
- long nowSec, nowMsec;
+ if (!gDvm.debuggerActive) {
+ LOGD("dvmJdwpLastDebuggerActivity: no active debugger\n");
+ return -1;
+ }
- /* these are volatile; lastSec becomes 0 during update */
- lastSec = state->lastActivitySec;
- lastMsec = state->lastActivityMsec;
+ s8 last = dvmQuasiAtomicRead64(&state->lastActivityWhen);
/* initializing or in the middle of something? */
- if (lastSec == 0 || state->lastActivitySec != lastSec) {
- //LOGI("+++ last=busy\n");
+ if (last == 0) {
+ LOGV("+++ last=busy\n");
return 0;
}
- /* get the current time *after* latching the "last" time */
- dvmJdwpGetNowMsec(&nowSec, &nowMsec);
+ /* now get the current time */
+ s8 now = dvmJdwpGetNowMsec();
+ assert(now > last);
- s8 last = (s8)lastSec * 1000 + lastMsec;
- s8 now = (s8)nowSec * 1000 + nowMsec;
-
- //LOGI("last is %ld.%ld --> %lld\n", lastSec, lastMsec, last);
- //LOGI("now is %ld.%ld --> %lld\n", nowSec, nowMsec, now);
-
-
- //LOGI("+++ interval=%lld\n", now - last);
+ LOGV("+++ debugger interval=%lld\n", now - last);
return now - last;
}
-
diff --git a/vm/jdwp/JdwpPriv.h b/vm/jdwp/JdwpPriv.h
index 87c3fc7..85f9ec2 100644
--- a/vm/jdwp/JdwpPriv.h
+++ b/vm/jdwp/JdwpPriv.h
@@ -91,9 +91,8 @@
pthread_mutex_t attachLock;
pthread_cond_t attachCond;
- /* time of last debugger activity; "sec" zeroed while processing */
- volatile long lastActivitySec;
- volatile long lastActivityMsec;
+ /* time of last debugger activity, in milliseconds */
+ s8 lastActivityWhen;
/* global counters and a mutex to protect them */
u4 requestSerial;
@@ -130,7 +129,7 @@
u4 dvmJdwpNextEventSerial(JdwpState* state);
/* get current time, in msec */
-void dvmJdwpGetNowMsec(long* pSec, long* pMsec);
+s8 dvmJdwpGetNowMsec(void);
/*
diff --git a/vm/jdwp/JdwpSocket.c b/vm/jdwp/JdwpSocket.c
index 42cd189..0c39202 100644
--- a/vm/jdwp/JdwpSocket.c
+++ b/vm/jdwp/JdwpSocket.c
@@ -270,6 +270,7 @@
/*
* Returns "true" if the fd is ready, "false" if not.
*/
+#if 0
static bool isFdReadable(int sock)
{
fd_set readfds;
@@ -291,6 +292,7 @@
LOGE("WEIRD: odd behavior in select (count=%d)\n", count);
return false;
}
+#endif
#if 0
/*
@@ -390,8 +392,7 @@
struct sockaddr addrPlain;
} addr;
struct hostent* pEntry;
- char auxBuf[128];
- int cc, h_errno;
+ int h_errno;
assert(state != NULL && state->netState != NULL);
assert(!state->params.server);
@@ -405,7 +406,8 @@
//#warning "forcing non-R"
#ifdef HAVE_GETHOSTBYNAME_R
struct hostent he;
- cc = gethostbyname_r(state->params.host, &he, auxBuf, sizeof(auxBuf),
+ char auxBuf[128];
+ int cc = gethostbyname_r(state->params.host, &he, auxBuf, sizeof(auxBuf),
&pEntry, &h_errno);
if (cc != 0) {
LOGW("gethostbyname_r('%s') failed: %s\n",
@@ -536,6 +538,7 @@
/*
* Dump the contents of a packet to stdout.
*/
+#if 0
static void dumpPacket(const unsigned char* packetBuf)
{
const unsigned char* buf = packetBuf;
@@ -567,6 +570,7 @@
if (dataLen > 0)
dvmPrintHexDumpDbg(buf, dataLen, LOG_TAG);
}
+#endif
/*
* Handle a packet. Returns "false" if we encounter a connection-fatal error.
@@ -918,4 +922,3 @@
{
return &socketTransport;
}
-
diff --git a/vm/jdwp/README.txt b/vm/jdwp/README.txt
index b511cc8..c97a069 100644
--- a/vm/jdwp/README.txt
+++ b/vm/jdwp/README.txt
@@ -10,4 +10,3 @@
might be useful in other projects. Once you get multiple simultaneous
events and debugger requests with thread suspension bouncing around,
though, it's difficult to keep things "generic".
-
diff --git a/vm/mterp/Makefile-mterp b/vm/mterp/Makefile-mterp
index d30dff2..2f96d59 100644
--- a/vm/mterp/Makefile-mterp
+++ b/vm/mterp/Makefile-mterp
@@ -49,4 +49,3 @@
$(GEN_SOURCES): $(SOURCE_DEPS)
@mkdir -p out
./gen-mterp.py $(TARGET_ARCH_EXT) $(OUTPUT_DIR)
-
diff --git a/vm/mterp/Mterp.c b/vm/mterp/Mterp.c
index ca2ca16..4b0ceb8 100644
--- a/vm/mterp/Mterp.c
+++ b/vm/mterp/Mterp.c
@@ -33,8 +33,6 @@
extern char dvmAsmInstructionStart[];
extern char dvmAsmInstructionEnd[];
- extern char dvmAsmSisterStart[];
- extern char dvmAsmSisterEnd[];
#define ASM_DEF_VERIFY
#include "mterp/common/asm-constants.h"
@@ -55,9 +53,6 @@
LOGE("(did an instruction handler exceed %d bytes?)\n", width);
dvmAbort();
}
- int sisterSize = dvmAsmSisterEnd - dvmAsmSisterStart;
- LOGV("mterp: interp is %d bytes, sisters are %d bytes\n",
- interpSize, sisterSize);
#endif // ndef DVM_NO_ASM_INTERP
@@ -81,13 +76,20 @@
glue->interpStackEnd = self->interpStackEnd;
glue->pSelfSuspendCount = &self->suspendCount;
+ glue->cardTable = gDvm.biasedCardTableBase;
#if defined(WITH_JIT)
glue->pJitProfTable = gDvmJit.pProfTable;
glue->ppJitProfTable = &gDvmJit.pProfTable;
glue->jitThreshold = gDvmJit.threshold;
#endif
#if defined(WITH_DEBUGGER)
- glue->pDebuggerActive = &gDvm.debuggerActive;
+ if (gDvm.jdwpConfigured) {
+ glue->pDebuggerActive = &gDvm.debuggerActive;
+ } else {
+ /* TODO: fix x86 impl before enabling this */
+ //glue->pDebuggerActive = NULL;
+ glue->pDebuggerActive = &gDvm.debuggerActive;
+ }
#endif
#if defined(WITH_PROFILER)
glue->pActiveProfilers = &gDvm.activeProfilers;
diff --git a/vm/mterp/NOTES.txt b/vm/mterp/NOTES.txt
index e348934..5dc7caa 100644
--- a/vm/mterp/NOTES.txt
+++ b/vm/mterp/NOTES.txt
@@ -69,4 +69,3 @@
code. JNI handles returns from interp->native by adding the value to the
local references table, but returns from native->interp are simply stored
in the usual "retval".
-
diff --git a/vm/mterp/README.txt b/vm/mterp/README.txt
index e6141d2..80596ea 100644
--- a/vm/mterp/README.txt
+++ b/vm/mterp/README.txt
@@ -213,4 +213,3 @@
The ultimate goal is to have the build system generate the necessary
output files without requiring this separate step, but we're not yet
ready to require Python in the build.
-
diff --git a/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S b/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S
index a8c3ea4..b75216e 100644
--- a/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S
+++ b/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S
@@ -40,4 +40,3 @@
.L${opcode}_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/arm-vfp/OP_CMPG_FLOAT.S b/vm/mterp/arm-vfp/OP_CMPG_FLOAT.S
index 4c14fbb..eade97d 100644
--- a/vm/mterp/arm-vfp/OP_CMPG_FLOAT.S
+++ b/vm/mterp/arm-vfp/OP_CMPG_FLOAT.S
@@ -40,4 +40,3 @@
.L${opcode}_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/arm-vfp/OP_CMPL_DOUBLE.S b/vm/mterp/arm-vfp/OP_CMPL_DOUBLE.S
index 999faee..6e85fe7 100644
--- a/vm/mterp/arm-vfp/OP_CMPL_DOUBLE.S
+++ b/vm/mterp/arm-vfp/OP_CMPL_DOUBLE.S
@@ -40,4 +40,3 @@
.L${opcode}_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/arm-vfp/OP_CMPL_FLOAT.S b/vm/mterp/arm-vfp/OP_CMPL_FLOAT.S
index 9b2133c..bdeb0be 100644
--- a/vm/mterp/arm-vfp/OP_CMPL_FLOAT.S
+++ b/vm/mterp/arm-vfp/OP_CMPL_FLOAT.S
@@ -40,4 +40,3 @@
.L${opcode}_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv4t/OP_AGET_WIDE.S b/vm/mterp/armv4t/OP_AGET_WIDE.S
index f06cb8b..dc5eee8 100644
--- a/vm/mterp/armv4t/OP_AGET_WIDE.S
+++ b/vm/mterp/armv4t/OP_AGET_WIDE.S
@@ -31,4 +31,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv4t/OP_APUT_WIDE.S b/vm/mterp/armv4t/OP_APUT_WIDE.S
index e8db664..9a718f2 100644
--- a/vm/mterp/armv4t/OP_APUT_WIDE.S
+++ b/vm/mterp/armv4t/OP_APUT_WIDE.S
@@ -29,4 +29,3 @@
add r0, #offArrayObject_contents
stmia r0, {r2-r3} @ vBB[vCC] <- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv4t/OP_IGET_WIDE.S b/vm/mterp/armv4t/OP_IGET_WIDE.S
index 576b43d..5940f56 100644
--- a/vm/mterp/armv4t/OP_IGET_WIDE.S
+++ b/vm/mterp/armv4t/OP_IGET_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "null object"
%verify "field already resolved"
@@ -33,13 +34,17 @@
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
- mov r2, rINST, lsr #8 @ r2<- A+
+ .if $volatile
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
add r9, r9, r3 @ r9<- obj + field offset
ldmia r9, {r0-r1} @ r0/r1<- obj.field (64-bit align ok)
- and r2, r2, #15 @ r2<- A
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv4t/OP_IGET_WIDE_QUICK.S b/vm/mterp/armv4t/OP_IGET_WIDE_QUICK.S
index 36a6e1d..b0022f5 100644
--- a/vm/mterp/armv4t/OP_IGET_WIDE_QUICK.S
+++ b/vm/mterp/armv4t/OP_IGET_WIDE_QUICK.S
@@ -15,4 +15,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv4t/OP_IGET_WIDE_VOLATILE.S b/vm/mterp/armv4t/OP_IGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..cdd8708
--- /dev/null
+++ b/vm/mterp/armv4t/OP_IGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv4t/OP_IGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv4t/OP_IPUT_WIDE.S b/vm/mterp/armv4t/OP_IPUT_WIDE.S
index c4b43b3..d0f7315 100644
--- a/vm/mterp/armv4t/OP_IPUT_WIDE.S
+++ b/vm/mterp/armv4t/OP_IPUT_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "null object"
%verify "field already resolved"
@@ -35,8 +36,11 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- add r9, r9, r3 @ r9<- object + byte offset
- stmia r9, {r0-r1} @ obj.field (64 bits, aligned)<- r0/r1
- GOTO_OPCODE(ip) @ jump to next instruction
-
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ add r2, r9, r3 @ r2<- object + byte offset
+ .if $volatile
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ stmia r2, {r0-r1} @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
diff --git a/vm/mterp/armv4t/OP_IPUT_WIDE_QUICK.S b/vm/mterp/armv4t/OP_IPUT_WIDE_QUICK.S
index a483060..b062127 100644
--- a/vm/mterp/armv4t/OP_IPUT_WIDE_QUICK.S
+++ b/vm/mterp/armv4t/OP_IPUT_WIDE_QUICK.S
@@ -15,4 +15,3 @@
stmia r2, {r0-r1} @ obj.field (64 bits, aligned)<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv4t/OP_IPUT_WIDE_VOLATILE.S b/vm/mterp/armv4t/OP_IPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..6b297f0
--- /dev/null
+++ b/vm/mterp/armv4t/OP_IPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv4t/OP_IPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv4t/OP_SGET_WIDE.S b/vm/mterp/armv4t/OP_SGET_WIDE.S
index 61a7a43..91e195d 100644
--- a/vm/mterp/armv4t/OP_SGET_WIDE.S
+++ b/vm/mterp/armv4t/OP_SGET_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "field already resolved"
%verify "field not yet resolved"
@@ -13,12 +14,16 @@
cmp r0, #0 @ is resolved entry null?
beq .L${opcode}_resolve @ yes, do resolve
.L${opcode}_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- add r0, r0, #offStaticField_value
- ldmia r0, {r2-r3} @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ .if $volatile
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldmia r0, {r0-r1} @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
%break
@@ -26,6 +31,8 @@
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.L${opcode}_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -35,4 +42,3 @@
cmp r0, #0 @ success?
bne .L${opcode}_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
diff --git a/vm/mterp/armv4t/OP_SGET_WIDE_VOLATILE.S b/vm/mterp/armv4t/OP_SGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..5615ab6
--- /dev/null
+++ b/vm/mterp/armv4t/OP_SGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv4t/OP_SGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv4t/OP_SPUT_WIDE.S b/vm/mterp/armv4t/OP_SPUT_WIDE.S
index b90cf50..a67e2d8 100644
--- a/vm/mterp/armv4t/OP_SPUT_WIDE.S
+++ b/vm/mterp/armv4t/OP_SPUT_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "field already resolved"
%verify "field not yet resolved"
@@ -6,27 +7,33 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .L${opcode}_resolve @ yes, do resolve
-.L${opcode}_finish: @ field ptr in r0, AA in r9
+.L${opcode}_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- add r0, r0, #offStaticField_value
- stmia r0, {r2-r3} @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ .if $volatile
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ stmia r2, {r0-r1} @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
%break
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.L${opcode}_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -34,6 +41,6 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .L${opcode}_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
diff --git a/vm/mterp/armv4t/OP_SPUT_WIDE_VOLATILE.S b/vm/mterp/armv4t/OP_SPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..850e83b
--- /dev/null
+++ b/vm/mterp/armv4t/OP_SPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv4t/OP_SPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv4t/platform.S b/vm/mterp/armv4t/platform.S
index d7a6d71..eca940a 100644
--- a/vm/mterp/armv4t/platform.S
+++ b/vm/mterp/armv4t/platform.S
@@ -37,3 +37,8 @@
bx lr
.endm
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro SMP_DMB
+.endm
diff --git a/vm/mterp/armv5te/OP_AGET.S b/vm/mterp/armv5te/OP_AGET.S
index 7a0950b..8d8ed58 100644
--- a/vm/mterp/armv5te/OP_AGET.S
+++ b/vm/mterp/armv5te/OP_AGET.S
@@ -25,4 +25,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_AGET_WIDE.S b/vm/mterp/armv5te/OP_AGET_WIDE.S
index ec346ca..6f641dc 100644
--- a/vm/mterp/armv5te/OP_AGET_WIDE.S
+++ b/vm/mterp/armv5te/OP_AGET_WIDE.S
@@ -30,4 +30,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_APUT.S b/vm/mterp/armv5te/OP_APUT.S
index f8ee4a8..741aadd 100644
--- a/vm/mterp/armv5te/OP_APUT.S
+++ b/vm/mterp/armv5te/OP_APUT.S
@@ -25,4 +25,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
$store r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_APUT_OBJECT.S b/vm/mterp/armv5te/OP_APUT_OBJECT.S
index c99ac2e..e926db6 100644
--- a/vm/mterp/armv5te/OP_APUT_OBJECT.S
+++ b/vm/mterp/armv5te/OP_APUT_OBJECT.S
@@ -36,9 +36,15 @@
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
+ add r10, #offArrayObject_contents @ r0<- pointer to slot
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r9, [r10] @ vBB[vCC]<- vAA
+ strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
+ GOTO_OPCODE(ip) @ jump to next instruction
.L${opcode}_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_APUT_WIDE.S b/vm/mterp/armv5te/OP_APUT_WIDE.S
index 48738cc..cc9f332 100644
--- a/vm/mterp/armv5te/OP_APUT_WIDE.S
+++ b/vm/mterp/armv5te/OP_APUT_WIDE.S
@@ -30,4 +30,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
strd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_ARRAY_LENGTH.S b/vm/mterp/armv5te/OP_ARRAY_LENGTH.S
index 5dc0f93..3a6faf3 100644
--- a/vm/mterp/armv5te/OP_ARRAY_LENGTH.S
+++ b/vm/mterp/armv5te/OP_ARRAY_LENGTH.S
@@ -13,4 +13,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CHECK_CAST.S b/vm/mterp/armv5te/OP_CHECK_CAST.S
index 74f458b..c711276 100644
--- a/vm/mterp/armv5te/OP_CHECK_CAST.S
+++ b/vm/mterp/armv5te/OP_CHECK_CAST.S
@@ -70,4 +70,3 @@
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
-
diff --git a/vm/mterp/armv5te/OP_CMPL_DOUBLE.S b/vm/mterp/armv5te/OP_CMPL_DOUBLE.S
index 50ff3f7..01a63f7 100644
--- a/vm/mterp/armv5te/OP_CMPL_DOUBLE.S
+++ b/vm/mterp/armv5te/OP_CMPL_DOUBLE.S
@@ -46,4 +46,3 @@
bcc .L${opcode}_finish
$naninst @ r1<- 1 or -1 for NaN
b .L${opcode}_finish
-
diff --git a/vm/mterp/armv5te/OP_CMPL_FLOAT.S b/vm/mterp/armv5te/OP_CMPL_FLOAT.S
index c53d419..657f0dc 100644
--- a/vm/mterp/armv5te/OP_CMPL_FLOAT.S
+++ b/vm/mterp/armv5te/OP_CMPL_FLOAT.S
@@ -113,4 +113,3 @@
b ${opcode}_finish
#endif
-
diff --git a/vm/mterp/armv5te/OP_CMP_LONG.S b/vm/mterp/armv5te/OP_CMP_LONG.S
index d456137..084a3f2 100644
--- a/vm/mterp/armv5te/OP_CMP_LONG.S
+++ b/vm/mterp/armv5te/OP_CMP_LONG.S
@@ -58,4 +58,3 @@
SET_VREG(r1, r9) @ vAA<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST.S b/vm/mterp/armv5te/OP_CONST.S
index 4394647..a813c52 100644
--- a/vm/mterp/armv5te/OP_CONST.S
+++ b/vm/mterp/armv5te/OP_CONST.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_16.S b/vm/mterp/armv5te/OP_CONST_16.S
index 0b44c99..b5654a3 100644
--- a/vm/mterp/armv5te/OP_CONST_16.S
+++ b/vm/mterp/armv5te/OP_CONST_16.S
@@ -6,4 +6,3 @@
SET_VREG(r0, r3) @ vAA<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_4.S b/vm/mterp/armv5te/OP_CONST_4.S
index 9ac53c2..6dd53af 100644
--- a/vm/mterp/armv5te/OP_CONST_4.S
+++ b/vm/mterp/armv5te/OP_CONST_4.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_CLASS.S b/vm/mterp/armv5te/OP_CONST_CLASS.S
index b834553..665e582 100644
--- a/vm/mterp/armv5te/OP_CONST_CLASS.S
+++ b/vm/mterp/armv5te/OP_CONST_CLASS.S
@@ -33,4 +33,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_HIGH16.S b/vm/mterp/armv5te/OP_CONST_HIGH16.S
index 07b5061..4536d3a 100644
--- a/vm/mterp/armv5te/OP_CONST_HIGH16.S
+++ b/vm/mterp/armv5te/OP_CONST_HIGH16.S
@@ -7,4 +7,3 @@
SET_VREG(r0, r3) @ vAA<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_STRING.S b/vm/mterp/armv5te/OP_CONST_STRING.S
index 5e2e389..2df3fda 100644
--- a/vm/mterp/armv5te/OP_CONST_STRING.S
+++ b/vm/mterp/armv5te/OP_CONST_STRING.S
@@ -32,4 +32,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S b/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S
index b98e0e1..cf9b009 100644
--- a/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S
+++ b/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S
@@ -34,4 +34,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE.S b/vm/mterp/armv5te/OP_CONST_WIDE.S
index 428d423..b724264 100644
--- a/vm/mterp/armv5te/OP_CONST_WIDE.S
+++ b/vm/mterp/armv5te/OP_CONST_WIDE.S
@@ -12,4 +12,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE_16.S b/vm/mterp/armv5te/OP_CONST_WIDE_16.S
index 2d37d58..e3e4149 100644
--- a/vm/mterp/armv5te/OP_CONST_WIDE_16.S
+++ b/vm/mterp/armv5te/OP_CONST_WIDE_16.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE_32.S b/vm/mterp/armv5te/OP_CONST_WIDE_32.S
index 5991eb4..a86e042 100644
--- a/vm/mterp/armv5te/OP_CONST_WIDE_32.S
+++ b/vm/mterp/armv5te/OP_CONST_WIDE_32.S
@@ -10,4 +10,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S b/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S
index 2e23f79..11bf518 100644
--- a/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S
+++ b/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S
@@ -9,4 +9,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S b/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
index 2cf88f0..3e0a26b 100644
--- a/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
@@ -52,4 +52,3 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
#endif
-
diff --git a/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S b/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
index 563027d..ff0fd2e 100644
--- a/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
@@ -51,4 +51,3 @@
1:
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
index 550bb83..f7ca704 100644
--- a/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
+++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
@@ -58,4 +58,3 @@
.L${opcode}_table:
.word gDvmInlineOpsTable
-
diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
index 4d62019..cf8b151 100644
--- a/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
+++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
@@ -53,4 +53,3 @@
.L${opcode}_table:
.word gDvmInlineOpsTable
-
diff --git a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
index a9c2d3e..b9abe5a 100644
--- a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
+++ b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
@@ -33,15 +33,15 @@
.L${opcode}_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if $isrange
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .L${opcode}_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -49,7 +49,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -81,8 +82,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -100,4 +106,3 @@
.L_strInternalError:
.word .LstrInternalError
.endif
-
diff --git a/vm/mterp/armv5te/OP_FLOAT_TO_INT.S b/vm/mterp/armv5te/OP_FLOAT_TO_INT.S
index e5f0ef5..c9cb957 100644
--- a/vm/mterp/armv5te/OP_FLOAT_TO_INT.S
+++ b/vm/mterp/armv5te/OP_FLOAT_TO_INT.S
@@ -38,4 +38,3 @@
bl __aeabi_f2iz @ convert float to int
ldmfd sp!, {r4, pc}
#endif
-
diff --git a/vm/mterp/armv5te/OP_FLOAT_TO_LONG.S b/vm/mterp/armv5te/OP_FLOAT_TO_LONG.S
index 19f7b96..e42e1a4 100644
--- a/vm/mterp/armv5te/OP_FLOAT_TO_LONG.S
+++ b/vm/mterp/armv5te/OP_FLOAT_TO_LONG.S
@@ -38,4 +38,3 @@
mov r0, r4 @ recover arg
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
diff --git a/vm/mterp/armv5te/OP_GOTO_16.S b/vm/mterp/armv5te/OP_GOTO_16.S
index f738a98..5a8edee 100644
--- a/vm/mterp/armv5te/OP_GOTO_16.S
+++ b/vm/mterp/armv5te/OP_GOTO_16.S
@@ -22,4 +22,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
diff --git a/vm/mterp/armv5te/OP_IGET.S b/vm/mterp/armv5te/OP_IGET.S
index a347e5c..b9cdee4 100644
--- a/vm/mterp/armv5te/OP_IGET.S
+++ b/vm/mterp/armv5te/OP_IGET.S
@@ -1,4 +1,4 @@
-%default { "load":"ldr", "sqnum":"0" }
+%default { "load":"ldr", "barrier":"@ no-op ", "sqnum":"0" }
%verify "executed"
%verify "null object"
%verify "field already resolved"
@@ -38,10 +38,10 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
$load r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ $barrier @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..acf9ac0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IGET_QUICK.S b/vm/mterp/armv5te/OP_IGET_QUICK.S
index f248bc2..c19f870 100644
--- a/vm/mterp/armv5te/OP_IGET_QUICK.S
+++ b/vm/mterp/armv5te/OP_IGET_QUICK.S
@@ -14,4 +14,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IGET_VOLATILE.S b/vm/mterp/armv5te/OP_IGET_VOLATILE.S
new file mode 100644
index 0000000..acf9ac0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE.S b/vm/mterp/armv5te/OP_IGET_WIDE.S
index 22377d9..95944de 100644
--- a/vm/mterp/armv5te/OP_IGET_WIDE.S
+++ b/vm/mterp/armv5te/OP_IGET_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "null object"
%verify "field already resolved"
@@ -33,12 +34,16 @@
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
- mov r2, rINST, lsr #8 @ r2<- A+
+ .if $volatile
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
- and r2, r2, #15 @ r2<- A
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE_QUICK.S b/vm/mterp/armv5te/OP_IGET_WIDE_QUICK.S
index 189b683..b32e429 100644
--- a/vm/mterp/armv5te/OP_IGET_WIDE_QUICK.S
+++ b/vm/mterp/armv5te/OP_IGET_WIDE_QUICK.S
@@ -14,4 +14,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..face363
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_INSTANCE_OF.S b/vm/mterp/armv5te/OP_INSTANCE_OF.S
index da9f450..66f0df3 100644
--- a/vm/mterp/armv5te/OP_INSTANCE_OF.S
+++ b/vm/mterp/armv5te/OP_INSTANCE_OF.S
@@ -83,4 +83,3 @@
GET_VREG(r0, r3) @ r0<- vB (object)
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .L${opcode}_resolved @ pick up where we left off
-
diff --git a/vm/mterp/armv5te/OP_INVOKE_DIRECT.S b/vm/mterp/armv5te/OP_INVOKE_DIRECT.S
index c8d551c..14ba8f7 100644
--- a/vm/mterp/armv5te/OP_INVOKE_DIRECT.S
+++ b/vm/mterp/armv5te/OP_INVOKE_DIRECT.S
@@ -45,4 +45,3 @@
GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
bne .L${opcode}_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
diff --git a/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S b/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S
index 5463d5c..7d52454 100644
--- a/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S
+++ b/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S
@@ -24,5 +24,4 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethod${routine} @ jump to common handler
-
+ b common_invokeMethod${routine} @ jump to common handler
diff --git a/vm/mterp/armv5te/OP_INVOKE_STATIC.S b/vm/mterp/armv5te/OP_INVOKE_STATIC.S
index 57d337b..cb359e6 100644
--- a/vm/mterp/armv5te/OP_INVOKE_STATIC.S
+++ b/vm/mterp/armv5te/OP_INVOKE_STATIC.S
@@ -22,4 +22,3 @@
cmp r0, #0 @ got null?
bne common_invokeMethod${routine} @ no, continue
b common_exceptionThrown @ yes, handle exception
-
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER.S b/vm/mterp/armv5te/OP_INVOKE_SUPER.S
index f24f690..6117947 100644
--- a/vm/mterp/armv5te/OP_INVOKE_SUPER.S
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER.S
@@ -58,4 +58,3 @@
.L${opcode}_nsm:
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S
index 90b2a91..bd07d06 100644
--- a/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S
@@ -23,4 +23,3 @@
ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethod${routine} @ continue on
-
diff --git a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S
index 33dc108..d92c6a9 100644
--- a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S
+++ b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S
@@ -43,4 +43,3 @@
ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethod${routine} @ continue on
-
diff --git a/vm/mterp/armv5te/OP_IPUT.S b/vm/mterp/armv5te/OP_IPUT.S
index 35c139f..53f4b4e 100644
--- a/vm/mterp/armv5te/OP_IPUT.S
+++ b/vm/mterp/armv5te/OP_IPUT.S
@@ -1,4 +1,4 @@
-%default { "store":"str", "sqnum":"0" }
+%default { "store":"str", "barrier":"@ no-op ", "sqnum":"0" }
%verify "executed"
%verify "null object"
%verify "field already resolved"
@@ -7,7 +7,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -42,6 +42,6 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ $barrier @ releasing store
$store r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT.S b/vm/mterp/armv5te/OP_IPUT_OBJECT.S
index 7a4d936..5e0fe83 100644
--- a/vm/mterp/armv5te/OP_IPUT_OBJECT.S
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT.S
@@ -1,2 +1,51 @@
+%default { "barrier":"@ no-op ", "sqnum":"0" }
%verify "executed"
-%include "armv5te/OP_IPUT.S"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .L${opcode}_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .L${opcode}_finish @ yes, finish up
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.L${opcode}_finish:
+ @bl common_squeak${sqnum}
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ $barrier @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
index 6838faf..648a69c 100644
--- a/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
@@ -1,2 +1,19 @@
%verify "executed"
-%include "armv5te/OP_IPUT_QUICK.S"
+%verify "null object"
+ /* For: iput-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
+ FETCH(r1, 1) @ r1<- field byte offset
+ cmp r3, #0 @ check object for null
+ mov r2, rINST, lsr #8 @ r2<- A(+)
+ beq common_errNullObject @ object was null
+ and r2, r2, #15
+ GET_VREG(r0, r2) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
+ cmp r0, #0
+ strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..b4d24e7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_OBJECT.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_QUICK.S b/vm/mterp/armv5te/OP_IPUT_QUICK.S
index c33a738..ad76eca 100644
--- a/vm/mterp/armv5te/OP_IPUT_QUICK.S
+++ b/vm/mterp/armv5te/OP_IPUT_QUICK.S
@@ -1,6 +1,6 @@
%verify "executed"
%verify "null object"
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -14,4 +14,3 @@
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IPUT_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_VOLATILE.S
new file mode 100644
index 0000000..ba3f615
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE.S b/vm/mterp/armv5te/OP_IPUT_WIDE.S
index 75465ec..8796cbb 100644
--- a/vm/mterp/armv5te/OP_IPUT_WIDE.S
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "null object"
%verify "field already resolved"
@@ -35,7 +36,11 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
- GOTO_OPCODE(ip) @ jump to next instruction
-
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if $volatile
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S b/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S
index 290591c..b7dd703 100644
--- a/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S
@@ -14,4 +14,3 @@
strd r0, [r2, r3] @ obj.field (64 bits, aligned)<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..944811b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_MONITOR_ENTER.S b/vm/mterp/armv5te/OP_MONITOR_ENTER.S
index 524621a..36faabc 100644
--- a/vm/mterp/armv5te/OP_MONITOR_ENTER.S
+++ b/vm/mterp/armv5te/OP_MONITOR_ENTER.S
@@ -20,4 +20,3 @@
#endif
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MONITOR_EXIT.S b/vm/mterp/armv5te/OP_MONITOR_EXIT.S
index c9aedf0..5c1b3c7 100644
--- a/vm/mterp/armv5te/OP_MONITOR_EXIT.S
+++ b/vm/mterp/armv5te/OP_MONITOR_EXIT.S
@@ -24,4 +24,3 @@
1:
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
-
diff --git a/vm/mterp/armv5te/OP_MOVE.S b/vm/mterp/armv5te/OP_MOVE.S
index 48db45f..efeddf4 100644
--- a/vm/mterp/armv5te/OP_MOVE.S
+++ b/vm/mterp/armv5te/OP_MOVE.S
@@ -9,4 +9,3 @@
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_16.S b/vm/mterp/armv5te/OP_MOVE_16.S
index f20f57b..3c08759 100644
--- a/vm/mterp/armv5te/OP_MOVE_16.S
+++ b/vm/mterp/armv5te/OP_MOVE_16.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S b/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S
index 45e66fa..f9e4cff 100644
--- a/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S
+++ b/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S
@@ -9,4 +9,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_FROM16.S b/vm/mterp/armv5te/OP_MOVE_FROM16.S
index fe54374..fdcc64e 100644
--- a/vm/mterp/armv5te/OP_MOVE_FROM16.S
+++ b/vm/mterp/armv5te/OP_MOVE_FROM16.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_RESULT.S b/vm/mterp/armv5te/OP_MOVE_RESULT.S
index d19de23..9de8401 100644
--- a/vm/mterp/armv5te/OP_MOVE_RESULT.S
+++ b/vm/mterp/armv5te/OP_MOVE_RESULT.S
@@ -7,4 +7,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S b/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S
index 7bb8254..92f7443 100644
--- a/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S
+++ b/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE.S b/vm/mterp/armv5te/OP_MOVE_WIDE.S
index 6bcc89a..05151e1 100644
--- a/vm/mterp/armv5te/OP_MOVE_WIDE.S
+++ b/vm/mterp/armv5te/OP_MOVE_WIDE.S
@@ -11,4 +11,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE_16.S b/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
index 88d996f..172ef03 100644
--- a/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
+++ b/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
@@ -10,4 +10,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S b/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S
index 0771dbc..81ae7dc 100644
--- a/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S
+++ b/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S
@@ -10,4 +10,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MUL_LONG.S b/vm/mterp/armv5te/OP_MUL_LONG.S
index b812ca1..3a7aac1 100644
--- a/vm/mterp/armv5te/OP_MUL_LONG.S
+++ b/vm/mterp/armv5te/OP_MUL_LONG.S
@@ -39,4 +39,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_MUL_LONG_2ADDR.S b/vm/mterp/armv5te/OP_MUL_LONG_2ADDR.S
index 4c1bcb8..a561dc9 100644
--- a/vm/mterp/armv5te/OP_MUL_LONG_2ADDR.S
+++ b/vm/mterp/armv5te/OP_MUL_LONG_2ADDR.S
@@ -24,4 +24,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_NEW_ARRAY.S b/vm/mterp/armv5te/OP_NEW_ARRAY.S
index 55fc4f3..da93c45 100644
--- a/vm/mterp/armv5te/OP_NEW_ARRAY.S
+++ b/vm/mterp/armv5te/OP_NEW_ARRAY.S
@@ -59,4 +59,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_NEW_INSTANCE.S b/vm/mterp/armv5te/OP_NEW_INSTANCE.S
index 639d9c6..2687e55 100644
--- a/vm/mterp/armv5te/OP_NEW_INSTANCE.S
+++ b/vm/mterp/armv5te/OP_NEW_INSTANCE.S
@@ -66,4 +66,3 @@
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
-
diff --git a/vm/mterp/armv5te/OP_NOP.S b/vm/mterp/armv5te/OP_NOP.S
index 1b72d3c..ff4cf5a 100644
--- a/vm/mterp/armv5te/OP_NOP.S
+++ b/vm/mterp/armv5te/OP_NOP.S
@@ -12,4 +12,3 @@
MTERP_ENTRY2
.fnend
#endif
-
diff --git a/vm/mterp/armv5te/OP_PACKED_SWITCH.S b/vm/mterp/armv5te/OP_PACKED_SWITCH.S
index 72e742a..941b232 100644
--- a/vm/mterp/armv5te/OP_PACKED_SWITCH.S
+++ b/vm/mterp/armv5te/OP_PACKED_SWITCH.S
@@ -32,4 +32,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
diff --git a/vm/mterp/armv5te/OP_RETURN.S b/vm/mterp/armv5te/OP_RETURN.S
index f76a223..8838182 100644
--- a/vm/mterp/armv5te/OP_RETURN.S
+++ b/vm/mterp/armv5te/OP_RETURN.S
@@ -10,4 +10,3 @@
GET_VREG(r0, r2) @ r0<- vAA
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
-
diff --git a/vm/mterp/armv5te/OP_RETURN_VOID.S b/vm/mterp/armv5te/OP_RETURN_VOID.S
index 647002d..e09ebb0 100644
--- a/vm/mterp/armv5te/OP_RETURN_VOID.S
+++ b/vm/mterp/armv5te/OP_RETURN_VOID.S
@@ -1,3 +1,2 @@
%verify "executed"
b common_returnFromMethod
-
diff --git a/vm/mterp/armv5te/OP_RETURN_WIDE.S b/vm/mterp/armv5te/OP_RETURN_WIDE.S
index 2d30792..33880de 100644
--- a/vm/mterp/armv5te/OP_RETURN_WIDE.S
+++ b/vm/mterp/armv5te/OP_RETURN_WIDE.S
@@ -10,4 +10,3 @@
ldmia r2, {r0-r1} @ r0/r1 <- vAA/vAA+1
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
-
diff --git a/vm/mterp/armv5te/OP_SGET.S b/vm/mterp/armv5te/OP_SGET.S
index 17ab26a..c803d27 100644
--- a/vm/mterp/armv5te/OP_SGET.S
+++ b/vm/mterp/armv5te/OP_SGET.S
@@ -1,3 +1,4 @@
+%default { "barrier":"@ no-op " }
%verify "executed"
%verify "field already resolved"
%verify "field not yet resolved"
@@ -16,6 +17,7 @@
beq .L${opcode}_resolve @ yes, do resolve
.L${opcode}_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ $barrier @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -35,4 +37,3 @@
cmp r0, #0 @ success?
bne .L${opcode}_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
diff --git a/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..8b9c103
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SGET_VOLATILE.S b/vm/mterp/armv5te/OP_SGET_VOLATILE.S
new file mode 100644
index 0000000..8b9c103
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SGET_WIDE.S b/vm/mterp/armv5te/OP_SGET_WIDE.S
index 1f93a2f..768b9da 100644
--- a/vm/mterp/armv5te/OP_SGET_WIDE.S
+++ b/vm/mterp/armv5te/OP_SGET_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "field already resolved"
%verify "field not yet resolved"
@@ -13,11 +14,16 @@
cmp r0, #0 @ is resolved entry null?
beq .L${opcode}_resolve @ yes, do resolve
.L${opcode}_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- ldrd r2, [r0, #offStaticField_value] @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if $volatile
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
%break
@@ -25,6 +31,8 @@
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.L${opcode}_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -34,4 +42,3 @@
cmp r0, #0 @ success?
bne .L${opcode}_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
diff --git a/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..b852348
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_SHL_LONG.S b/vm/mterp/armv5te/OP_SHL_LONG.S
index 3510565..b48ca5e 100644
--- a/vm/mterp/armv5te/OP_SHL_LONG.S
+++ b/vm/mterp/armv5te/OP_SHL_LONG.S
@@ -30,4 +30,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_SHL_LONG_2ADDR.S b/vm/mterp/armv5te/OP_SHL_LONG_2ADDR.S
index 93f8260..42a0904 100644
--- a/vm/mterp/armv5te/OP_SHL_LONG_2ADDR.S
+++ b/vm/mterp/armv5te/OP_SHL_LONG_2ADDR.S
@@ -26,4 +26,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_SHR_LONG.S b/vm/mterp/armv5te/OP_SHR_LONG.S
index c7f10aa..e6489a0 100644
--- a/vm/mterp/armv5te/OP_SHR_LONG.S
+++ b/vm/mterp/armv5te/OP_SHR_LONG.S
@@ -30,4 +30,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_SHR_LONG_2ADDR.S b/vm/mterp/armv5te/OP_SHR_LONG_2ADDR.S
index 188017f..9414ffb 100644
--- a/vm/mterp/armv5te/OP_SHR_LONG_2ADDR.S
+++ b/vm/mterp/armv5te/OP_SHR_LONG_2ADDR.S
@@ -26,4 +26,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_SPUT.S b/vm/mterp/armv5te/OP_SPUT.S
index 5236614..e709b22 100644
--- a/vm/mterp/armv5te/OP_SPUT.S
+++ b/vm/mterp/armv5te/OP_SPUT.S
@@ -1,3 +1,4 @@
+%default { "barrier":"@ no-op " }
%verify "executed"
%verify "field already resolved"
%verify "field not yet resolved"
@@ -5,7 +6,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -19,6 +20,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ $barrier @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
%break
@@ -35,4 +37,3 @@
cmp r0, #0 @ success?
bne .L${opcode}_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT.S b/vm/mterp/armv5te/OP_SPUT_OBJECT.S
index 1048982..54a04fc 100644
--- a/vm/mterp/armv5te/OP_SPUT_OBJECT.S
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT.S
@@ -1,2 +1,38 @@
+%default { "barrier":"@ no-op " }
%verify "executed"
-%include "armv5te/OP_SPUT.S"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 32-bit SPUT handler for objects
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .L${opcode}_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .L${opcode}_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+%break
+.L${opcode}_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ $barrier @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..fe12b9e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_OBJECT.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SPUT_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_VOLATILE.S
new file mode 100644
index 0000000..cfb2b27
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SPUT_WIDE.S b/vm/mterp/armv5te/OP_SPUT_WIDE.S
index a7bc5f2..330c72b 100644
--- a/vm/mterp/armv5te/OP_SPUT_WIDE.S
+++ b/vm/mterp/armv5te/OP_SPUT_WIDE.S
@@ -1,3 +1,4 @@
+%default {"volatile":"0"}
%verify "executed"
%verify "field already resolved"
%verify "field not yet resolved"
@@ -6,26 +7,33 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .L${opcode}_resolve @ yes, do resolve
-.L${opcode}_finish: @ field ptr in r0, AA in r9
+.L${opcode}_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r2, [r0, #offStaticField_value] @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if $volatile
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
%break
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.L${opcode}_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -33,6 +41,6 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .L${opcode}_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
diff --git a/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..a88de85
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_THROW.S b/vm/mterp/armv5te/OP_THROW.S
index c8c5c36..dd0a0b8 100644
--- a/vm/mterp/armv5te/OP_THROW.S
+++ b/vm/mterp/armv5te/OP_THROW.S
@@ -7,9 +7,9 @@
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
-
diff --git a/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
index 0ed928b..8bd4f35 100644
--- a/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
+++ b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
@@ -11,4 +11,3 @@
mov r1, rINST, lsr #8 @ r1<- AA
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
-
diff --git a/vm/mterp/armv5te/OP_UNUSED_E3.S b/vm/mterp/armv5te/OP_UNUSED_E3.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E3.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E4.S b/vm/mterp/armv5te/OP_UNUSED_E4.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E4.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E5.S b/vm/mterp/armv5te/OP_UNUSED_E5.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E5.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E6.S b/vm/mterp/armv5te/OP_UNUSED_E6.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E6.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E7.S b/vm/mterp/armv5te/OP_UNUSED_E7.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E7.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E8.S b/vm/mterp/armv5te/OP_UNUSED_E8.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E8.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E9.S b/vm/mterp/armv5te/OP_UNUSED_E9.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_E9.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EA.S b/vm/mterp/armv5te/OP_UNUSED_EA.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_EA.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EB.S b/vm/mterp/armv5te/OP_UNUSED_EB.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_EB.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_FC.S b/vm/mterp/armv5te/OP_UNUSED_FC.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_FC.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_FD.S b/vm/mterp/armv5te/OP_UNUSED_FD.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_FD.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_FE.S b/vm/mterp/armv5te/OP_UNUSED_FE.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_FE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_USHR_LONG.S b/vm/mterp/armv5te/OP_USHR_LONG.S
index fc14b57..d9ae338 100644
--- a/vm/mterp/armv5te/OP_USHR_LONG.S
+++ b/vm/mterp/armv5te/OP_USHR_LONG.S
@@ -30,4 +30,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/OP_USHR_LONG_2ADDR.S b/vm/mterp/armv5te/OP_USHR_LONG_2ADDR.S
index 18167e3..27592a4 100644
--- a/vm/mterp/armv5te/OP_USHR_LONG_2ADDR.S
+++ b/vm/mterp/armv5te/OP_USHR_LONG_2ADDR.S
@@ -26,4 +26,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv5te/bincmp.S b/vm/mterp/armv5te/bincmp.S
index 1f43918..58f9079 100644
--- a/vm/mterp/armv5te/bincmp.S
+++ b/vm/mterp/armv5te/bincmp.S
@@ -29,4 +29,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
diff --git a/vm/mterp/armv5te/binop.S b/vm/mterp/armv5te/binop.S
index 0f085dc..d169ed6 100644
--- a/vm/mterp/armv5te/binop.S
+++ b/vm/mterp/armv5te/binop.S
@@ -33,4 +33,3 @@
SET_VREG($result, r9) @ vAA<- $result
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
-
diff --git a/vm/mterp/armv5te/binop2addr.S b/vm/mterp/armv5te/binop2addr.S
index 27afdda..061242a 100644
--- a/vm/mterp/armv5te/binop2addr.S
+++ b/vm/mterp/armv5te/binop2addr.S
@@ -31,4 +31,3 @@
SET_VREG($result, r9) @ vAA<- $result
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
-
diff --git a/vm/mterp/armv5te/binopLit16.S b/vm/mterp/armv5te/binopLit16.S
index 3cb1875..df49929 100644
--- a/vm/mterp/armv5te/binopLit16.S
+++ b/vm/mterp/armv5te/binopLit16.S
@@ -28,4 +28,3 @@
SET_VREG($result, r9) @ vAA<- $result
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
-
diff --git a/vm/mterp/armv5te/binopLit8.S b/vm/mterp/armv5te/binopLit8.S
index 4406259..2addd26 100644
--- a/vm/mterp/armv5te/binopLit8.S
+++ b/vm/mterp/armv5te/binopLit8.S
@@ -30,4 +30,3 @@
SET_VREG($result, r9) @ vAA<- $result
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
-
diff --git a/vm/mterp/armv5te/binopWide.S b/vm/mterp/armv5te/binopWide.S
index 87c5f07..71fd3fe 100644
--- a/vm/mterp/armv5te/binopWide.S
+++ b/vm/mterp/armv5te/binopWide.S
@@ -36,4 +36,3 @@
stmia r9, {$result0,$result1} @ vAA/vAA+1<- $result0/$result1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
-
diff --git a/vm/mterp/armv5te/binopWide2addr.S b/vm/mterp/armv5te/binopWide2addr.S
index 98c6c98..3fd5747 100644
--- a/vm/mterp/armv5te/binopWide2addr.S
+++ b/vm/mterp/armv5te/binopWide2addr.S
@@ -33,4 +33,3 @@
stmia r9, {$result0,$result1} @ vAA/vAA+1<- $result0/$result1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
-
diff --git a/vm/mterp/armv5te/debug.c b/vm/mterp/armv5te/debug.c
index 9d7413c..9f893fe 100644
--- a/vm/mterp/armv5te/debug.c
+++ b/vm/mterp/armv5te/debug.c
@@ -18,15 +18,15 @@
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
- extern char dvmAsmInstructionStart[];
+ //extern char dvmAsmInstructionStart[];
printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
printf(" : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
rPC, rFP, rGLUE, rINST);
printf(" : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
- MterpGlue* glue = (MterpGlue*) rGLUE;
- const Method* method = glue->method;
+ //MterpGlue* glue = (MterpGlue*) rGLUE;
+ //const Method* method = glue->method;
printf(" + self is %p\n", dvmThreadSelf());
//printf(" + currently in %s.%s %s\n",
// method->clazz->descriptor, method->name, method->shorty);
diff --git a/vm/mterp/armv5te/entry.S b/vm/mterp/armv5te/entry.S
index 99e2366..eddac53 100644
--- a/vm/mterp/armv5te/entry.S
+++ b/vm/mterp/armv5te/entry.S
@@ -68,14 +68,27 @@
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -148,4 +161,3 @@
*/
strBadEntryPoint:
.word .LstrBadEntryPoint
-
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index cf797de..3212126 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -27,12 +27,21 @@
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -41,7 +50,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -50,7 +59,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -59,7 +68,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -68,7 +77,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -83,7 +92,7 @@
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
@@ -124,7 +133,7 @@
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -133,9 +142,9 @@
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -147,6 +156,7 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
+ add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
@@ -190,7 +200,8 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
-#ifdef JIT_STATS
+ add rINST,#-4 @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
@@ -210,9 +221,32 @@
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -237,6 +271,7 @@
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -357,6 +392,11 @@
/*
* Common code when a backward branch is taken.
*
+ * TODO: we could avoid a branch by just setting r0 and falling through
+ * into the common_periodicChecks code, and having a test on r0 at the
+ * end determine if we should return to the caller or update & branch to
+ * the next instr.
+ *
* On entry:
* r9 is PC adjustment *in bytes*
*/
@@ -379,23 +419,25 @@
/*
* Need to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
+ * activity has begun. If so, we suspend the thread or side-exit to
+ * the debug interpreter as appropriate.
*
- * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
- * have to do the second ldr.
+ * The common case is no activity on any of these, so we want to figure
+ * that out quickly. If something is up, we can then sort out what.
+ *
+ * We want to be fast if the VM was built without debugger or profiler
+ * support, but we also need to recognize that the system is usually
+ * shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
- * r0 is reentry type, e.g. kInterpEntryInstr
+ * r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
- @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
- str r0, [rGLUE, #offGlue_entryPoint]
-
#if defined(WITH_DEBUGGER)
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
#endif
@@ -403,33 +445,42 @@
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
#endif
- ldr r3, [r3] @ r3<- suspendCount (int)
+ ldr ip, [r3] @ ip<- suspendCount (int)
-#if defined(WITH_DEBUGGER)
- ldrb r1, [r1] @ r1<- debuggerActive (boolean)
-#endif
-#if defined (WITH_PROFILER)
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
+ orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
+#elif defined(WITH_DEBUGGER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+ orrsne ip, ip, r1 @ yes, ip<- suspend | debugger; set Z
+ @ (if not enabled, Z was set by test for r1==0, which is what we want)
+#elif defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrs ip, ip, r2 @ ip<- suspendCount | activeProfilers
+#else
+ cmp ip, #0 @ not ORing anything in; set Z
#endif
- cmp r3, #0 @ suspend pending?
- bne 2f @ yes, do full suspension check
+ bxeq lr @ all zero, return
+ /*
+ * One or more interesting events have happened. Figure out what.
+ *
+ * If debugging or profiling are compiled in, we need to disambiguate.
+ *
+ * r0 still holds the reentry type.
+ */
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
-# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
- orrs r1, r1, r2 @ r1<- r1 | r2
- cmp r1, #0 @ debugger attached or profiler started?
-# elif defined(WITH_DEBUGGER)
- cmp r1, #0 @ debugger attached?
-# elif defined(WITH_PROFILER)
- cmp r2, #0 @ profiler started?
-# endif
- bne 3f @ debugger/profiler, switch interp
+ ldr ip, [r3] @ ip<- suspendCount (int)
+ cmp ip, #0 @ want suspend?
+ beq 1f @ no, must be debugger/profiler
#endif
- bx lr @ nothing to do, return
-
-2: @ check suspend
+ stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
@@ -444,12 +495,45 @@
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
- b dvmCheckSuspendPending @ suspend if necessary, then return
+ bl dvmCheckSuspendPending @ do full check, suspend if necessary
+ ldmfd sp!, {r0, lr} @ restore r0 and lr
-3: @ debugger/profiler enabled, bail out
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+
+ /*
+ * Reload the debugger/profiler enable flags. We're checking to see
+ * if either of these got set while we were suspended.
+ *
+ * We can't really avoid the #ifdefs here, because the fields don't
+ * exist when the feature is disabled.
+ */
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+#else
+ mov r1, #0
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#else
+ mov r2, #0
+#endif
+
+ orrs r1, r1, r2
+ beq 2f
+
+1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
- b common_gotoBail
+ b common_gotoBail @ side exit
+
+#endif /*WITH_DEBUGGER || WITH_PROFILER*/
+
+2:
+ bx lr @ nothing to do, return
/*
@@ -553,7 +637,7 @@
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
- blt .LstackOverflow @ yes, this frame will overflow stack
+ blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
@@ -728,15 +812,12 @@
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
@@ -1172,4 +1253,3 @@
.asciz "<0x%x>"
.LstrPrintLong:
.asciz "<%lld>"
-
diff --git a/vm/mterp/armv5te/header.S b/vm/mterp/armv5te/header.S
index b6e9891..bd6b7ee 100644
--- a/vm/mterp/armv5te/header.S
+++ b/vm/mterp/armv5te/header.S
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* ARMv5 definitions and declarations.
*/
diff --git a/vm/mterp/armv5te/platform.S b/vm/mterp/armv5te/platform.S
index 4e7c03e..9f59c8b 100644
--- a/vm/mterp/armv5te/platform.S
+++ b/vm/mterp/armv5te/platform.S
@@ -34,3 +34,8 @@
ldmfd sp!, {\regs,pc}
.endm
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro SMP_DMB
+.endm
diff --git a/vm/mterp/armv5te/stub.S b/vm/mterp/armv5te/stub.S
index 7607f09..54f0778 100644
--- a/vm/mterp/armv5te/stub.S
+++ b/vm/mterp/armv5te/stub.S
@@ -6,4 +6,3 @@
FETCH_INST() @ load next instruction from rPC
GET_INST_OPCODE(ip) @ ...trim down to just the opcode
GOTO_OPCODE(ip) @ ...and jump to the handler
-
diff --git a/vm/mterp/armv5te/unopWide.S b/vm/mterp/armv5te/unopWide.S
index e097317..0805fdf 100644
--- a/vm/mterp/armv5te/unopWide.S
+++ b/vm/mterp/armv5te/unopWide.S
@@ -20,4 +20,3 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-13 instructions */
-
diff --git a/vm/mterp/armv5te/unused.S b/vm/mterp/armv5te/unused.S
index 1c82919..0194f58 100644
--- a/vm/mterp/armv5te/unused.S
+++ b/vm/mterp/armv5te/unused.S
@@ -1,2 +1 @@
bl common_abort
-
diff --git a/vm/mterp/armv5te/zcmp.S b/vm/mterp/armv5te/zcmp.S
index 861ca5b..d79e7c4 100644
--- a/vm/mterp/armv5te/zcmp.S
+++ b/vm/mterp/armv5te/zcmp.S
@@ -29,4 +29,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
diff --git a/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S b/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S
index bb995e2..05991be 100644
--- a/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S
+++ b/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S
@@ -12,4 +12,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_CONST_4.S b/vm/mterp/armv6t2/OP_CONST_4.S
index 0d6092c..8ec67d7 100644
--- a/vm/mterp/armv6t2/OP_CONST_4.S
+++ b/vm/mterp/armv6t2/OP_CONST_4.S
@@ -7,4 +7,3 @@
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
diff --git a/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S b/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S
index d3882f3..f66dc5f 100644
--- a/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S
@@ -52,4 +52,3 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
#endif
-
diff --git a/vm/mterp/armv6t2/OP_DOUBLE_TO_LONG.S b/vm/mterp/armv6t2/OP_DOUBLE_TO_LONG.S
index a9ecab7..ac751de 100644
--- a/vm/mterp/armv6t2/OP_DOUBLE_TO_LONG.S
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_LONG.S
@@ -51,4 +51,3 @@
1:
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
diff --git a/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S b/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S
index 444ebae..4ba28e7 100644
--- a/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S
@@ -38,4 +38,3 @@
bl __aeabi_f2iz @ convert float to int
ldmfd sp!, {r4, pc}
#endif
-
diff --git a/vm/mterp/armv6t2/OP_FLOAT_TO_LONG.S b/vm/mterp/armv6t2/OP_FLOAT_TO_LONG.S
index 5efd04b..168e338 100644
--- a/vm/mterp/armv6t2/OP_FLOAT_TO_LONG.S
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_LONG.S
@@ -38,4 +38,3 @@
mov r0, r4 @ recover arg
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
diff --git a/vm/mterp/armv6t2/OP_IGET.S b/vm/mterp/armv6t2/OP_IGET.S
index 537c534..f5a21eb 100644
--- a/vm/mterp/armv6t2/OP_IGET.S
+++ b/vm/mterp/armv6t2/OP_IGET.S
@@ -43,4 +43,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IGET_QUICK.S b/vm/mterp/armv6t2/OP_IGET_QUICK.S
index 83714d5..0ce2ebc 100644
--- a/vm/mterp/armv6t2/OP_IGET_QUICK.S
+++ b/vm/mterp/armv6t2/OP_IGET_QUICK.S
@@ -13,4 +13,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IGET_WIDE.S b/vm/mterp/armv6t2/OP_IGET_WIDE.S
index 948d53d..92cd1a6 100644
--- a/vm/mterp/armv6t2/OP_IGET_WIDE.S
+++ b/vm/mterp/armv6t2/OP_IGET_WIDE.S
@@ -40,4 +40,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S b/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S
index 98abf72..067d40d 100644
--- a/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S
+++ b/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S
@@ -13,4 +13,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IPUT.S b/vm/mterp/armv6t2/OP_IPUT.S
index 10eea24..b69443b 100644
--- a/vm/mterp/armv6t2/OP_IPUT.S
+++ b/vm/mterp/armv6t2/OP_IPUT.S
@@ -43,4 +43,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
$store r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IPUT_QUICK.S b/vm/mterp/armv6t2/OP_IPUT_QUICK.S
index 0b6d61c..ad87b55 100644
--- a/vm/mterp/armv6t2/OP_IPUT_QUICK.S
+++ b/vm/mterp/armv6t2/OP_IPUT_QUICK.S
@@ -13,4 +13,3 @@
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IPUT_WIDE.S b/vm/mterp/armv6t2/OP_IPUT_WIDE.S
index 5c1ab97..334e352 100644
--- a/vm/mterp/armv6t2/OP_IPUT_WIDE.S
+++ b/vm/mterp/armv6t2/OP_IPUT_WIDE.S
@@ -37,4 +37,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_IPUT_WIDE_QUICK.S b/vm/mterp/armv6t2/OP_IPUT_WIDE_QUICK.S
index 5cf4798..09f7a8e 100644
--- a/vm/mterp/armv6t2/OP_IPUT_WIDE_QUICK.S
+++ b/vm/mterp/armv6t2/OP_IPUT_WIDE_QUICK.S
@@ -13,4 +13,3 @@
strd r0, [r2, r3] @ obj.field (64 bits, aligned)<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_MOVE.S b/vm/mterp/armv6t2/OP_MOVE.S
index 0c11d1a..3047158 100644
--- a/vm/mterp/armv6t2/OP_MOVE.S
+++ b/vm/mterp/armv6t2/OP_MOVE.S
@@ -8,4 +8,3 @@
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
diff --git a/vm/mterp/armv6t2/OP_MOVE_WIDE.S b/vm/mterp/armv6t2/OP_MOVE_WIDE.S
index c896e62..adc2c95 100644
--- a/vm/mterp/armv6t2/OP_MOVE_WIDE.S
+++ b/vm/mterp/armv6t2/OP_MOVE_WIDE.S
@@ -10,4 +10,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S
index c050ecc..1526a1e 100644
--- a/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S
+++ b/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S
@@ -23,4 +23,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S
index bad569a..502481e 100644
--- a/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S
+++ b/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S
@@ -25,4 +25,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S
index fa77b61..501b3f2 100644
--- a/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S
+++ b/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S
@@ -25,4 +25,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S
index 1183d1f..a1fcef4 100644
--- a/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S
+++ b/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S
@@ -25,4 +25,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
diff --git a/vm/mterp/armv6t2/bincmp.S b/vm/mterp/armv6t2/bincmp.S
index f3b81b0..002eeed 100644
--- a/vm/mterp/armv6t2/bincmp.S
+++ b/vm/mterp/armv6t2/bincmp.S
@@ -28,4 +28,3 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
diff --git a/vm/mterp/armv6t2/binop2addr.S b/vm/mterp/armv6t2/binop2addr.S
index 9b421bc..b402156 100644
--- a/vm/mterp/armv6t2/binop2addr.S
+++ b/vm/mterp/armv6t2/binop2addr.S
@@ -30,4 +30,3 @@
SET_VREG($result, r9) @ vAA<- $result
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
-
diff --git a/vm/mterp/armv6t2/binopLit16.S b/vm/mterp/armv6t2/binopLit16.S
index 7bc9902..1f67524 100644
--- a/vm/mterp/armv6t2/binopLit16.S
+++ b/vm/mterp/armv6t2/binopLit16.S
@@ -27,4 +27,3 @@
SET_VREG($result, r9) @ vAA<- $result
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
-
diff --git a/vm/mterp/armv6t2/binopWide2addr.S b/vm/mterp/armv6t2/binopWide2addr.S
index af83c7b..0b4691f 100644
--- a/vm/mterp/armv6t2/binopWide2addr.S
+++ b/vm/mterp/armv6t2/binopWide2addr.S
@@ -32,4 +32,3 @@
stmia r9, {$result0,$result1} @ vAA/vAA+1<- $result0/$result1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
-
diff --git a/vm/mterp/armv6t2/unopWide.S b/vm/mterp/armv6t2/unopWide.S
index 62d8645..e0a303e 100644
--- a/vm/mterp/armv6t2/unopWide.S
+++ b/vm/mterp/armv6t2/unopWide.S
@@ -19,4 +19,3 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-11 instructions */
-
diff --git a/vm/mterp/armv7-a/platform.S b/vm/mterp/armv7-a/platform.S
new file mode 100644
index 0000000..6419da1
--- /dev/null
+++ b/vm/mterp/armv7-a/platform.S
@@ -0,0 +1,51 @@
+/*
+ * ===========================================================================
+ * CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * Macro for "LDR PC,xxx", which is not allowed pre-ARMv5. Essentially a
+ * one-way branch.
+ *
+ * May modify IP. Does not modify LR.
+ */
+.macro LDR_PC source
+ ldr pc, \source
+.endm
+
+/*
+ * 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
+
+/*
+ * Macro for "LDMFD SP!, {...regs...,PC}".
+ *
+ * May modify IP and LR.
+ */
+.macro LDMFD_PC regs
+ ldmfd sp!, {\regs,pc}
+.endm
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ * If the argument is nonzero, emit barrier; otherwise, emit nothing.
+ */
+.macro SMP_DMB
+#if ANDROID_SMP != 0
+ dmb
+#else
+ /* not SMP */
+#endif
+.endm
diff --git a/vm/mterp/c/OP_APUT_OBJECT.c b/vm/mterp/c/OP_APUT_OBJECT.c
index cc87f5d..07e48c6 100644
--- a/vm/mterp/c/OP_APUT_OBJECT.c
+++ b/vm/mterp/c/OP_APUT_OBJECT.c
@@ -32,8 +32,9 @@
}
}
ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
- ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
- GET_REGISTER(vdst);
+ dvmSetObjectArrayElement(arrayObj,
+ GET_REGISTER(vsrc2),
+ (Object *)GET_REGISTER(vdst));
}
FINISH(2);
OP_END
diff --git a/vm/mterp/c/OP_FILL_ARRAY_DATA.c b/vm/mterp/c/OP_FILL_ARRAY_DATA.c
index 157d3fc..095b465 100644
--- a/vm/mterp/c/OP_FILL_ARRAY_DATA.c
+++ b/vm/mterp/c/OP_FILL_ARRAY_DATA.c
@@ -14,7 +14,7 @@
arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
{
/* should have been caught in verifier */
- dvmThrowException("Ljava/lang/InternalError;",
+ dvmThrowException("Ljava/lang/InternalError;",
"bad fill array data");
GOTO_exceptionThrown();
}
diff --git a/vm/mterp/c/OP_IGET_OBJECT_VOLATILE.c b/vm/mterp/c/OP_IGET_OBJECT_VOLATILE.c
new file mode 100644
index 0000000..3577552
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_OBJECT_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_VOLATILE.c b/vm/mterp/c/OP_IGET_VOLATILE.c
new file mode 100644
index 0000000..7a3be56
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_VOLATILE, "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_WIDE_VOLATILE.c b/vm/mterp/c/OP_IGET_WIDE_VOLATILE.c
new file mode 100644
index 0000000..a080823
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_WIDE_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE.c b/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE.c
new file mode 100644
index 0000000..cce63c1
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_VOLATILE.c b/vm/mterp/c/OP_IPUT_VOLATILE.c
new file mode 100644
index 0000000..814379e
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_VOLATILE, "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_WIDE_VOLATILE.c b/vm/mterp/c/OP_IPUT_WIDE_VOLATILE.c
new file mode 100644
index 0000000..d888b4a
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_WIDE_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_NEW_ARRAY.c b/vm/mterp/c/OP_NEW_ARRAY.c
index 22af516..525c43b 100644
--- a/vm/mterp/c/OP_NEW_ARRAY.c
+++ b/vm/mterp/c/OP_NEW_ARRAY.c
@@ -33,4 +33,3 @@
}
FINISH(2);
OP_END
-
diff --git a/vm/mterp/c/OP_NEW_INSTANCE.c b/vm/mterp/c/OP_NEW_INSTANCE.c
index ce04286..f7d4c64 100644
--- a/vm/mterp/c/OP_NEW_INSTANCE.c
+++ b/vm/mterp/c/OP_NEW_INSTANCE.c
@@ -19,6 +19,16 @@
GOTO_exceptionThrown();
/*
+ * The JIT needs dvmDexGetResolvedClass() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (!dvmDexGetResolvedClass(methodClassDex, ref)) {
+ /* Class initialization is still ongoing - abandon the trace */
+ ABORT_JIT_TSELECT();
+ }
+
+ /*
* Verifier now tests for interface/abstract class.
*/
//if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
diff --git a/vm/mterp/c/OP_SGET_OBJECT_VOLATILE.c b/vm/mterp/c/OP_SGET_OBJECT_VOLATILE.c
new file mode 100644
index 0000000..0a9049f
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_OBJECT_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_VOLATILE.c b/vm/mterp/c/OP_SGET_VOLATILE.c
new file mode 100644
index 0000000..6713a54
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_VOLATILE, "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_WIDE_VOLATILE.c b/vm/mterp/c/OP_SGET_WIDE_VOLATILE.c
new file mode 100644
index 0000000..26a67bf
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_WIDE_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE.c b/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE.c
new file mode 100644
index 0000000..38d6c0d
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_VOLATILE.c b/vm/mterp/c/OP_SPUT_VOLATILE.c
new file mode 100644
index 0000000..7899d05
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_VOLATILE, "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_WIDE_VOLATILE.c b/vm/mterp/c/OP_SPUT_WIDE_VOLATILE.c
new file mode 100644
index 0000000..bdf552c
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_WIDE_VOLATILE.c
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_THROW.c b/vm/mterp/c/OP_THROW.c
index 9a56040..0dcaced 100644
--- a/vm/mterp/c/OP_THROW.c
+++ b/vm/mterp/c/OP_THROW.c
@@ -2,10 +2,17 @@
{
Object* obj;
+ /*
+ * We don't create an exception here, but the process of searching
+ * for a catch block can do class lookups and throw exceptions.
+ * We need to update the saved PC.
+ */
+ EXPORT_PC();
+
vsrc1 = INST_AA(inst);
ILOGV("|throw v%d (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
obj = (Object*) GET_REGISTER(vsrc1);
- if (!checkForNullExportPC(obj, fp, pc)) {
+ if (!checkForNull(obj)) {
/* will throw a null pointer exception */
LOGVV("Bad exception\n");
} else {
diff --git a/vm/mterp/c/OP_UNUSED_E3.c b/vm/mterp/c/OP_UNUSED_E3.c
deleted file mode 100644
index d52836b..0000000
--- a/vm/mterp/c/OP_UNUSED_E3.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E3)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E4.c b/vm/mterp/c/OP_UNUSED_E4.c
deleted file mode 100644
index 30a714f..0000000
--- a/vm/mterp/c/OP_UNUSED_E4.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E4)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E5.c b/vm/mterp/c/OP_UNUSED_E5.c
deleted file mode 100644
index 0cc6ff9..0000000
--- a/vm/mterp/c/OP_UNUSED_E5.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E5)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E6.c b/vm/mterp/c/OP_UNUSED_E6.c
deleted file mode 100644
index 255dcd1..0000000
--- a/vm/mterp/c/OP_UNUSED_E6.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E6)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E7.c b/vm/mterp/c/OP_UNUSED_E7.c
deleted file mode 100644
index b910f71..0000000
--- a/vm/mterp/c/OP_UNUSED_E7.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E7)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E8.c b/vm/mterp/c/OP_UNUSED_E8.c
deleted file mode 100644
index ba11d34..0000000
--- a/vm/mterp/c/OP_UNUSED_E8.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E8)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E9.c b/vm/mterp/c/OP_UNUSED_E9.c
deleted file mode 100644
index 6f4d8fb..0000000
--- a/vm/mterp/c/OP_UNUSED_E9.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_E9)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EA.c b/vm/mterp/c/OP_UNUSED_EA.c
deleted file mode 100644
index 8456083..0000000
--- a/vm/mterp/c/OP_UNUSED_EA.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_EA)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EB.c b/vm/mterp/c/OP_UNUSED_EB.c
deleted file mode 100644
index 3525262..0000000
--- a/vm/mterp/c/OP_UNUSED_EB.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_EB)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_FC.c b/vm/mterp/c/OP_UNUSED_FC.c
deleted file mode 100644
index 4b49684..0000000
--- a/vm/mterp/c/OP_UNUSED_FC.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_FC)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_FD.c b/vm/mterp/c/OP_UNUSED_FD.c
deleted file mode 100644
index c10efaf..0000000
--- a/vm/mterp/c/OP_UNUSED_FD.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_FD)
-OP_END
diff --git a/vm/mterp/c/OP_UNUSED_FE.c b/vm/mterp/c/OP_UNUSED_FE.c
deleted file mode 100644
index 7b097d9..0000000
--- a/vm/mterp/c/OP_UNUSED_FE.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_FE)
-OP_END
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index 534d0b0..b17fb80 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -94,6 +94,9 @@
vdst >>= 4;
}
}
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
retval.l = newArray;
}
@@ -151,6 +154,10 @@
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -302,6 +309,10 @@
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -373,6 +384,16 @@
ILOGV("+ unknown method\n");
GOTO_exceptionThrown();
}
+
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) {
+ /* Class initialization is still ongoing */
+ ABORT_JIT_TSELECT();
+ }
}
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
GOTO_TARGET_END
@@ -406,6 +427,10 @@
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
@@ -494,7 +519,6 @@
GOTO_TARGET_END
-
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
@@ -534,7 +558,7 @@
LOGVV("+++ returned into break frame\n");
#if defined(WITH_JIT)
/* Let the Jit know the return is terminating normally */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
GOTO_bail();
}
@@ -722,6 +746,7 @@
GOTO_TARGET_END
+
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
@@ -904,12 +929,14 @@
TRACE_METHOD_ENTER(self, methodToCall);
#endif
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
+ {
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+ }
#if defined(WITH_JIT)
/* Allow the Jit to end any pending trace building */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
/*
diff --git a/vm/mterp/c/opcommon.c b/vm/mterp/c/opcommon.c
index 28d03c9..43ee5bc 100644
--- a/vm/mterp/c/opcommon.c
+++ b/vm/mterp/c/opcommon.c
@@ -602,6 +602,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -615,6 +620,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -636,6 +644,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -643,4 +654,3 @@
UPDATE_FIELD_PUT(&sfield->field); \
} \
FINISH(2);
-
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index 135abfd..475b897 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -97,8 +97,33 @@
MTERP_OFFSET(offGlue_bailPtr, MterpGlue, bailPtr, 28)
MTERP_OFFSET(offGlue_interpStackEnd, MterpGlue, interpStackEnd, 32)
MTERP_OFFSET(offGlue_pSelfSuspendCount, MterpGlue, pSelfSuspendCount, 36)
+MTERP_OFFSET(offGlue_cardTable, MterpGlue, cardTable, 40)
#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
-MTERP_OFFSET(offGlue_pDebuggerActive, MterpGlue, pDebuggerActive, 40)
+MTERP_OFFSET(offGlue_pDebuggerActive, MterpGlue, pDebuggerActive, 44)
+MTERP_OFFSET(offGlue_pActiveProfilers, MterpGlue, pActiveProfilers, 48)
+MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 52)
+#if defined(WITH_JIT)
+MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 60)
+MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 64)
+MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 68)
+MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 72)
+MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 76)
+MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 80)
+MTERP_OFFSET(offGlue_icRechainCount, MterpGlue, icRechainCount, 84)
+#endif
+#elif defined(WITH_DEBUGGER)
+MTERP_OFFSET(offGlue_pDebuggerActive, MterpGlue, pDebuggerActive, 44)
+MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 48)
+#if defined(WITH_JIT)
+MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 56)
+MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 60)
+MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 64)
+MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 68)
+MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 72)
+MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 76)
+MTERP_OFFSET(offGlue_icRechainCount, MterpGlue, icRechainCount, 80)
+#endif
+#elif defined(WITH_PROFILER)
MTERP_OFFSET(offGlue_pActiveProfilers, MterpGlue, pActiveProfilers, 44)
MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 48)
#if defined(WITH_JIT)
@@ -108,38 +133,18 @@
MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 68)
MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 72)
MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 76)
-#endif
-#elif defined(WITH_DEBUGGER)
-MTERP_OFFSET(offGlue_pDebuggerActive, MterpGlue, pDebuggerActive, 40)
-MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 44)
-#if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 52)
-MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 56)
-MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 60)
-MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 64)
-MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 68)
-MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 72)
-#endif
-#elif defined(WITH_PROFILER)
-MTERP_OFFSET(offGlue_pActiveProfilers, MterpGlue, pActiveProfilers, 40)
-MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 44)
-#if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 52)
-MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 56)
-MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 60)
-MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 64)
-MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 68)
-MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 72)
+MTERP_OFFSET(offGlue_icRechainCount, MterpGlue, icRechainCount, 80)
#endif
#else
-MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 40)
+MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 44)
#if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 48)
-MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 52)
-MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 56)
-MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 60)
-MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 64)
-MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 68)
+MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 52)
+MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 56)
+MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 60)
+MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 64)
+MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 68)
+MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 72)
+MTERP_OFFSET(offGlue_icRechainCount, MterpGlue, icRechainCount, 76)
#endif
#endif
/* make sure all JValue union members are stored at the same offset */
@@ -179,12 +184,13 @@
/* ShadowSpace fields */
#if defined(WITH_JIT) && defined(WITH_SELF_VERIFICATION)
-MTERP_OFFSET(offShadowSpace_startPC, ShadowSpace, startPC, 0)
-MTERP_OFFSET(offShadowSpace_fp, ShadowSpace, fp, 4)
-MTERP_OFFSET(offShadowSpace_glue, ShadowSpace, glue, 8)
-MTERP_OFFSET(offShadowSpace_svState, ShadowSpace, selfVerificationState, 12)
-MTERP_OFFSET(offShadowSpace_shadowFP, ShadowSpace, shadowFP, 20)
-MTERP_OFFSET(offShadowSpace_interpState, ShadowSpace, interpState, 24)
+MTERP_OFFSET(offShadowSpace_startPC, ShadowSpace, startPC, 0)
+MTERP_OFFSET(offShadowSpace_fp, ShadowSpace, fp, 4)
+MTERP_OFFSET(offShadowSpace_glue, ShadowSpace, glue, 8)
+MTERP_OFFSET(offShadowSpace_jitExitState,ShadowSpace, jitExitState, 12)
+MTERP_OFFSET(offShadowSpace_svState, ShadowSpace, selfVerificationState, 16)
+MTERP_OFFSET(offShadowSpace_shadowFP, ShadowSpace, shadowFP, 24)
+MTERP_OFFSET(offShadowSpace_interpState, ShadowSpace, interpState, 32)
#endif
/* InstField fields */
@@ -221,6 +227,16 @@
#if defined(WITH_JIT)
MTERP_OFFSET(offThread_inJitCodeCache, Thread, inJitCodeCache, 76)
+#if defined(WITH_SELF_VERIFICATION)
+MTERP_OFFSET(offThread_shadowSpace, Thread, shadowSpace, 80)
+#ifdef USE_INDIRECT_REF
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+ Thread, jniLocalRefTable.segmentState.all, 84)
+#else
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+ Thread, jniLocalRefTable.nextEntry, 84)
+#endif
+#else
#ifdef USE_INDIRECT_REF
MTERP_OFFSET(offThread_jniLocal_topCookie, \
Thread, jniLocalRefTable.segmentState.all, 80)
@@ -228,6 +244,7 @@
MTERP_OFFSET(offThread_jniLocal_topCookie, \
Thread, jniLocalRefTable.nextEntry, 80)
#endif
+#endif
#else
#ifdef USE_INDIRECT_REF
MTERP_OFFSET(offThread_jniLocal_topCookie, \
@@ -308,7 +325,7 @@
MTERP_CONSTANT(kSVSStart, 1)
MTERP_CONSTANT(kSVSPunt, 2)
MTERP_CONSTANT(kSVSSingleStep, 3)
-MTERP_CONSTANT(kSVSTraceSelectNoChain, 4)
+MTERP_CONSTANT(kSVSNoProfile, 4)
MTERP_CONSTANT(kSVSTraceSelect, 5)
MTERP_CONSTANT(kSVSNormal, 6)
MTERP_CONSTANT(kSVSNoChain, 7)
@@ -336,7 +353,10 @@
MTERP_CONSTANT(ACC_ABSTRACT, 0x0400)
/* flags for dvmMalloc */
-MTERP_CONSTANT(ALLOC_DONT_TRACK, 0x02)
+MTERP_CONSTANT(ALLOC_DONT_TRACK, 0x01)
+
+/* for GC */
+MTERP_CONSTANT(GC_CARD_SHIFT, 7)
/* opcode number */
MTERP_CONSTANT(OP_MOVE_EXCEPTION, 0x0d)
diff --git a/vm/mterp/config-allstubs b/vm/mterp/config-allstubs
index 72166aa..23796d8 100644
--- a/vm/mterp/config-allstubs
+++ b/vm/mterp/config-allstubs
@@ -42,4 +42,3 @@
# finish
import cstubs/enddefs.c
-
diff --git a/vm/mterp/config-armv4t b/vm/mterp/config-armv4t
index 01eddb2..ed39b42 100644
--- a/vm/mterp/config-armv4t
+++ b/vm/mterp/config-armv4t
@@ -50,6 +50,10 @@
op OP_IPUT_WIDE_QUICK armv4t
op OP_SGET_WIDE armv4t
op OP_SPUT_WIDE armv4t
+ op OP_IGET_WIDE_VOLATILE armv4t
+ op OP_IPUT_WIDE_VOLATILE armv4t
+ op OP_SGET_WIDE_VOLATILE armv4t
+ op OP_SPUT_WIDE_VOLATILE armv4t
op-end
# "helper" code for C; include if you use any of the C stubs (this generates
@@ -62,4 +66,3 @@
# common subroutines for asm
import armv5te/footer.S
import armv5te/debug.c
-
diff --git a/vm/mterp/config-armv5te b/vm/mterp/config-armv5te
index 8b4838e..2dceb04 100644
--- a/vm/mterp/config-armv5te
+++ b/vm/mterp/config-armv5te
@@ -52,4 +52,3 @@
# common subroutines for asm
import armv5te/footer.S
import armv5te/debug.c
-
diff --git a/vm/mterp/config-armv5te-vfp b/vm/mterp/config-armv5te-vfp
index cc77002..ce0c521 100644
--- a/vm/mterp/config-armv5te-vfp
+++ b/vm/mterp/config-armv5te-vfp
@@ -102,4 +102,3 @@
# common subroutines for asm
import armv5te/footer.S
import armv5te/debug.c
-
diff --git a/vm/mterp/config-armv7-a b/vm/mterp/config-armv7-a
index 9193632..e66640c 100644
--- a/vm/mterp/config-armv7-a
+++ b/vm/mterp/config-armv7-a
@@ -34,7 +34,7 @@
import cstubs/stubdefs.c
# highly-platform-specific defs
-import armv5te/platform.S
+import armv7-a/platform.S
# common defs for the C helpers; include this before the instruction handlers
import c/opcommon.c
@@ -164,4 +164,3 @@
# common subroutines for asm
import armv5te/footer.S
import armv5te/debug.c
-
diff --git a/vm/mterp/config-armv7-a-neon b/vm/mterp/config-armv7-a-neon
index 9193632..e66640c 100644
--- a/vm/mterp/config-armv7-a-neon
+++ b/vm/mterp/config-armv7-a-neon
@@ -34,7 +34,7 @@
import cstubs/stubdefs.c
# highly-platform-specific defs
-import armv5te/platform.S
+import armv7-a/platform.S
# common defs for the C helpers; include this before the instruction handlers
import c/opcommon.c
@@ -164,4 +164,3 @@
# common subroutines for asm
import armv5te/footer.S
import armv5te/debug.c
-
diff --git a/vm/mterp/config-portdbg b/vm/mterp/config-portdbg
index 7e1de14..c6982d7 100644
--- a/vm/mterp/config-portdbg
+++ b/vm/mterp/config-portdbg
@@ -47,4 +47,3 @@
# finish
import portable/enddefs.c
-
diff --git a/vm/mterp/config-portstd b/vm/mterp/config-portstd
index fad4e68..41ecb4f 100644
--- a/vm/mterp/config-portstd
+++ b/vm/mterp/config-portstd
@@ -46,4 +46,3 @@
# finish
import portable/enddefs.c
-
diff --git a/vm/mterp/config-x86 b/vm/mterp/config-x86
index cf5adb5..627e06c 100644
--- a/vm/mterp/config-x86
+++ b/vm/mterp/config-x86
@@ -35,6 +35,10 @@
op-start x86
# stub -- need native impl
op OP_EXECUTE_INLINE_RANGE c
+ op OP_IGET_WIDE_VOLATILE c
+ op OP_IPUT_WIDE_VOLATILE c
+ op OP_SGET_WIDE_VOLATILE c
+ op OP_SPUT_WIDE_VOLATILE c
op-end
# arch-specific entry point to interpreter
@@ -50,4 +54,3 @@
# common subroutines for asm
import x86/footer.S
-
diff --git a/vm/mterp/config-x86-atom b/vm/mterp/config-x86-atom
index a8acc65..970253c 100644
--- a/vm/mterp/config-x86-atom
+++ b/vm/mterp/config-x86-atom
@@ -286,6 +286,18 @@
# TODO: provide native implementations
op OP_BREAKPOINT c
op OP_EXECUTE_INLINE_RANGE c
+op OP_IGET_VOLATILE c
+op OP_IPUT_VOLATILE c
+op OP_SGET_VOLATILE c
+op OP_SPUT_VOLATILE c
+op OP_IGET_OBJECT_VOLATILE c
+op OP_IPUT_OBJECT_VOLATILE c
+op OP_SGET_OBJECT_VOLATILE c
+op OP_SPUT_OBJECT_VOLATILE c
+op OP_IGET_WIDE_VOLATILE c
+op OP_IPUT_WIDE_VOLATILE c
+op OP_SGET_WIDE_VOLATILE c
+op OP_SPUT_WIDE_VOLATILE c
op-end
@@ -298,5 +310,3 @@
# common subroutines for asm
import x86-atom/footer.S
-
-
diff --git a/vm/mterp/cstubs/entry.c b/vm/mterp/cstubs/entry.c
index 0597d19..af31a3d 100644
--- a/vm/mterp/cstubs/entry.c
+++ b/vm/mterp/cstubs/entry.c
@@ -78,4 +78,3 @@
jmp_buf* pJmpBuf = glue->bailPtr;
longjmp(*pJmpBuf, ((int)changeInterp)+1);
}
-
diff --git a/vm/mterp/cstubs/stubdefs.c b/vm/mterp/cstubs/stubdefs.c
index ba10853..bf870c6 100644
--- a/vm/mterp/cstubs/stubdefs.c
+++ b/vm/mterp/cstubs/stubdefs.c
@@ -2,10 +2,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index 5909745..5ce80ff 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -20,6 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* ARMv5 definitions and declarations.
*/
@@ -242,6 +243,11 @@
ldmfd sp!, {\regs,pc}
.endm
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro SMP_DMB
+.endm
/* File: armv5te/entry.S */
/*
@@ -314,14 +320,27 @@
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -396,7 +415,6 @@
.word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
@@ -420,7 +438,6 @@
.fnend
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
@@ -436,7 +453,6 @@
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_FROM16: /* 0x02 */
@@ -451,7 +467,6 @@
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
@@ -466,7 +481,6 @@
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE: /* 0x04 */
@@ -484,7 +498,6 @@
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
@@ -501,7 +514,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
@@ -518,7 +530,6 @@
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT: /* 0x07 */
@@ -536,7 +547,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
@@ -553,7 +563,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
@@ -570,7 +579,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT: /* 0x0a */
@@ -584,7 +592,6 @@
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
@@ -599,7 +606,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
@@ -615,7 +621,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_EXCEPTION: /* 0x0d */
@@ -631,14 +636,12 @@
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
/* File: armv5te/OP_RETURN_VOID.S */
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -655,7 +658,6 @@
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
@@ -672,7 +674,6 @@
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_OBJECT: /* 0x11 */
@@ -691,7 +692,6 @@
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
@@ -706,7 +706,6 @@
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
@@ -719,7 +718,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST: /* 0x14 */
@@ -734,7 +732,6 @@
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_HIGH16: /* 0x15 */
@@ -748,7 +745,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_16: /* 0x16 */
@@ -763,7 +759,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_32: /* 0x17 */
@@ -780,7 +775,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE: /* 0x18 */
@@ -799,7 +793,6 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
@@ -815,7 +808,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
@@ -894,7 +886,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
@@ -923,7 +914,6 @@
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
-
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
@@ -999,7 +989,6 @@
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_NEW_INSTANCE: /* 0x22 */
@@ -1135,13 +1124,13 @@
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
@@ -1197,7 +1186,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO_32: /* 0x2a */
@@ -1270,7 +1258,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_SPARSE_SWITCH: /* 0x2c */
@@ -1310,7 +1297,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_CMPL_FLOAT: /* 0x2d */
@@ -1566,7 +1552,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NE: /* 0x33 */
@@ -1603,7 +1588,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LT: /* 0x34 */
@@ -1640,7 +1624,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GE: /* 0x35 */
@@ -1677,7 +1660,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GT: /* 0x36 */
@@ -1714,7 +1696,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LE: /* 0x37 */
@@ -1751,7 +1732,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_EQZ: /* 0x38 */
@@ -1788,7 +1768,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
@@ -1825,7 +1804,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
@@ -1862,7 +1840,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
@@ -1899,7 +1876,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
@@ -1936,7 +1912,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
@@ -1973,7 +1948,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
@@ -1982,7 +1956,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
@@ -1991,7 +1964,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
@@ -2000,7 +1972,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
@@ -2009,7 +1980,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
@@ -2018,7 +1988,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
@@ -2027,7 +1996,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
@@ -2058,7 +2026,6 @@
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
@@ -2118,7 +2085,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
@@ -2151,7 +2117,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
@@ -2184,7 +2149,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
@@ -2217,7 +2181,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
@@ -2250,7 +2213,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
@@ -2281,7 +2243,6 @@
str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
@@ -2367,7 +2328,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
@@ -2400,7 +2360,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
@@ -2433,7 +2392,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
@@ -2466,7 +2424,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
@@ -2668,7 +2625,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2712,11 +2669,10 @@
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
/*
- * General 32-bit instance field put.
+ * 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2735,7 +2691,6 @@
bne .LOP_IPUT_OBJECT_finish @ yes, finish up
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2745,7 +2700,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2774,7 +2729,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2803,7 +2758,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2832,7 +2787,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2870,6 +2825,7 @@
beq .LOP_SGET_resolve @ yes, do resolve
.LOP_SGET_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2891,12 +2847,16 @@
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_resolve @ yes, do resolve
.LOP_SGET_WIDE_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- add r0, r0, #offStaticField_value
- ldmia r0, {r2-r3} @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ .if 0
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldmia r0, {r0-r1} @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
@@ -2919,6 +2879,7 @@
beq .LOP_SGET_OBJECT_resolve @ yes, do resolve
.LOP_SGET_OBJECT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2945,6 +2906,7 @@
beq .LOP_SGET_BOOLEAN_resolve @ yes, do resolve
.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2971,6 +2933,7 @@
beq .LOP_SGET_BYTE_resolve @ yes, do resolve
.LOP_SGET_BYTE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2997,6 +2960,7 @@
beq .LOP_SGET_CHAR_resolve @ yes, do resolve
.LOP_SGET_CHAR_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3023,6 +2987,7 @@
beq .LOP_SGET_SHORT_resolve @ yes, do resolve
.LOP_SGET_SHORT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3037,7 +3002,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3051,6 +3016,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3062,31 +3028,34 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
-.LOP_SPUT_WIDE_finish: @ field ptr in r0, AA in r9
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- add r0, r0, #offStaticField_value
- stmia r0, {r2-r3} @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ .if 0
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ stmia r2, {r0-r1} @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
/*
- * General 32-bit SPUT handler.
+ * 32-bit SPUT handler for objects
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3094,14 +3063,14 @@
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
- beq .LOP_SPUT_OBJECT_resolve @ yes, do resolve
-.LOP_SPUT_OBJECT_finish: @ field ptr in r0
- mov r2, rINST, lsr #8 @ r2<- AA
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- GET_VREG(r1, r2) @ r1<- fp[AA]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r1, [r0, #offStaticField_value] @ field<- vAA
- GOTO_OPCODE(ip) @ jump to next instruction
+ bne .LOP_SPUT_OBJECT_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
@@ -3112,7 +3081,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3126,6 +3095,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3138,7 +3108,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3152,6 +3122,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3164,7 +3135,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3178,6 +3149,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3190,7 +3162,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3204,6 +3176,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3326,7 +3299,6 @@
bne common_invokeMethodNoRange @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE: /* 0x72 */
@@ -3353,8 +3325,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodNoRange @ jump to common handler
-
+ b common_invokeMethodNoRange @ jump to common handler
/* ------------------------------ */
.balign 64
@@ -3364,7 +3335,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
@@ -3491,7 +3461,6 @@
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
@@ -3519,8 +3488,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodRange @ jump to common handler
-
+ b common_invokeMethodRange @ jump to common handler
/* ------------------------------ */
@@ -3531,7 +3499,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
@@ -3540,7 +3507,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
@@ -3623,7 +3589,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
@@ -3652,7 +3617,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
@@ -3708,7 +3672,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
@@ -3808,7 +3771,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_FLOAT: /* 0x85 */
@@ -3867,7 +3829,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
@@ -3933,7 +3894,6 @@
ldmfd sp!, {r4, pc}
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_LONG: /* 0x88 */
@@ -4072,7 +4032,6 @@
ldmfd sp!, {r4, r5, pc}
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_LONG: /* 0x8b */
@@ -4103,7 +4062,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
@@ -4256,7 +4214,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -4298,7 +4255,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -4341,7 +4297,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT: /* 0x93 */
@@ -4383,7 +4338,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
@@ -4426,7 +4380,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT: /* 0x95 */
@@ -4468,7 +4421,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -4510,7 +4462,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -4552,7 +4503,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -4594,7 +4544,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT: /* 0x99 */
@@ -4636,7 +4585,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT: /* 0x9a */
@@ -4678,7 +4626,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG: /* 0x9b */
@@ -4723,7 +4670,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG: /* 0x9c */
@@ -4768,7 +4714,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG: /* 0x9d */
@@ -4852,7 +4797,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG: /* 0x9f */
@@ -4898,7 +4842,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG: /* 0xa0 */
@@ -4943,7 +4886,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG: /* 0xa1 */
@@ -4988,7 +4930,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG: /* 0xa2 */
@@ -5033,7 +4974,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG: /* 0xa3 */
@@ -5162,7 +5102,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT: /* 0xa7 */
@@ -5204,7 +5143,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT: /* 0xa8 */
@@ -5246,7 +5184,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT: /* 0xa9 */
@@ -5288,7 +5225,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT: /* 0xaa */
@@ -5331,7 +5267,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
@@ -5376,7 +5311,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE: /* 0xac */
@@ -5421,7 +5355,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE: /* 0xad */
@@ -5466,7 +5399,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE: /* 0xae */
@@ -5511,7 +5443,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE: /* 0xaf */
@@ -5557,7 +5488,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_2ADDR: /* 0xb0 */
@@ -5597,7 +5527,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
@@ -5637,7 +5566,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
@@ -5678,7 +5606,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_2ADDR: /* 0xb3 */
@@ -5718,7 +5645,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
@@ -5759,7 +5685,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
@@ -5799,7 +5724,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
@@ -5839,7 +5763,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
@@ -5879,7 +5802,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
@@ -5919,7 +5841,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
@@ -5959,7 +5880,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
@@ -5999,7 +5919,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
@@ -6041,7 +5960,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG_2ADDR: /* 0xbc */
@@ -6083,7 +6001,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG_2ADDR: /* 0xbd */
@@ -6114,7 +6031,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG_2ADDR: /* 0xbe */
@@ -6156,7 +6072,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG_2ADDR: /* 0xbf */
@@ -6199,7 +6114,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG_2ADDR: /* 0xc0 */
@@ -6241,7 +6155,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG_2ADDR: /* 0xc1 */
@@ -6283,7 +6196,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
@@ -6325,7 +6237,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
@@ -6443,7 +6354,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
@@ -6483,7 +6393,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
@@ -6523,7 +6432,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
@@ -6563,7 +6471,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT_2ADDR: /* 0xca */
@@ -6604,7 +6511,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
@@ -6646,7 +6552,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
@@ -6688,7 +6593,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
@@ -6730,7 +6634,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
@@ -6772,7 +6675,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
@@ -6815,7 +6717,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT16: /* 0xd0 */
@@ -6852,7 +6753,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
@@ -6890,7 +6790,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT16: /* 0xd2 */
@@ -6928,7 +6827,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT16: /* 0xd3 */
@@ -6965,7 +6863,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT16: /* 0xd4 */
@@ -7003,7 +6900,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT16: /* 0xd5 */
@@ -7040,7 +6936,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT16: /* 0xd6 */
@@ -7077,7 +6972,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
@@ -7114,7 +7008,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT8: /* 0xd8 */
@@ -7153,7 +7046,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT_LIT8: /* 0xd9 */
@@ -7192,7 +7084,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
@@ -7232,7 +7123,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
@@ -7271,7 +7161,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT8: /* 0xdc */
@@ -7311,7 +7200,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT8: /* 0xdd */
@@ -7350,7 +7238,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT8: /* 0xde */
@@ -7389,7 +7276,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
@@ -7428,7 +7314,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_LIT8: /* 0xe0 */
@@ -7467,7 +7352,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_LIT8: /* 0xe1 */
@@ -7506,7 +7390,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_LIT8: /* 0xe2 */
@@ -7545,86 +7428,251 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: armv5te/OP_UNUSED_E3.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: armv5te/OP_UNUSED_E4.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: armv5te/OP_UNUSED_E5.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: armv5te/OP_UNUSED_E6.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r1, [r0, #offStaticField_value] @ field<- vAA
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: armv5te/OP_UNUSED_E7.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_OBJECT_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: armv5te/OP_UNUSED_E8.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv4t/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv4t/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ /* iget-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_WIDE_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: armv5te/OP_UNUSED_E9.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv4t/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv4t/OP_IPUT_WIDE.S */
+ /* iput-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: armv5te/OP_UNUSED_EA.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv4t/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv4t/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ /* sget-wide vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+ mov r9, rINST, lsr #8 @ r9<- AA
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ .if 1
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldmia r0, {r0-r1} @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: armv5te/OP_UNUSED_EB.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv4t/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv4t/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-wide vAA, field@BBBB */
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r2, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ .if 1
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ stmia r2, {r0-r1} @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
@@ -7635,7 +7683,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
@@ -7653,7 +7700,6 @@
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
@@ -7732,7 +7778,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
@@ -7752,7 +7797,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
@@ -7773,7 +7817,6 @@
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
@@ -7795,12 +7838,11 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7815,7 +7857,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
@@ -7836,13 +7877,11 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7852,13 +7891,14 @@
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
+ cmp r0, #0
+ strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7938,7 +7978,6 @@
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodNoRange @ continue on
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -7968,31 +8007,85 @@
bl common_invokeMethodRange @ continue on
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: armv5te/OP_UNUSED_FC.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: armv5te/OP_UNUSED_FD.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_OBJECT_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: armv5te/OP_UNUSED_FE.S */
-/* File: armv5te/unused.S */
- bl common_abort
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+ /*
+ * 32-bit SPUT handler for objects
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
@@ -8005,7 +8098,6 @@
-
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
@@ -8041,7 +8133,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_STRING_JUMBO */
/*
@@ -8061,7 +8152,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_CLASS */
/*
@@ -8082,7 +8172,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CHECK_CAST */
/*
@@ -8127,7 +8216,6 @@
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
-
/* continuation for OP_INSTANCE_OF */
/*
@@ -8183,7 +8271,6 @@
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .LOP_INSTANCE_OF_resolved @ pick up where we left off
-
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
@@ -8226,7 +8313,6 @@
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
-
/* continuation for OP_NEW_ARRAY */
@@ -8266,7 +8352,6 @@
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_FILLED_NEW_ARRAY */
/*
@@ -8277,15 +8362,15 @@
.LOP_FILLED_NEW_ARRAY_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 0
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -8293,7 +8378,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8325,8 +8411,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8345,7 +8436,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
/*
@@ -8356,15 +8446,15 @@
.LOP_FILLED_NEW_ARRAY_RANGE_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 1
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -8372,7 +8462,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8404,8 +8495,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8424,7 +8520,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_CMPL_FLOAT */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8488,7 +8583,6 @@
#endif
-
/* continuation for OP_CMPG_FLOAT */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8552,7 +8646,6 @@
#endif
-
/* continuation for OP_CMPL_DOUBLE */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8568,7 +8661,6 @@
mvn r1, #0 @ r1<- 1 or -1 for NaN
b .LOP_CMPL_DOUBLE_finish
-
/* continuation for OP_CMPG_DOUBLE */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8584,7 +8676,6 @@
mov r1, #1 @ r1<- 1 or -1 for NaN
b .LOP_CMPG_DOUBLE_finish
-
/* continuation for OP_CMP_LONG */
.LOP_CMP_LONG_less:
@@ -8606,7 +8697,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_AGET_WIDE */
.LOP_AGET_WIDE_finish:
@@ -8618,7 +8708,6 @@
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
@@ -8629,7 +8718,6 @@
stmia r0, {r2-r3} @ vBB[vCC] <- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_OBJECT */
/*
* On entry:
@@ -8645,13 +8733,19 @@
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
+ add r10, #offArrayObject_contents @ r0<- pointer to slot
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r9, [r10] @ vBB[vCC]<- vAA
+ strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
+ GOTO_OPCODE(ip) @ jump to next instruction
.LOP_APUT_OBJECT_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET */
/*
@@ -8665,6 +8759,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8672,7 +8767,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_WIDE */
/*
@@ -8684,17 +8778,21 @@
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
- mov r2, rINST, lsr #8 @ r2<- A+
+ .if 0
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
add r9, r9, r3 @ r9<- obj + field offset
ldmia r9, {r0-r1} @ r0/r1<- obj.field (64-bit align ok)
- and r2, r2, #15 @ r2<- A
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_OBJECT */
/*
@@ -8708,6 +8806,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8715,7 +8814,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BOOLEAN */
/*
@@ -8729,6 +8827,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8736,7 +8835,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BYTE */
/*
@@ -8750,6 +8848,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8757,7 +8856,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_CHAR */
/*
@@ -8771,6 +8869,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8778,7 +8877,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_SHORT */
/*
@@ -8792,6 +8890,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8799,7 +8898,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT */
/*
@@ -8817,10 +8915,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_WIDE */
/*
@@ -8837,11 +8935,14 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- add r9, r9, r3 @ r9<- object + byte offset
- stmia r9, {r0-r1} @ obj.field (64 bits, aligned)<- r0/r1
- GOTO_OPCODE(ip) @ jump to next instruction
-
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ add r2, r9, r3 @ r2<- object + byte offset
+ .if 0
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ stmia r2, {r0-r1} @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* continuation for OP_IPUT_OBJECT */
@@ -8857,13 +8958,17 @@
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ @ no-op @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BOOLEAN */
/*
@@ -8881,10 +8986,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BYTE */
/*
@@ -8902,10 +9007,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_CHAR */
/*
@@ -8923,10 +9028,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_SHORT */
/*
@@ -8944,10 +9049,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SGET */
/*
@@ -8963,12 +9068,13 @@
bne .LOP_SGET_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8979,7 +9085,6 @@
bne .LOP_SGET_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_OBJECT */
/*
@@ -8995,7 +9100,6 @@
bne .LOP_SGET_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BOOLEAN */
/*
@@ -9011,7 +9115,6 @@
bne .LOP_SGET_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BYTE */
/*
@@ -9027,7 +9130,6 @@
bne .LOP_SGET_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_CHAR */
/*
@@ -9043,7 +9145,6 @@
bne .LOP_SGET_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_SHORT */
/*
@@ -9059,7 +9160,6 @@
bne .LOP_SGET_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT */
/*
@@ -9075,13 +9175,14 @@
bne .LOP_SPUT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -9089,25 +9190,23 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_OBJECT */
-
- /*
- * Continuation if the field has not yet been resolved.
- * r1: BBBB field ref
- */
-.LOP_SPUT_OBJECT_resolve:
- ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
- EXPORT_PC() @ resolve() could throw, so export now
- ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
- bl dvmResolveStaticField @ r0<- resolved StaticField ptr
- cmp r0, #0 @ success?
- bne .LOP_SPUT_OBJECT_finish @ yes, finish
- b common_exceptionThrown @ no, handle exception
-
+.LOP_SPUT_OBJECT_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ @ no-op @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SPUT_BOOLEAN */
@@ -9124,7 +9223,6 @@
bne .LOP_SPUT_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_BYTE */
/*
@@ -9140,7 +9238,6 @@
bne .LOP_SPUT_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_CHAR */
/*
@@ -9156,7 +9253,6 @@
bne .LOP_SPUT_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_SHORT */
/*
@@ -9172,7 +9268,6 @@
bne .LOP_SPUT_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL */
/*
@@ -9190,7 +9285,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
-
/* continuation for OP_INVOKE_SUPER */
/*
@@ -9225,7 +9319,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT */
/*
@@ -9243,7 +9336,6 @@
bne .LOP_INVOKE_DIRECT_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
/*
@@ -9261,7 +9353,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
-
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
@@ -9296,7 +9387,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
@@ -9314,7 +9404,6 @@
bne .LOP_INVOKE_DIRECT_RANGE_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_FLOAT_TO_LONG */
/*
* Convert the float in r0 to a long in r0/r1.
@@ -9352,7 +9441,6 @@
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
/* continuation for OP_DOUBLE_TO_LONG */
/*
* Convert the double in r0/r1 to a long in r0/r1.
@@ -9403,7 +9491,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
/* continuation for OP_MUL_LONG */
.LOP_MUL_LONG_finish:
@@ -9411,7 +9498,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
@@ -9420,7 +9506,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG */
.LOP_SHR_LONG_finish:
@@ -9429,7 +9514,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG */
.LOP_USHR_LONG_finish:
@@ -9438,7 +9522,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG_2ADDR */
.LOP_SHL_LONG_2ADDR_finish:
@@ -9446,7 +9529,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG_2ADDR */
.LOP_SHR_LONG_2ADDR_finish:
@@ -9454,7 +9536,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG_2ADDR */
.LOP_USHR_LONG_2ADDR_finish:
@@ -9462,6 +9543,185 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
+/* continuation for OP_IGET_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_VOLATILE_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ .if 1
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ add r9, r9, r3 @ r9<- obj + field offset
+ ldmia r9, {r0-r1} @ r0/r1<- obj.field (64-bit align ok)
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+ mov r2, rINST, lsr #8 @ r2<- A+
+ cmp r9, #0 @ check object for null
+ and r2, r2, #15 @ r2<- A
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r2, {r0-r1} @ r0/r1<- fp[A]
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ add r2, r9, r3 @ r2<- object + byte offset
+ .if 1
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ stmia r2, {r0-r1} @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
+ */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ * r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
+ */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
+ bne .LOP_SPUT_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* continuation for OP_EXECUTE_INLINE */
@@ -9498,7 +9758,6 @@
.LOP_EXECUTE_INLINE_table:
.word gDvmInlineOpsTable
-
/* continuation for OP_EXECUTE_INLINE_RANGE */
/*
@@ -9528,6 +9787,59 @@
.LOP_EXECUTE_INLINE_RANGE_table:
.word gDvmInlineOpsTable
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+.LOP_SPUT_OBJECT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ SMP_DMB @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
@@ -9563,12 +9875,21 @@
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9577,7 +9898,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9586,7 +9907,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9595,7 +9916,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9604,7 +9925,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9619,7 +9940,7 @@
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
@@ -9660,7 +9981,7 @@
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9669,9 +9990,9 @@
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9683,6 +10004,7 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
+ add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
@@ -9726,7 +10048,8 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
-#ifdef JIT_STATS
+ add rINST,#-4 @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
@@ -9746,9 +10069,32 @@
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9773,6 +10119,7 @@
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -9893,6 +10240,11 @@
/*
* Common code when a backward branch is taken.
*
+ * TODO: we could avoid a branch by just setting r0 and falling through
+ * into the common_periodicChecks code, and having a test on r0 at the
+ * end determine if we should return to the caller or update & branch to
+ * the next instr.
+ *
* On entry:
* r9 is PC adjustment *in bytes*
*/
@@ -9915,23 +10267,25 @@
/*
* Need to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
+ * activity has begun. If so, we suspend the thread or side-exit to
+ * the debug interpreter as appropriate.
*
- * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
- * have to do the second ldr.
+ * The common case is no activity on any of these, so we want to figure
+ * that out quickly. If something is up, we can then sort out what.
+ *
+ * We want to be fast if the VM was built without debugger or profiler
+ * support, but we also need to recognize that the system is usually
+ * shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
- * r0 is reentry type, e.g. kInterpEntryInstr
+ * r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
- @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
- str r0, [rGLUE, #offGlue_entryPoint]
-
#if defined(WITH_DEBUGGER)
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
#endif
@@ -9939,33 +10293,42 @@
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
#endif
- ldr r3, [r3] @ r3<- suspendCount (int)
+ ldr ip, [r3] @ ip<- suspendCount (int)
-#if defined(WITH_DEBUGGER)
- ldrb r1, [r1] @ r1<- debuggerActive (boolean)
-#endif
-#if defined (WITH_PROFILER)
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
+ orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
+#elif defined(WITH_DEBUGGER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+ orrsne ip, ip, r1 @ yes, ip<- suspend | debugger; set Z
+ @ (if not enabled, Z was set by test for r1==0, which is what we want)
+#elif defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrs ip, ip, r2 @ ip<- suspendCount | activeProfilers
+#else
+ cmp ip, #0 @ not ORing anything in; set Z
#endif
- cmp r3, #0 @ suspend pending?
- bne 2f @ yes, do full suspension check
+ bxeq lr @ all zero, return
+ /*
+ * One or more interesting events have happened. Figure out what.
+ *
+ * If debugging or profiling are compiled in, we need to disambiguate.
+ *
+ * r0 still holds the reentry type.
+ */
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
-# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
- orrs r1, r1, r2 @ r1<- r1 | r2
- cmp r1, #0 @ debugger attached or profiler started?
-# elif defined(WITH_DEBUGGER)
- cmp r1, #0 @ debugger attached?
-# elif defined(WITH_PROFILER)
- cmp r2, #0 @ profiler started?
-# endif
- bne 3f @ debugger/profiler, switch interp
+ ldr ip, [r3] @ ip<- suspendCount (int)
+ cmp ip, #0 @ want suspend?
+ beq 1f @ no, must be debugger/profiler
#endif
- bx lr @ nothing to do, return
-
-2: @ check suspend
+ stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
@@ -9980,12 +10343,45 @@
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
- b dvmCheckSuspendPending @ suspend if necessary, then return
+ bl dvmCheckSuspendPending @ do full check, suspend if necessary
+ ldmfd sp!, {r0, lr} @ restore r0 and lr
-3: @ debugger/profiler enabled, bail out
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+
+ /*
+ * Reload the debugger/profiler enable flags. We're checking to see
+ * if either of these got set while we were suspended.
+ *
+ * We can't really avoid the #ifdefs here, because the fields don't
+ * exist when the feature is disabled.
+ */
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+#else
+ mov r1, #0
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#else
+ mov r2, #0
+#endif
+
+ orrs r1, r1, r2
+ beq 2f
+
+1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
- b common_gotoBail
+ b common_gotoBail @ side exit
+
+#endif /*WITH_DEBUGGER || WITH_PROFILER*/
+
+2:
+ bx lr @ nothing to do, return
/*
@@ -10089,7 +10485,7 @@
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
- blt .LstackOverflow @ yes, this frame will overflow stack
+ blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
@@ -10264,15 +10660,12 @@
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
@@ -10709,4 +11102,3 @@
.LstrPrintLong:
.asciz "<%lld>"
-
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 8244371..6421454 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -20,6 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* ARMv5 definitions and declarations.
*/
@@ -242,6 +243,11 @@
ldmfd sp!, {\regs,pc}
.endm
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro SMP_DMB
+.endm
/* File: armv5te/entry.S */
/*
@@ -314,14 +320,27 @@
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -396,7 +415,6 @@
.word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
@@ -420,7 +438,6 @@
.fnend
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
@@ -436,7 +453,6 @@
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_FROM16: /* 0x02 */
@@ -451,7 +467,6 @@
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
@@ -466,7 +481,6 @@
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE: /* 0x04 */
@@ -484,7 +498,6 @@
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
@@ -501,7 +514,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
@@ -518,7 +530,6 @@
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT: /* 0x07 */
@@ -536,7 +547,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
@@ -553,7 +563,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
@@ -570,7 +579,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT: /* 0x0a */
@@ -584,7 +592,6 @@
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
@@ -599,7 +606,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
@@ -615,7 +621,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_EXCEPTION: /* 0x0d */
@@ -631,14 +636,12 @@
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
/* File: armv5te/OP_RETURN_VOID.S */
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -655,7 +658,6 @@
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
@@ -672,7 +674,6 @@
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_OBJECT: /* 0x11 */
@@ -691,7 +692,6 @@
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
@@ -706,7 +706,6 @@
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
@@ -719,7 +718,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST: /* 0x14 */
@@ -734,7 +732,6 @@
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_HIGH16: /* 0x15 */
@@ -748,7 +745,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_16: /* 0x16 */
@@ -763,7 +759,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_32: /* 0x17 */
@@ -780,7 +775,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE: /* 0x18 */
@@ -799,7 +793,6 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
@@ -815,7 +808,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
@@ -894,7 +886,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
@@ -923,7 +914,6 @@
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
-
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
@@ -999,7 +989,6 @@
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_NEW_INSTANCE: /* 0x22 */
@@ -1135,13 +1124,13 @@
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
@@ -1197,7 +1186,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO_32: /* 0x2a */
@@ -1270,7 +1258,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_SPARSE_SWITCH: /* 0x2c */
@@ -1310,7 +1297,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_CMPL_FLOAT: /* 0x2d */
@@ -1544,7 +1530,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NE: /* 0x33 */
@@ -1581,7 +1566,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LT: /* 0x34 */
@@ -1618,7 +1602,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GE: /* 0x35 */
@@ -1655,7 +1638,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GT: /* 0x36 */
@@ -1692,7 +1674,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LE: /* 0x37 */
@@ -1729,7 +1710,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_EQZ: /* 0x38 */
@@ -1766,7 +1746,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
@@ -1803,7 +1782,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
@@ -1840,7 +1818,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
@@ -1877,7 +1854,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
@@ -1914,7 +1890,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
@@ -1951,7 +1926,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
@@ -1960,7 +1934,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
@@ -1969,7 +1942,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
@@ -1978,7 +1950,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
@@ -1987,7 +1958,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
@@ -1996,7 +1966,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
@@ -2005,7 +1974,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
@@ -2036,7 +2004,6 @@
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
@@ -2096,7 +2063,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
@@ -2129,7 +2095,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
@@ -2162,7 +2127,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
@@ -2195,7 +2159,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
@@ -2228,7 +2191,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
@@ -2259,7 +2221,6 @@
str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
@@ -2347,7 +2308,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
@@ -2380,7 +2340,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
@@ -2413,7 +2372,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
@@ -2446,7 +2404,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
@@ -2648,7 +2605,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2692,11 +2649,10 @@
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
/*
- * General 32-bit instance field put.
+ * 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2715,7 +2671,6 @@
bne .LOP_IPUT_OBJECT_finish @ yes, finish up
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2725,7 +2680,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2754,7 +2709,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2783,7 +2738,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2812,7 +2767,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2850,6 +2805,7 @@
beq .LOP_SGET_resolve @ yes, do resolve
.LOP_SGET_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2871,11 +2827,16 @@
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_resolve @ yes, do resolve
.LOP_SGET_WIDE_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- ldrd r2, [r0, #offStaticField_value] @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 0
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
@@ -2898,6 +2859,7 @@
beq .LOP_SGET_OBJECT_resolve @ yes, do resolve
.LOP_SGET_OBJECT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2924,6 +2886,7 @@
beq .LOP_SGET_BOOLEAN_resolve @ yes, do resolve
.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2950,6 +2913,7 @@
beq .LOP_SGET_BYTE_resolve @ yes, do resolve
.LOP_SGET_BYTE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2976,6 +2940,7 @@
beq .LOP_SGET_CHAR_resolve @ yes, do resolve
.LOP_SGET_CHAR_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3002,6 +2967,7 @@
beq .LOP_SGET_SHORT_resolve @ yes, do resolve
.LOP_SGET_SHORT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3016,7 +2982,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3030,6 +2996,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3041,30 +3008,34 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
-.LOP_SPUT_WIDE_finish: @ field ptr in r0, AA in r9
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r2, [r0, #offStaticField_value] @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 0
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
/*
- * General 32-bit SPUT handler.
+ * 32-bit SPUT handler for objects
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3072,14 +3043,14 @@
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
- beq .LOP_SPUT_OBJECT_resolve @ yes, do resolve
-.LOP_SPUT_OBJECT_finish: @ field ptr in r0
- mov r2, rINST, lsr #8 @ r2<- AA
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- GET_VREG(r1, r2) @ r1<- fp[AA]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r1, [r0, #offStaticField_value] @ field<- vAA
- GOTO_OPCODE(ip) @ jump to next instruction
+ bne .LOP_SPUT_OBJECT_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
@@ -3090,7 +3061,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3104,6 +3075,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3116,7 +3088,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3130,6 +3102,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3142,7 +3115,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3156,6 +3129,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3168,7 +3142,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3182,6 +3156,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3304,7 +3279,6 @@
bne common_invokeMethodNoRange @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE: /* 0x72 */
@@ -3331,8 +3305,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodNoRange @ jump to common handler
-
+ b common_invokeMethodNoRange @ jump to common handler
/* ------------------------------ */
.balign 64
@@ -3342,7 +3315,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
@@ -3469,7 +3441,6 @@
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
@@ -3497,8 +3468,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodRange @ jump to common handler
-
+ b common_invokeMethodRange @ jump to common handler
/* ------------------------------ */
@@ -3509,7 +3479,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
@@ -3518,7 +3487,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
@@ -3601,7 +3569,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
@@ -3630,7 +3597,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
@@ -3686,7 +3652,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
@@ -3782,7 +3747,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_FLOAT: /* 0x85 */
@@ -3841,7 +3805,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
@@ -3976,7 +3939,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
@@ -4124,7 +4086,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -4166,7 +4127,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -4209,7 +4169,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT: /* 0x93 */
@@ -4251,7 +4210,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
@@ -4294,7 +4252,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT: /* 0x95 */
@@ -4336,7 +4293,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -4378,7 +4334,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -4420,7 +4375,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -4462,7 +4416,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT: /* 0x99 */
@@ -4504,7 +4457,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT: /* 0x9a */
@@ -4546,7 +4498,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG: /* 0x9b */
@@ -4591,7 +4542,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG: /* 0x9c */
@@ -4636,7 +4586,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG: /* 0x9d */
@@ -4720,7 +4669,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG: /* 0x9f */
@@ -4766,7 +4714,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG: /* 0xa0 */
@@ -4811,7 +4758,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG: /* 0xa1 */
@@ -4856,7 +4802,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG: /* 0xa2 */
@@ -4901,7 +4846,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG: /* 0xa3 */
@@ -5151,7 +5095,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
@@ -5317,7 +5260,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_2ADDR: /* 0xb0 */
@@ -5357,7 +5299,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
@@ -5397,7 +5338,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
@@ -5438,7 +5378,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_2ADDR: /* 0xb3 */
@@ -5478,7 +5417,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
@@ -5519,7 +5457,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
@@ -5559,7 +5496,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
@@ -5599,7 +5535,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
@@ -5639,7 +5574,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
@@ -5679,7 +5613,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
@@ -5719,7 +5652,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
@@ -5759,7 +5691,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
@@ -5801,7 +5732,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG_2ADDR: /* 0xbc */
@@ -5843,7 +5773,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG_2ADDR: /* 0xbd */
@@ -5874,7 +5803,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG_2ADDR: /* 0xbe */
@@ -5916,7 +5844,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG_2ADDR: /* 0xbf */
@@ -5959,7 +5886,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG_2ADDR: /* 0xc0 */
@@ -6001,7 +5927,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG_2ADDR: /* 0xc1 */
@@ -6043,7 +5968,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
@@ -6085,7 +6009,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
@@ -6316,7 +6239,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
@@ -6475,7 +6397,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT16: /* 0xd0 */
@@ -6512,7 +6433,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
@@ -6550,7 +6470,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT16: /* 0xd2 */
@@ -6588,7 +6507,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT16: /* 0xd3 */
@@ -6625,7 +6543,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT16: /* 0xd4 */
@@ -6663,7 +6580,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT16: /* 0xd5 */
@@ -6700,7 +6616,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT16: /* 0xd6 */
@@ -6737,7 +6652,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
@@ -6774,7 +6688,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT8: /* 0xd8 */
@@ -6813,7 +6726,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT_LIT8: /* 0xd9 */
@@ -6852,7 +6764,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
@@ -6892,7 +6803,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
@@ -6931,7 +6841,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT8: /* 0xdc */
@@ -6971,7 +6880,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT8: /* 0xdd */
@@ -7010,7 +6918,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT8: /* 0xde */
@@ -7049,7 +6956,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
@@ -7088,7 +6994,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_LIT8: /* 0xe0 */
@@ -7127,7 +7032,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_LIT8: /* 0xe1 */
@@ -7166,7 +7070,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_LIT8: /* 0xe2 */
@@ -7205,86 +7108,251 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: armv5te/OP_UNUSED_E3.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: armv5te/OP_UNUSED_E4.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: armv5te/OP_UNUSED_E5.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: armv5te/OP_UNUSED_E6.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r1, [r0, #offStaticField_value] @ field<- vAA
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: armv5te/OP_UNUSED_E7.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_OBJECT_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: armv5te/OP_UNUSED_E8.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ /* iget-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_WIDE_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: armv5te/OP_UNUSED_E9.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+ /* iput-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: armv5te/OP_UNUSED_EA.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ /* sget-wide vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 1
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: armv5te/OP_UNUSED_EB.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-wide vAA, field@BBBB */
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r2, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
@@ -7295,7 +7363,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
@@ -7313,7 +7380,6 @@
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
@@ -7392,7 +7458,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
@@ -7412,7 +7477,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
@@ -7432,7 +7496,6 @@
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
@@ -7454,12 +7517,11 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7474,7 +7536,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
@@ -7494,13 +7555,11 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7510,13 +7569,14 @@
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
+ cmp r0, #0
+ strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7596,7 +7656,6 @@
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodNoRange @ continue on
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -7626,31 +7685,85 @@
bl common_invokeMethodRange @ continue on
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: armv5te/OP_UNUSED_FC.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: armv5te/OP_UNUSED_FD.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_OBJECT_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: armv5te/OP_UNUSED_FE.S */
-/* File: armv5te/unused.S */
- bl common_abort
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+ /*
+ * 32-bit SPUT handler for objects
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
@@ -7663,7 +7776,6 @@
-
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
@@ -7699,7 +7811,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_STRING_JUMBO */
/*
@@ -7719,7 +7830,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_CLASS */
/*
@@ -7740,7 +7850,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CHECK_CAST */
/*
@@ -7785,7 +7894,6 @@
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
-
/* continuation for OP_INSTANCE_OF */
/*
@@ -7841,7 +7949,6 @@
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .LOP_INSTANCE_OF_resolved @ pick up where we left off
-
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
@@ -7884,7 +7991,6 @@
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
-
/* continuation for OP_NEW_ARRAY */
@@ -7924,7 +8030,6 @@
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_FILLED_NEW_ARRAY */
/*
@@ -7935,15 +8040,15 @@
.LOP_FILLED_NEW_ARRAY_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 0
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -7951,7 +8056,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -7983,8 +8089,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8003,7 +8114,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
/*
@@ -8014,15 +8124,15 @@
.LOP_FILLED_NEW_ARRAY_RANGE_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 1
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -8030,7 +8140,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8062,8 +8173,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8082,31 +8198,26 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPG_FLOAT */
.LOP_CMPG_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPL_DOUBLE */
.LOP_CMPL_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPG_DOUBLE */
.LOP_CMPG_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMP_LONG */
.LOP_CMP_LONG_less:
@@ -8128,7 +8239,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_AGET_WIDE */
.LOP_AGET_WIDE_finish:
@@ -8139,7 +8249,6 @@
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
@@ -8149,7 +8258,6 @@
strd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_OBJECT */
/*
* On entry:
@@ -8165,13 +8273,19 @@
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
+ add r10, #offArrayObject_contents @ r0<- pointer to slot
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r9, [r10] @ vBB[vCC]<- vAA
+ strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
+ GOTO_OPCODE(ip) @ jump to next instruction
.LOP_APUT_OBJECT_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET */
/*
@@ -8185,6 +8299,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8192,7 +8307,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_WIDE */
/*
@@ -8204,16 +8318,20 @@
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
- mov r2, rINST, lsr #8 @ r2<- A+
+ .if 0
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
- and r2, r2, #15 @ r2<- A
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_OBJECT */
/*
@@ -8227,6 +8345,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8234,7 +8353,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BOOLEAN */
/*
@@ -8248,6 +8366,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8255,7 +8374,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BYTE */
/*
@@ -8269,6 +8387,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8276,7 +8395,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_CHAR */
/*
@@ -8290,6 +8408,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8297,7 +8416,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_SHORT */
/*
@@ -8311,6 +8429,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8318,7 +8437,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT */
/*
@@ -8336,10 +8454,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_WIDE */
/*
@@ -8356,10 +8474,14 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
- GOTO_OPCODE(ip) @ jump to next instruction
-
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 0
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* continuation for OP_IPUT_OBJECT */
@@ -8375,13 +8497,17 @@
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ @ no-op @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BOOLEAN */
/*
@@ -8399,10 +8525,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BYTE */
/*
@@ -8420,10 +8546,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_CHAR */
/*
@@ -8441,10 +8567,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_SHORT */
/*
@@ -8462,10 +8588,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SGET */
/*
@@ -8481,12 +8607,13 @@
bne .LOP_SGET_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8497,7 +8624,6 @@
bne .LOP_SGET_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_OBJECT */
/*
@@ -8513,7 +8639,6 @@
bne .LOP_SGET_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BOOLEAN */
/*
@@ -8529,7 +8654,6 @@
bne .LOP_SGET_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BYTE */
/*
@@ -8545,7 +8669,6 @@
bne .LOP_SGET_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_CHAR */
/*
@@ -8561,7 +8684,6 @@
bne .LOP_SGET_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_SHORT */
/*
@@ -8577,7 +8699,6 @@
bne .LOP_SGET_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT */
/*
@@ -8593,13 +8714,14 @@
bne .LOP_SPUT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8607,25 +8729,23 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_OBJECT */
-
- /*
- * Continuation if the field has not yet been resolved.
- * r1: BBBB field ref
- */
-.LOP_SPUT_OBJECT_resolve:
- ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
- EXPORT_PC() @ resolve() could throw, so export now
- ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
- bl dvmResolveStaticField @ r0<- resolved StaticField ptr
- cmp r0, #0 @ success?
- bne .LOP_SPUT_OBJECT_finish @ yes, finish
- b common_exceptionThrown @ no, handle exception
-
+.LOP_SPUT_OBJECT_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ @ no-op @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SPUT_BOOLEAN */
@@ -8642,7 +8762,6 @@
bne .LOP_SPUT_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_BYTE */
/*
@@ -8658,7 +8777,6 @@
bne .LOP_SPUT_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_CHAR */
/*
@@ -8674,7 +8792,6 @@
bne .LOP_SPUT_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_SHORT */
/*
@@ -8690,7 +8807,6 @@
bne .LOP_SPUT_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL */
/*
@@ -8708,7 +8824,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
-
/* continuation for OP_INVOKE_SUPER */
/*
@@ -8743,7 +8858,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT */
/*
@@ -8761,7 +8875,6 @@
bne .LOP_INVOKE_DIRECT_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
/*
@@ -8779,7 +8892,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
-
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
@@ -8814,7 +8926,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
@@ -8832,7 +8943,6 @@
bne .LOP_INVOKE_DIRECT_RANGE_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_FLOAT_TO_LONG */
/*
* Convert the float in r0 to a long in r0/r1.
@@ -8870,7 +8980,6 @@
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
/* continuation for OP_DOUBLE_TO_LONG */
/*
* Convert the double in r0/r1 to a long in r0/r1.
@@ -8921,7 +9030,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
/* continuation for OP_MUL_LONG */
.LOP_MUL_LONG_finish:
@@ -8929,7 +9037,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
@@ -8938,7 +9045,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG */
.LOP_SHR_LONG_finish:
@@ -8947,7 +9053,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG */
.LOP_USHR_LONG_finish:
@@ -8956,7 +9061,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG_2ADDR */
.LOP_SHL_LONG_2ADDR_finish:
@@ -8964,7 +9068,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG_2ADDR */
.LOP_SHR_LONG_2ADDR_finish:
@@ -8972,7 +9075,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG_2ADDR */
.LOP_USHR_LONG_2ADDR_finish:
@@ -8980,6 +9082,184 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
+/* continuation for OP_IGET_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_VOLATILE_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ .if 1
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+ mov r2, rINST, lsr #8 @ r2<- A+
+ cmp r9, #0 @ check object for null
+ and r2, r2, #15 @ r2<- A
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r2, {r0-r1} @ r0/r1<- fp[A]
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
+ */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ * r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
+ */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
+ bne .LOP_SPUT_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* continuation for OP_EXECUTE_INLINE */
@@ -9016,7 +9296,6 @@
.LOP_EXECUTE_INLINE_table:
.word gDvmInlineOpsTable
-
/* continuation for OP_EXECUTE_INLINE_RANGE */
/*
@@ -9046,6 +9325,59 @@
.LOP_EXECUTE_INLINE_RANGE_table:
.word gDvmInlineOpsTable
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+.LOP_SPUT_OBJECT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ SMP_DMB @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
@@ -9081,12 +9413,21 @@
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9095,7 +9436,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9104,7 +9445,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9113,7 +9454,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9122,7 +9463,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9137,7 +9478,7 @@
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
@@ -9178,7 +9519,7 @@
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9187,9 +9528,9 @@
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9201,6 +9542,7 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
+ add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
@@ -9244,7 +9586,8 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
-#ifdef JIT_STATS
+ add rINST,#-4 @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
@@ -9264,9 +9607,32 @@
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9291,6 +9657,7 @@
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -9411,6 +9778,11 @@
/*
* Common code when a backward branch is taken.
*
+ * TODO: we could avoid a branch by just setting r0 and falling through
+ * into the common_periodicChecks code, and having a test on r0 at the
+ * end determine if we should return to the caller or update & branch to
+ * the next instr.
+ *
* On entry:
* r9 is PC adjustment *in bytes*
*/
@@ -9433,23 +9805,25 @@
/*
* Need to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
+ * activity has begun. If so, we suspend the thread or side-exit to
+ * the debug interpreter as appropriate.
*
- * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
- * have to do the second ldr.
+ * The common case is no activity on any of these, so we want to figure
+ * that out quickly. If something is up, we can then sort out what.
+ *
+ * We want to be fast if the VM was built without debugger or profiler
+ * support, but we also need to recognize that the system is usually
+ * shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
- * r0 is reentry type, e.g. kInterpEntryInstr
+ * r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
- @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
- str r0, [rGLUE, #offGlue_entryPoint]
-
#if defined(WITH_DEBUGGER)
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
#endif
@@ -9457,33 +9831,42 @@
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
#endif
- ldr r3, [r3] @ r3<- suspendCount (int)
+ ldr ip, [r3] @ ip<- suspendCount (int)
-#if defined(WITH_DEBUGGER)
- ldrb r1, [r1] @ r1<- debuggerActive (boolean)
-#endif
-#if defined (WITH_PROFILER)
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
+ orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
+#elif defined(WITH_DEBUGGER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+ orrsne ip, ip, r1 @ yes, ip<- suspend | debugger; set Z
+ @ (if not enabled, Z was set by test for r1==0, which is what we want)
+#elif defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrs ip, ip, r2 @ ip<- suspendCount | activeProfilers
+#else
+ cmp ip, #0 @ not ORing anything in; set Z
#endif
- cmp r3, #0 @ suspend pending?
- bne 2f @ yes, do full suspension check
+ bxeq lr @ all zero, return
+ /*
+ * One or more interesting events have happened. Figure out what.
+ *
+ * If debugging or profiling are compiled in, we need to disambiguate.
+ *
+ * r0 still holds the reentry type.
+ */
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
-# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
- orrs r1, r1, r2 @ r1<- r1 | r2
- cmp r1, #0 @ debugger attached or profiler started?
-# elif defined(WITH_DEBUGGER)
- cmp r1, #0 @ debugger attached?
-# elif defined(WITH_PROFILER)
- cmp r2, #0 @ profiler started?
-# endif
- bne 3f @ debugger/profiler, switch interp
+ ldr ip, [r3] @ ip<- suspendCount (int)
+ cmp ip, #0 @ want suspend?
+ beq 1f @ no, must be debugger/profiler
#endif
- bx lr @ nothing to do, return
-
-2: @ check suspend
+ stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
@@ -9498,12 +9881,45 @@
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
- b dvmCheckSuspendPending @ suspend if necessary, then return
+ bl dvmCheckSuspendPending @ do full check, suspend if necessary
+ ldmfd sp!, {r0, lr} @ restore r0 and lr
-3: @ debugger/profiler enabled, bail out
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+
+ /*
+ * Reload the debugger/profiler enable flags. We're checking to see
+ * if either of these got set while we were suspended.
+ *
+ * We can't really avoid the #ifdefs here, because the fields don't
+ * exist when the feature is disabled.
+ */
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+#else
+ mov r1, #0
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#else
+ mov r2, #0
+#endif
+
+ orrs r1, r1, r2
+ beq 2f
+
+1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
- b common_gotoBail
+ b common_gotoBail @ side exit
+
+#endif /*WITH_DEBUGGER || WITH_PROFILER*/
+
+2:
+ bx lr @ nothing to do, return
/*
@@ -9607,7 +10023,7 @@
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
- blt .LstackOverflow @ yes, this frame will overflow stack
+ blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
@@ -9782,15 +10198,12 @@
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
@@ -10227,4 +10640,3 @@
.LstrPrintLong:
.asciz "<%lld>"
-
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 2a69ca6..f756471 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -20,6 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* ARMv5 definitions and declarations.
*/
@@ -242,6 +243,11 @@
ldmfd sp!, {\regs,pc}
.endm
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro SMP_DMB
+.endm
/* File: armv5te/entry.S */
/*
@@ -314,14 +320,27 @@
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -396,7 +415,6 @@
.word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
@@ -420,7 +438,6 @@
.fnend
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
@@ -436,7 +453,6 @@
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_FROM16: /* 0x02 */
@@ -451,7 +467,6 @@
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
@@ -466,7 +481,6 @@
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE: /* 0x04 */
@@ -484,7 +498,6 @@
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
@@ -501,7 +514,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
@@ -518,7 +530,6 @@
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT: /* 0x07 */
@@ -536,7 +547,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
@@ -553,7 +563,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
@@ -570,7 +579,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT: /* 0x0a */
@@ -584,7 +592,6 @@
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
@@ -599,7 +606,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
@@ -615,7 +621,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_EXCEPTION: /* 0x0d */
@@ -631,14 +636,12 @@
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
/* File: armv5te/OP_RETURN_VOID.S */
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -655,7 +658,6 @@
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
@@ -672,7 +674,6 @@
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_OBJECT: /* 0x11 */
@@ -691,7 +692,6 @@
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
@@ -706,7 +706,6 @@
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
@@ -719,7 +718,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST: /* 0x14 */
@@ -734,7 +732,6 @@
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_HIGH16: /* 0x15 */
@@ -748,7 +745,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_16: /* 0x16 */
@@ -763,7 +759,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_32: /* 0x17 */
@@ -780,7 +775,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE: /* 0x18 */
@@ -799,7 +793,6 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
@@ -815,7 +808,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
@@ -894,7 +886,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
@@ -923,7 +914,6 @@
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
-
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
@@ -999,7 +989,6 @@
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_NEW_INSTANCE: /* 0x22 */
@@ -1135,13 +1124,13 @@
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
@@ -1197,7 +1186,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO_32: /* 0x2a */
@@ -1270,7 +1258,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_SPARSE_SWITCH: /* 0x2c */
@@ -1310,7 +1297,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_CMPL_FLOAT: /* 0x2d */
@@ -1566,7 +1552,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NE: /* 0x33 */
@@ -1603,7 +1588,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LT: /* 0x34 */
@@ -1640,7 +1624,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GE: /* 0x35 */
@@ -1677,7 +1660,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GT: /* 0x36 */
@@ -1714,7 +1696,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LE: /* 0x37 */
@@ -1751,7 +1732,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_EQZ: /* 0x38 */
@@ -1788,7 +1768,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
@@ -1825,7 +1804,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
@@ -1862,7 +1840,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
@@ -1899,7 +1876,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
@@ -1936,7 +1912,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
@@ -1973,7 +1948,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
@@ -1982,7 +1956,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
@@ -1991,7 +1964,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
@@ -2000,7 +1972,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
@@ -2009,7 +1980,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
@@ -2018,7 +1988,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
@@ -2027,7 +1996,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
@@ -2058,7 +2026,6 @@
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
@@ -2118,7 +2085,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
@@ -2151,7 +2117,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
@@ -2184,7 +2149,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
@@ -2217,7 +2181,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
@@ -2250,7 +2213,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
@@ -2281,7 +2243,6 @@
str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
@@ -2369,7 +2330,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
@@ -2402,7 +2362,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
@@ -2435,7 +2394,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
@@ -2468,7 +2426,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
@@ -2670,7 +2627,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2714,11 +2671,10 @@
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
/*
- * General 32-bit instance field put.
+ * 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2737,7 +2693,6 @@
bne .LOP_IPUT_OBJECT_finish @ yes, finish up
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2747,7 +2702,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2776,7 +2731,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2805,7 +2760,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2834,7 +2789,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2872,6 +2827,7 @@
beq .LOP_SGET_resolve @ yes, do resolve
.LOP_SGET_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2893,11 +2849,16 @@
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_resolve @ yes, do resolve
.LOP_SGET_WIDE_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- ldrd r2, [r0, #offStaticField_value] @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 0
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
@@ -2920,6 +2881,7 @@
beq .LOP_SGET_OBJECT_resolve @ yes, do resolve
.LOP_SGET_OBJECT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2946,6 +2908,7 @@
beq .LOP_SGET_BOOLEAN_resolve @ yes, do resolve
.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2972,6 +2935,7 @@
beq .LOP_SGET_BYTE_resolve @ yes, do resolve
.LOP_SGET_BYTE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2998,6 +2962,7 @@
beq .LOP_SGET_CHAR_resolve @ yes, do resolve
.LOP_SGET_CHAR_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3024,6 +2989,7 @@
beq .LOP_SGET_SHORT_resolve @ yes, do resolve
.LOP_SGET_SHORT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3038,7 +3004,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3052,6 +3018,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3063,30 +3030,34 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
-.LOP_SPUT_WIDE_finish: @ field ptr in r0, AA in r9
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r2, [r0, #offStaticField_value] @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 0
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
/*
- * General 32-bit SPUT handler.
+ * 32-bit SPUT handler for objects
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3094,14 +3065,14 @@
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
- beq .LOP_SPUT_OBJECT_resolve @ yes, do resolve
-.LOP_SPUT_OBJECT_finish: @ field ptr in r0
- mov r2, rINST, lsr #8 @ r2<- AA
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- GET_VREG(r1, r2) @ r1<- fp[AA]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r1, [r0, #offStaticField_value] @ field<- vAA
- GOTO_OPCODE(ip) @ jump to next instruction
+ bne .LOP_SPUT_OBJECT_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
@@ -3112,7 +3083,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3126,6 +3097,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3138,7 +3110,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3152,6 +3124,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3164,7 +3137,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3178,6 +3151,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3190,7 +3164,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3204,6 +3178,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3326,7 +3301,6 @@
bne common_invokeMethodNoRange @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE: /* 0x72 */
@@ -3353,8 +3327,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodNoRange @ jump to common handler
-
+ b common_invokeMethodNoRange @ jump to common handler
/* ------------------------------ */
.balign 64
@@ -3364,7 +3337,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
@@ -3491,7 +3463,6 @@
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
@@ -3519,8 +3490,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodRange @ jump to common handler
-
+ b common_invokeMethodRange @ jump to common handler
/* ------------------------------ */
@@ -3531,7 +3501,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
@@ -3540,7 +3509,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
@@ -3623,7 +3591,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
@@ -3652,7 +3619,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
@@ -3708,7 +3674,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
@@ -3808,7 +3773,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_FLOAT: /* 0x85 */
@@ -3867,7 +3831,6 @@
/* 12-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
@@ -3933,7 +3896,6 @@
ldmfd sp!, {r4, pc}
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_LONG: /* 0x88 */
@@ -4072,7 +4034,6 @@
ldmfd sp!, {r4, r5, pc}
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_LONG: /* 0x8b */
@@ -4103,7 +4064,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
@@ -4256,7 +4216,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -4298,7 +4257,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -4341,7 +4299,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT: /* 0x93 */
@@ -4383,7 +4340,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
@@ -4426,7 +4382,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT: /* 0x95 */
@@ -4468,7 +4423,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -4510,7 +4464,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -4552,7 +4505,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -4594,7 +4546,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT: /* 0x99 */
@@ -4636,7 +4587,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT: /* 0x9a */
@@ -4678,7 +4628,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG: /* 0x9b */
@@ -4723,7 +4672,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG: /* 0x9c */
@@ -4768,7 +4716,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG: /* 0x9d */
@@ -4852,7 +4799,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG: /* 0x9f */
@@ -4898,7 +4844,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG: /* 0xa0 */
@@ -4943,7 +4888,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG: /* 0xa1 */
@@ -4988,7 +4932,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG: /* 0xa2 */
@@ -5033,7 +4976,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG: /* 0xa3 */
@@ -5162,7 +5104,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT: /* 0xa7 */
@@ -5204,7 +5145,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT: /* 0xa8 */
@@ -5246,7 +5186,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT: /* 0xa9 */
@@ -5288,7 +5227,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT: /* 0xaa */
@@ -5331,7 +5269,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
@@ -5376,7 +5313,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE: /* 0xac */
@@ -5421,7 +5357,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE: /* 0xad */
@@ -5466,7 +5401,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE: /* 0xae */
@@ -5511,7 +5445,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE: /* 0xaf */
@@ -5557,7 +5490,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_2ADDR: /* 0xb0 */
@@ -5597,7 +5529,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
@@ -5637,7 +5568,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
@@ -5678,7 +5608,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_2ADDR: /* 0xb3 */
@@ -5718,7 +5647,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
@@ -5759,7 +5687,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
@@ -5799,7 +5726,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
@@ -5839,7 +5765,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
@@ -5879,7 +5804,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
@@ -5919,7 +5843,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
@@ -5959,7 +5882,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
@@ -5999,7 +5921,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
@@ -6041,7 +5962,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG_2ADDR: /* 0xbc */
@@ -6083,7 +6003,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG_2ADDR: /* 0xbd */
@@ -6114,7 +6033,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG_2ADDR: /* 0xbe */
@@ -6156,7 +6074,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG_2ADDR: /* 0xbf */
@@ -6199,7 +6116,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG_2ADDR: /* 0xc0 */
@@ -6241,7 +6157,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG_2ADDR: /* 0xc1 */
@@ -6283,7 +6198,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
@@ -6325,7 +6239,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
@@ -6443,7 +6356,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
@@ -6483,7 +6395,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
@@ -6523,7 +6434,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
@@ -6563,7 +6473,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT_2ADDR: /* 0xca */
@@ -6604,7 +6513,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
@@ -6646,7 +6554,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
@@ -6688,7 +6595,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
@@ -6730,7 +6636,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
@@ -6772,7 +6677,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
@@ -6815,7 +6719,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT16: /* 0xd0 */
@@ -6852,7 +6755,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
@@ -6890,7 +6792,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT16: /* 0xd2 */
@@ -6928,7 +6829,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT16: /* 0xd3 */
@@ -6965,7 +6865,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT16: /* 0xd4 */
@@ -7003,7 +6902,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT16: /* 0xd5 */
@@ -7040,7 +6938,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT16: /* 0xd6 */
@@ -7077,7 +6974,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
@@ -7114,7 +7010,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT8: /* 0xd8 */
@@ -7153,7 +7048,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT_LIT8: /* 0xd9 */
@@ -7192,7 +7086,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
@@ -7232,7 +7125,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
@@ -7271,7 +7163,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT8: /* 0xdc */
@@ -7311,7 +7202,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT8: /* 0xdd */
@@ -7350,7 +7240,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT8: /* 0xde */
@@ -7389,7 +7278,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
@@ -7428,7 +7316,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_LIT8: /* 0xe0 */
@@ -7467,7 +7354,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_LIT8: /* 0xe1 */
@@ -7506,7 +7392,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_LIT8: /* 0xe2 */
@@ -7545,86 +7430,251 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: armv5te/OP_UNUSED_E3.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: armv5te/OP_UNUSED_E4.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: armv5te/OP_UNUSED_E5.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: armv5te/OP_UNUSED_E6.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r1, [r0, #offStaticField_value] @ field<- vAA
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: armv5te/OP_UNUSED_E7.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_OBJECT_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: armv5te/OP_UNUSED_E8.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ /* iget-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_WIDE_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: armv5te/OP_UNUSED_E9.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+ /* iput-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: armv5te/OP_UNUSED_EA.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ /* sget-wide vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 1
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: armv5te/OP_UNUSED_EB.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-wide vAA, field@BBBB */
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r2, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
@@ -7635,7 +7685,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
@@ -7653,7 +7702,6 @@
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
@@ -7732,7 +7780,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
@@ -7752,7 +7799,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
@@ -7772,7 +7818,6 @@
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
@@ -7794,12 +7839,11 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7814,7 +7858,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
@@ -7834,13 +7877,11 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7850,13 +7891,14 @@
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
+ cmp r0, #0
+ strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7936,7 +7978,6 @@
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodNoRange @ continue on
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -7966,31 +8007,85 @@
bl common_invokeMethodRange @ continue on
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: armv5te/OP_UNUSED_FC.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: armv5te/OP_UNUSED_FD.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_OBJECT_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: armv5te/OP_UNUSED_FE.S */
-/* File: armv5te/unused.S */
- bl common_abort
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+ /*
+ * 32-bit SPUT handler for objects
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
@@ -8003,7 +8098,6 @@
-
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
@@ -8039,7 +8133,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_STRING_JUMBO */
/*
@@ -8059,7 +8152,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_CLASS */
/*
@@ -8080,7 +8172,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CHECK_CAST */
/*
@@ -8125,7 +8216,6 @@
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
-
/* continuation for OP_INSTANCE_OF */
/*
@@ -8181,7 +8271,6 @@
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .LOP_INSTANCE_OF_resolved @ pick up where we left off
-
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
@@ -8224,7 +8313,6 @@
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
-
/* continuation for OP_NEW_ARRAY */
@@ -8264,7 +8352,6 @@
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_FILLED_NEW_ARRAY */
/*
@@ -8275,15 +8362,15 @@
.LOP_FILLED_NEW_ARRAY_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 0
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -8291,7 +8378,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8323,8 +8411,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8343,7 +8436,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
/*
@@ -8354,15 +8446,15 @@
.LOP_FILLED_NEW_ARRAY_RANGE_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 1
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -8370,7 +8462,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8402,8 +8495,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8422,7 +8520,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_CMPL_FLOAT */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8486,7 +8583,6 @@
#endif
-
/* continuation for OP_CMPG_FLOAT */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8550,7 +8646,6 @@
#endif
-
/* continuation for OP_CMPL_DOUBLE */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8566,7 +8661,6 @@
mvn r1, #0 @ r1<- 1 or -1 for NaN
b .LOP_CMPL_DOUBLE_finish
-
/* continuation for OP_CMPG_DOUBLE */
@ Test for NaN with a second comparison. EABI forbids testing bit
@@ -8582,7 +8676,6 @@
mov r1, #1 @ r1<- 1 or -1 for NaN
b .LOP_CMPG_DOUBLE_finish
-
/* continuation for OP_CMP_LONG */
.LOP_CMP_LONG_less:
@@ -8604,7 +8697,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_AGET_WIDE */
.LOP_AGET_WIDE_finish:
@@ -8615,7 +8707,6 @@
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
@@ -8625,7 +8716,6 @@
strd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_OBJECT */
/*
* On entry:
@@ -8641,13 +8731,19 @@
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
+ add r10, #offArrayObject_contents @ r0<- pointer to slot
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r9, [r10] @ vBB[vCC]<- vAA
+ strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
+ GOTO_OPCODE(ip) @ jump to next instruction
.LOP_APUT_OBJECT_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET */
/*
@@ -8661,6 +8757,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8668,7 +8765,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_WIDE */
/*
@@ -8680,16 +8776,20 @@
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
- mov r2, rINST, lsr #8 @ r2<- A+
+ .if 0
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
- and r2, r2, #15 @ r2<- A
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_OBJECT */
/*
@@ -8703,6 +8803,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8710,7 +8811,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BOOLEAN */
/*
@@ -8724,6 +8824,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8731,7 +8832,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BYTE */
/*
@@ -8745,6 +8845,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8752,7 +8853,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_CHAR */
/*
@@ -8766,6 +8866,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8773,7 +8874,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_SHORT */
/*
@@ -8787,6 +8887,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8794,7 +8895,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT */
/*
@@ -8812,10 +8912,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_WIDE */
/*
@@ -8832,10 +8932,14 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
- GOTO_OPCODE(ip) @ jump to next instruction
-
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 0
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* continuation for OP_IPUT_OBJECT */
@@ -8851,13 +8955,17 @@
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ @ no-op @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BOOLEAN */
/*
@@ -8875,10 +8983,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BYTE */
/*
@@ -8896,10 +9004,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_CHAR */
/*
@@ -8917,10 +9025,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_SHORT */
/*
@@ -8938,10 +9046,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SGET */
/*
@@ -8957,12 +9065,13 @@
bne .LOP_SGET_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8973,7 +9082,6 @@
bne .LOP_SGET_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_OBJECT */
/*
@@ -8989,7 +9097,6 @@
bne .LOP_SGET_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BOOLEAN */
/*
@@ -9005,7 +9112,6 @@
bne .LOP_SGET_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BYTE */
/*
@@ -9021,7 +9127,6 @@
bne .LOP_SGET_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_CHAR */
/*
@@ -9037,7 +9142,6 @@
bne .LOP_SGET_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_SHORT */
/*
@@ -9053,7 +9157,6 @@
bne .LOP_SGET_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT */
/*
@@ -9069,13 +9172,14 @@
bne .LOP_SPUT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -9083,25 +9187,23 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_OBJECT */
-
- /*
- * Continuation if the field has not yet been resolved.
- * r1: BBBB field ref
- */
-.LOP_SPUT_OBJECT_resolve:
- ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
- EXPORT_PC() @ resolve() could throw, so export now
- ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
- bl dvmResolveStaticField @ r0<- resolved StaticField ptr
- cmp r0, #0 @ success?
- bne .LOP_SPUT_OBJECT_finish @ yes, finish
- b common_exceptionThrown @ no, handle exception
-
+.LOP_SPUT_OBJECT_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ @ no-op @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SPUT_BOOLEAN */
@@ -9118,7 +9220,6 @@
bne .LOP_SPUT_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_BYTE */
/*
@@ -9134,7 +9235,6 @@
bne .LOP_SPUT_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_CHAR */
/*
@@ -9150,7 +9250,6 @@
bne .LOP_SPUT_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_SHORT */
/*
@@ -9166,7 +9265,6 @@
bne .LOP_SPUT_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL */
/*
@@ -9184,7 +9282,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
-
/* continuation for OP_INVOKE_SUPER */
/*
@@ -9219,7 +9316,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT */
/*
@@ -9237,7 +9333,6 @@
bne .LOP_INVOKE_DIRECT_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
/*
@@ -9255,7 +9350,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
-
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
@@ -9290,7 +9384,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
@@ -9308,7 +9401,6 @@
bne .LOP_INVOKE_DIRECT_RANGE_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_FLOAT_TO_LONG */
/*
* Convert the float in r0 to a long in r0/r1.
@@ -9346,7 +9438,6 @@
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
/* continuation for OP_DOUBLE_TO_LONG */
/*
* Convert the double in r0/r1 to a long in r0/r1.
@@ -9397,7 +9488,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
/* continuation for OP_MUL_LONG */
.LOP_MUL_LONG_finish:
@@ -9405,7 +9495,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
@@ -9414,7 +9503,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG */
.LOP_SHR_LONG_finish:
@@ -9423,7 +9511,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG */
.LOP_USHR_LONG_finish:
@@ -9432,7 +9519,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG_2ADDR */
.LOP_SHL_LONG_2ADDR_finish:
@@ -9440,7 +9526,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG_2ADDR */
.LOP_SHR_LONG_2ADDR_finish:
@@ -9448,7 +9533,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG_2ADDR */
.LOP_USHR_LONG_2ADDR_finish:
@@ -9456,6 +9540,184 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
+/* continuation for OP_IGET_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_VOLATILE_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ .if 1
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+ mov r2, rINST, lsr #8 @ r2<- A+
+ cmp r9, #0 @ check object for null
+ and r2, r2, #15 @ r2<- A
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r2, {r0-r1} @ r0/r1<- fp[A]
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
+ */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ * r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
+ */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
+ bne .LOP_SPUT_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* continuation for OP_EXECUTE_INLINE */
@@ -9492,7 +9754,6 @@
.LOP_EXECUTE_INLINE_table:
.word gDvmInlineOpsTable
-
/* continuation for OP_EXECUTE_INLINE_RANGE */
/*
@@ -9522,6 +9783,59 @@
.LOP_EXECUTE_INLINE_RANGE_table:
.word gDvmInlineOpsTable
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+.LOP_SPUT_OBJECT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ SMP_DMB @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
@@ -9557,12 +9871,21 @@
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9571,7 +9894,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9580,7 +9903,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9589,7 +9912,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9598,7 +9921,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9613,7 +9936,7 @@
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
@@ -9654,7 +9977,7 @@
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9663,9 +9986,9 @@
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9677,6 +10000,7 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
+ add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
@@ -9720,7 +10044,8 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
-#ifdef JIT_STATS
+ add rINST,#-4 @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
@@ -9740,9 +10065,32 @@
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9767,6 +10115,7 @@
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -9887,6 +10236,11 @@
/*
* Common code when a backward branch is taken.
*
+ * TODO: we could avoid a branch by just setting r0 and falling through
+ * into the common_periodicChecks code, and having a test on r0 at the
+ * end determine if we should return to the caller or update & branch to
+ * the next instr.
+ *
* On entry:
* r9 is PC adjustment *in bytes*
*/
@@ -9909,23 +10263,25 @@
/*
* Need to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
+ * activity has begun. If so, we suspend the thread or side-exit to
+ * the debug interpreter as appropriate.
*
- * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
- * have to do the second ldr.
+ * The common case is no activity on any of these, so we want to figure
+ * that out quickly. If something is up, we can then sort out what.
+ *
+ * We want to be fast if the VM was built without debugger or profiler
+ * support, but we also need to recognize that the system is usually
+ * shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
- * r0 is reentry type, e.g. kInterpEntryInstr
+ * r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
- @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
- str r0, [rGLUE, #offGlue_entryPoint]
-
#if defined(WITH_DEBUGGER)
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
#endif
@@ -9933,33 +10289,42 @@
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
#endif
- ldr r3, [r3] @ r3<- suspendCount (int)
+ ldr ip, [r3] @ ip<- suspendCount (int)
-#if defined(WITH_DEBUGGER)
- ldrb r1, [r1] @ r1<- debuggerActive (boolean)
-#endif
-#if defined (WITH_PROFILER)
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
+ orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
+#elif defined(WITH_DEBUGGER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+ orrsne ip, ip, r1 @ yes, ip<- suspend | debugger; set Z
+ @ (if not enabled, Z was set by test for r1==0, which is what we want)
+#elif defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrs ip, ip, r2 @ ip<- suspendCount | activeProfilers
+#else
+ cmp ip, #0 @ not ORing anything in; set Z
#endif
- cmp r3, #0 @ suspend pending?
- bne 2f @ yes, do full suspension check
+ bxeq lr @ all zero, return
+ /*
+ * One or more interesting events have happened. Figure out what.
+ *
+ * If debugging or profiling are compiled in, we need to disambiguate.
+ *
+ * r0 still holds the reentry type.
+ */
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
-# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
- orrs r1, r1, r2 @ r1<- r1 | r2
- cmp r1, #0 @ debugger attached or profiler started?
-# elif defined(WITH_DEBUGGER)
- cmp r1, #0 @ debugger attached?
-# elif defined(WITH_PROFILER)
- cmp r2, #0 @ profiler started?
-# endif
- bne 3f @ debugger/profiler, switch interp
+ ldr ip, [r3] @ ip<- suspendCount (int)
+ cmp ip, #0 @ want suspend?
+ beq 1f @ no, must be debugger/profiler
#endif
- bx lr @ nothing to do, return
-
-2: @ check suspend
+ stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
@@ -9974,12 +10339,45 @@
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
- b dvmCheckSuspendPending @ suspend if necessary, then return
+ bl dvmCheckSuspendPending @ do full check, suspend if necessary
+ ldmfd sp!, {r0, lr} @ restore r0 and lr
-3: @ debugger/profiler enabled, bail out
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+
+ /*
+ * Reload the debugger/profiler enable flags. We're checking to see
+ * if either of these got set while we were suspended.
+ *
+ * We can't really avoid the #ifdefs here, because the fields don't
+ * exist when the feature is disabled.
+ */
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+#else
+ mov r1, #0
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#else
+ mov r2, #0
+#endif
+
+ orrs r1, r1, r2
+ beq 2f
+
+1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
- b common_gotoBail
+ b common_gotoBail @ side exit
+
+#endif /*WITH_DEBUGGER || WITH_PROFILER*/
+
+2:
+ bx lr @ nothing to do, return
/*
@@ -10083,7 +10481,7 @@
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
- blt .LstackOverflow @ yes, this frame will overflow stack
+ blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
@@ -10258,15 +10656,12 @@
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
@@ -10703,4 +11098,3 @@
.LstrPrintLong:
.asciz "<%lld>"
-
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index 45013af..a08d936 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -20,6 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* ARMv5 definitions and declarations.
*/
@@ -205,7 +206,7 @@
#include "../common/jit-config.h"
#endif
-/* File: armv5te/platform.S */
+/* File: armv7-a/platform.S */
/*
* ===========================================================================
* CPU-version-specific defines
@@ -242,6 +243,21 @@
ldmfd sp!, {\regs,pc}
.endm
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ * If the argument is nonzero, emit barrier; otherwise, emit nothing.
+ */
+.macro SMP_DMB
+#if ANDROID_SMP != 0
+ dmb
+#else
+ /* not SMP */
+#endif
+.endm
/* File: armv5te/entry.S */
/*
@@ -314,14 +330,27 @@
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -396,7 +425,6 @@
.word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
@@ -420,7 +448,6 @@
.fnend
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
@@ -435,7 +462,6 @@
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_FROM16: /* 0x02 */
@@ -450,7 +476,6 @@
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
@@ -465,7 +490,6 @@
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE: /* 0x04 */
@@ -482,7 +506,6 @@
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
@@ -499,7 +522,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
@@ -516,7 +538,6 @@
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT: /* 0x07 */
@@ -534,7 +555,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
@@ -551,7 +571,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
@@ -568,7 +587,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT: /* 0x0a */
@@ -582,7 +600,6 @@
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
@@ -597,7 +614,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
@@ -613,7 +629,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_EXCEPTION: /* 0x0d */
@@ -629,14 +644,12 @@
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
/* File: armv5te/OP_RETURN_VOID.S */
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -653,7 +666,6 @@
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
@@ -670,7 +682,6 @@
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_OBJECT: /* 0x11 */
@@ -689,7 +700,6 @@
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
@@ -703,7 +713,6 @@
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
@@ -716,7 +725,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST: /* 0x14 */
@@ -731,7 +739,6 @@
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_HIGH16: /* 0x15 */
@@ -745,7 +752,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_16: /* 0x16 */
@@ -760,7 +766,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_32: /* 0x17 */
@@ -777,7 +782,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE: /* 0x18 */
@@ -796,7 +800,6 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
@@ -812,7 +815,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
@@ -891,7 +893,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
@@ -920,7 +921,6 @@
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
-
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
@@ -995,7 +995,6 @@
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_NEW_INSTANCE: /* 0x22 */
@@ -1131,13 +1130,13 @@
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
@@ -1193,7 +1192,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO_32: /* 0x2a */
@@ -1266,7 +1264,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_SPARSE_SWITCH: /* 0x2c */
@@ -1306,7 +1303,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_CMPL_FLOAT: /* 0x2d */
@@ -1539,7 +1535,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NE: /* 0x33 */
@@ -1575,7 +1570,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LT: /* 0x34 */
@@ -1611,7 +1605,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GE: /* 0x35 */
@@ -1647,7 +1640,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GT: /* 0x36 */
@@ -1683,7 +1675,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LE: /* 0x37 */
@@ -1719,7 +1710,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_EQZ: /* 0x38 */
@@ -1756,7 +1746,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
@@ -1793,7 +1782,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
@@ -1830,7 +1818,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
@@ -1867,7 +1854,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
@@ -1904,7 +1890,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
@@ -1941,7 +1926,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
@@ -1950,7 +1934,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
@@ -1959,7 +1942,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
@@ -1968,7 +1950,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
@@ -1977,7 +1958,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
@@ -1986,7 +1966,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
@@ -1995,7 +1974,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
@@ -2026,7 +2004,6 @@
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
@@ -2086,7 +2063,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
@@ -2119,7 +2095,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
@@ -2152,7 +2127,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
@@ -2185,7 +2159,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
@@ -2218,7 +2191,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
@@ -2249,7 +2221,6 @@
str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
@@ -2337,7 +2308,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
@@ -2370,7 +2340,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
@@ -2403,7 +2372,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
@@ -2436,7 +2404,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
@@ -2682,11 +2649,10 @@
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
/*
- * General 32-bit instance field put.
+ * 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2705,7 +2671,6 @@
bne .LOP_IPUT_OBJECT_finish @ yes, finish up
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2715,7 +2680,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2744,7 +2709,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2773,7 +2738,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2802,7 +2767,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2840,6 +2805,7 @@
beq .LOP_SGET_resolve @ yes, do resolve
.LOP_SGET_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2861,11 +2827,16 @@
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_resolve @ yes, do resolve
.LOP_SGET_WIDE_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- ldrd r2, [r0, #offStaticField_value] @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 0
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
@@ -2888,6 +2859,7 @@
beq .LOP_SGET_OBJECT_resolve @ yes, do resolve
.LOP_SGET_OBJECT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2914,6 +2886,7 @@
beq .LOP_SGET_BOOLEAN_resolve @ yes, do resolve
.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2940,6 +2913,7 @@
beq .LOP_SGET_BYTE_resolve @ yes, do resolve
.LOP_SGET_BYTE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2966,6 +2940,7 @@
beq .LOP_SGET_CHAR_resolve @ yes, do resolve
.LOP_SGET_CHAR_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2992,6 +2967,7 @@
beq .LOP_SGET_SHORT_resolve @ yes, do resolve
.LOP_SGET_SHORT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3006,7 +2982,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3020,6 +2996,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3031,30 +3008,34 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
-.LOP_SPUT_WIDE_finish: @ field ptr in r0, AA in r9
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r2, [r0, #offStaticField_value] @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 0
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
/*
- * General 32-bit SPUT handler.
+ * 32-bit SPUT handler for objects
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3062,14 +3043,14 @@
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
- beq .LOP_SPUT_OBJECT_resolve @ yes, do resolve
-.LOP_SPUT_OBJECT_finish: @ field ptr in r0
- mov r2, rINST, lsr #8 @ r2<- AA
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- GET_VREG(r1, r2) @ r1<- fp[AA]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r1, [r0, #offStaticField_value] @ field<- vAA
- GOTO_OPCODE(ip) @ jump to next instruction
+ bne .LOP_SPUT_OBJECT_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
@@ -3080,7 +3061,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3094,6 +3075,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3106,7 +3088,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3120,6 +3102,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3132,7 +3115,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3146,6 +3129,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3158,7 +3142,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3172,6 +3156,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3294,7 +3279,6 @@
bne common_invokeMethodNoRange @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE: /* 0x72 */
@@ -3321,8 +3305,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodNoRange @ jump to common handler
-
+ b common_invokeMethodNoRange @ jump to common handler
/* ------------------------------ */
.balign 64
@@ -3332,7 +3315,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
@@ -3459,7 +3441,6 @@
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
@@ -3487,8 +3468,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodRange @ jump to common handler
-
+ b common_invokeMethodRange @ jump to common handler
/* ------------------------------ */
@@ -3499,7 +3479,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
@@ -3508,7 +3487,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
@@ -3588,7 +3566,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
@@ -3616,7 +3593,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
@@ -3670,7 +3646,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
@@ -3765,7 +3740,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_FLOAT: /* 0x85 */
@@ -3822,7 +3796,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
@@ -3955,7 +3928,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
@@ -4100,7 +4072,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -4142,7 +4113,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -4185,7 +4155,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT: /* 0x93 */
@@ -4227,7 +4196,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
@@ -4270,7 +4238,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT: /* 0x95 */
@@ -4312,7 +4279,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -4354,7 +4320,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -4396,7 +4361,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -4438,7 +4402,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT: /* 0x99 */
@@ -4480,7 +4443,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT: /* 0x9a */
@@ -4522,7 +4484,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG: /* 0x9b */
@@ -4567,7 +4528,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG: /* 0x9c */
@@ -4612,7 +4572,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG: /* 0x9d */
@@ -4696,7 +4655,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG: /* 0x9f */
@@ -4742,7 +4700,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG: /* 0xa0 */
@@ -4787,7 +4744,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG: /* 0xa1 */
@@ -4832,7 +4788,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG: /* 0xa2 */
@@ -4877,7 +4832,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG: /* 0xa3 */
@@ -5127,7 +5081,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
@@ -5293,7 +5246,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_2ADDR: /* 0xb0 */
@@ -5332,7 +5284,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
@@ -5371,7 +5322,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
@@ -5411,7 +5361,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_2ADDR: /* 0xb3 */
@@ -5450,7 +5399,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
@@ -5490,7 +5438,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
@@ -5529,7 +5476,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
@@ -5568,7 +5514,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
@@ -5607,7 +5552,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
@@ -5646,7 +5590,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
@@ -5685,7 +5628,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
@@ -5724,7 +5666,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
@@ -5765,7 +5706,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG_2ADDR: /* 0xbc */
@@ -5806,7 +5746,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG_2ADDR: /* 0xbd */
@@ -5836,7 +5775,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG_2ADDR: /* 0xbe */
@@ -5877,7 +5815,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG_2ADDR: /* 0xbf */
@@ -5919,7 +5856,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG_2ADDR: /* 0xc0 */
@@ -5960,7 +5896,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG_2ADDR: /* 0xc1 */
@@ -6001,7 +5936,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
@@ -6042,7 +5976,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
@@ -6269,7 +6202,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
@@ -6427,7 +6359,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT16: /* 0xd0 */
@@ -6463,7 +6394,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
@@ -6500,7 +6430,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT16: /* 0xd2 */
@@ -6537,7 +6466,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT16: /* 0xd3 */
@@ -6573,7 +6501,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT16: /* 0xd4 */
@@ -6610,7 +6537,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT16: /* 0xd5 */
@@ -6646,7 +6572,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT16: /* 0xd6 */
@@ -6682,7 +6607,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
@@ -6718,7 +6642,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT8: /* 0xd8 */
@@ -6757,7 +6680,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT_LIT8: /* 0xd9 */
@@ -6796,7 +6718,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
@@ -6836,7 +6757,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
@@ -6875,7 +6795,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT8: /* 0xdc */
@@ -6915,7 +6834,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT8: /* 0xdd */
@@ -6954,7 +6872,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT8: /* 0xde */
@@ -6993,7 +6910,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
@@ -7032,7 +6948,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_LIT8: /* 0xe0 */
@@ -7071,7 +6986,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_LIT8: /* 0xe1 */
@@ -7110,7 +7024,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_LIT8: /* 0xe2 */
@@ -7149,86 +7062,251 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: armv5te/OP_UNUSED_E3.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: armv5te/OP_UNUSED_E4.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: armv5te/OP_UNUSED_E5.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: armv5te/OP_UNUSED_E6.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r1, [r0, #offStaticField_value] @ field<- vAA
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: armv5te/OP_UNUSED_E7.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_OBJECT_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: armv5te/OP_UNUSED_E8.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ /* iget-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_WIDE_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: armv5te/OP_UNUSED_E9.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+ /* iput-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: armv5te/OP_UNUSED_EA.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ /* sget-wide vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 1
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: armv5te/OP_UNUSED_EB.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-wide vAA, field@BBBB */
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r2, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
@@ -7239,7 +7317,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
@@ -7257,7 +7334,6 @@
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
@@ -7336,7 +7412,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
@@ -7355,26 +7430,24 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
/* File: armv6t2/OP_IGET_WIDE_QUICK.S */
/* iget-wide-quick vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
- FETCH(r1, 1) @ r1<- field byte offset
+ FETCH(ip, 1) @ ip<- field byte offset
GET_VREG(r3, r2) @ r3<- object we're operating on
ubfx r2, rINST, #8, #4 @ r2<- A
cmp r3, #0 @ check object for null
beq common_errNullObject @ object was null
- ldrd r0, [r3, r1] @ r0<- obj.field (64 bits, aligned)
+ ldrd r0, [r3, ip] @ r0<- obj.field (64 bits, aligned)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
@@ -7396,7 +7469,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
@@ -7415,7 +7487,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
@@ -7434,13 +7505,11 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7450,13 +7519,14 @@
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
+ cmp r0, #0
+ strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7536,7 +7606,6 @@
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodNoRange @ continue on
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -7566,31 +7635,85 @@
bl common_invokeMethodRange @ continue on
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: armv5te/OP_UNUSED_FC.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: armv5te/OP_UNUSED_FD.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_OBJECT_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: armv5te/OP_UNUSED_FE.S */
-/* File: armv5te/unused.S */
- bl common_abort
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+ /*
+ * 32-bit SPUT handler for objects
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
@@ -7603,7 +7726,6 @@
-
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
@@ -7639,7 +7761,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_STRING_JUMBO */
/*
@@ -7659,7 +7780,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_CLASS */
/*
@@ -7680,7 +7800,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CHECK_CAST */
/*
@@ -7725,7 +7844,6 @@
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
-
/* continuation for OP_INSTANCE_OF */
/*
@@ -7781,7 +7899,6 @@
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .LOP_INSTANCE_OF_resolved @ pick up where we left off
-
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
@@ -7824,7 +7941,6 @@
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
-
/* continuation for OP_NEW_ARRAY */
@@ -7864,7 +7980,6 @@
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_FILLED_NEW_ARRAY */
/*
@@ -7875,15 +7990,15 @@
.LOP_FILLED_NEW_ARRAY_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 0
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -7891,7 +8006,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -7923,8 +8039,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -7943,7 +8064,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
/*
@@ -7954,15 +8074,15 @@
.LOP_FILLED_NEW_ARRAY_RANGE_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 1
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -7970,7 +8090,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8002,8 +8123,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8022,31 +8148,26 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPG_FLOAT */
.LOP_CMPG_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPL_DOUBLE */
.LOP_CMPL_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPG_DOUBLE */
.LOP_CMPG_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMP_LONG */
.LOP_CMP_LONG_less:
@@ -8068,7 +8189,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_AGET_WIDE */
.LOP_AGET_WIDE_finish:
@@ -8079,7 +8199,6 @@
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
@@ -8089,7 +8208,6 @@
strd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_OBJECT */
/*
* On entry:
@@ -8105,13 +8223,19 @@
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
+ add r10, #offArrayObject_contents @ r0<- pointer to slot
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r9, [r10] @ vBB[vCC]<- vAA
+ strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
+ GOTO_OPCODE(ip) @ jump to next instruction
.LOP_APUT_OBJECT_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET */
/*
@@ -8131,7 +8255,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_WIDE */
/*
@@ -8151,7 +8274,6 @@
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_OBJECT */
/*
@@ -8165,6 +8287,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8172,7 +8295,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BOOLEAN */
/*
@@ -8186,6 +8308,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8193,7 +8316,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BYTE */
/*
@@ -8207,6 +8329,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8214,7 +8337,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_CHAR */
/*
@@ -8228,6 +8350,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8235,7 +8358,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_SHORT */
/*
@@ -8249,6 +8371,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8256,7 +8379,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT */
/*
@@ -8276,7 +8398,6 @@
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_WIDE */
/*
@@ -8296,7 +8417,6 @@
strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_OBJECT */
/*
@@ -8311,13 +8431,17 @@
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ @ no-op @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BOOLEAN */
/*
@@ -8335,10 +8459,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BYTE */
/*
@@ -8356,10 +8480,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_CHAR */
/*
@@ -8377,10 +8501,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_SHORT */
/*
@@ -8398,10 +8522,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SGET */
/*
@@ -8417,12 +8541,13 @@
bne .LOP_SGET_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8433,7 +8558,6 @@
bne .LOP_SGET_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_OBJECT */
/*
@@ -8449,7 +8573,6 @@
bne .LOP_SGET_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BOOLEAN */
/*
@@ -8465,7 +8588,6 @@
bne .LOP_SGET_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BYTE */
/*
@@ -8481,7 +8603,6 @@
bne .LOP_SGET_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_CHAR */
/*
@@ -8497,7 +8618,6 @@
bne .LOP_SGET_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_SHORT */
/*
@@ -8513,7 +8633,6 @@
bne .LOP_SGET_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT */
/*
@@ -8529,13 +8648,14 @@
bne .LOP_SPUT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8543,25 +8663,23 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_OBJECT */
-
- /*
- * Continuation if the field has not yet been resolved.
- * r1: BBBB field ref
- */
-.LOP_SPUT_OBJECT_resolve:
- ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
- EXPORT_PC() @ resolve() could throw, so export now
- ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
- bl dvmResolveStaticField @ r0<- resolved StaticField ptr
- cmp r0, #0 @ success?
- bne .LOP_SPUT_OBJECT_finish @ yes, finish
- b common_exceptionThrown @ no, handle exception
-
+.LOP_SPUT_OBJECT_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ @ no-op @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SPUT_BOOLEAN */
@@ -8578,7 +8696,6 @@
bne .LOP_SPUT_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_BYTE */
/*
@@ -8594,7 +8711,6 @@
bne .LOP_SPUT_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_CHAR */
/*
@@ -8610,7 +8726,6 @@
bne .LOP_SPUT_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_SHORT */
/*
@@ -8626,7 +8741,6 @@
bne .LOP_SPUT_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL */
/*
@@ -8644,7 +8758,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
-
/* continuation for OP_INVOKE_SUPER */
/*
@@ -8679,7 +8792,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT */
/*
@@ -8697,7 +8809,6 @@
bne .LOP_INVOKE_DIRECT_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
/*
@@ -8715,7 +8826,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
-
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
@@ -8750,7 +8860,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
@@ -8768,7 +8877,6 @@
bne .LOP_INVOKE_DIRECT_RANGE_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_FLOAT_TO_LONG */
/*
* Convert the float in r0 to a long in r0/r1.
@@ -8806,7 +8914,6 @@
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
/* continuation for OP_DOUBLE_TO_LONG */
/*
* Convert the double in r0/r1 to a long in r0/r1.
@@ -8857,7 +8964,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
/* continuation for OP_MUL_LONG */
.LOP_MUL_LONG_finish:
@@ -8865,7 +8971,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
@@ -8874,7 +8979,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG */
.LOP_SHR_LONG_finish:
@@ -8883,7 +8987,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG */
.LOP_USHR_LONG_finish:
@@ -8892,7 +8995,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG_2ADDR */
.LOP_SHL_LONG_2ADDR_finish:
@@ -8900,7 +9002,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG_2ADDR */
.LOP_SHR_LONG_2ADDR_finish:
@@ -8908,7 +9009,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG_2ADDR */
.LOP_USHR_LONG_2ADDR_finish:
@@ -8916,6 +9016,184 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
+/* continuation for OP_IGET_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_VOLATILE_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ .if 1
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+ mov r2, rINST, lsr #8 @ r2<- A+
+ cmp r9, #0 @ check object for null
+ and r2, r2, #15 @ r2<- A
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r2, {r0-r1} @ r0/r1<- fp[A]
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
+ */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ * r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
+ */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
+ bne .LOP_SPUT_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* continuation for OP_EXECUTE_INLINE */
@@ -8952,7 +9230,6 @@
.LOP_EXECUTE_INLINE_table:
.word gDvmInlineOpsTable
-
/* continuation for OP_EXECUTE_INLINE_RANGE */
/*
@@ -8982,6 +9259,59 @@
.LOP_EXECUTE_INLINE_RANGE_table:
.word gDvmInlineOpsTable
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+.LOP_SPUT_OBJECT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ SMP_DMB @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
@@ -9017,12 +9347,21 @@
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9031,7 +9370,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9040,7 +9379,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9049,7 +9388,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9058,7 +9397,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9073,7 +9412,7 @@
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
@@ -9114,7 +9453,7 @@
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9123,9 +9462,9 @@
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9137,6 +9476,7 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
+ add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
@@ -9180,7 +9520,8 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
-#ifdef JIT_STATS
+ add rINST,#-4 @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
@@ -9200,9 +9541,32 @@
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9227,6 +9591,7 @@
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -9347,6 +9712,11 @@
/*
* Common code when a backward branch is taken.
*
+ * TODO: we could avoid a branch by just setting r0 and falling through
+ * into the common_periodicChecks code, and having a test on r0 at the
+ * end determine if we should return to the caller or update & branch to
+ * the next instr.
+ *
* On entry:
* r9 is PC adjustment *in bytes*
*/
@@ -9369,23 +9739,25 @@
/*
* Need to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
+ * activity has begun. If so, we suspend the thread or side-exit to
+ * the debug interpreter as appropriate.
*
- * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
- * have to do the second ldr.
+ * The common case is no activity on any of these, so we want to figure
+ * that out quickly. If something is up, we can then sort out what.
+ *
+ * We want to be fast if the VM was built without debugger or profiler
+ * support, but we also need to recognize that the system is usually
+ * shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
- * r0 is reentry type, e.g. kInterpEntryInstr
+ * r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
- @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
- str r0, [rGLUE, #offGlue_entryPoint]
-
#if defined(WITH_DEBUGGER)
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
#endif
@@ -9393,33 +9765,42 @@
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
#endif
- ldr r3, [r3] @ r3<- suspendCount (int)
+ ldr ip, [r3] @ ip<- suspendCount (int)
-#if defined(WITH_DEBUGGER)
- ldrb r1, [r1] @ r1<- debuggerActive (boolean)
-#endif
-#if defined (WITH_PROFILER)
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
+ orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
+#elif defined(WITH_DEBUGGER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+ orrsne ip, ip, r1 @ yes, ip<- suspend | debugger; set Z
+ @ (if not enabled, Z was set by test for r1==0, which is what we want)
+#elif defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrs ip, ip, r2 @ ip<- suspendCount | activeProfilers
+#else
+ cmp ip, #0 @ not ORing anything in; set Z
#endif
- cmp r3, #0 @ suspend pending?
- bne 2f @ yes, do full suspension check
+ bxeq lr @ all zero, return
+ /*
+ * One or more interesting events have happened. Figure out what.
+ *
+ * If debugging or profiling are compiled in, we need to disambiguate.
+ *
+ * r0 still holds the reentry type.
+ */
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
-# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
- orrs r1, r1, r2 @ r1<- r1 | r2
- cmp r1, #0 @ debugger attached or profiler started?
-# elif defined(WITH_DEBUGGER)
- cmp r1, #0 @ debugger attached?
-# elif defined(WITH_PROFILER)
- cmp r2, #0 @ profiler started?
-# endif
- bne 3f @ debugger/profiler, switch interp
+ ldr ip, [r3] @ ip<- suspendCount (int)
+ cmp ip, #0 @ want suspend?
+ beq 1f @ no, must be debugger/profiler
#endif
- bx lr @ nothing to do, return
-
-2: @ check suspend
+ stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
@@ -9434,12 +9815,45 @@
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
- b dvmCheckSuspendPending @ suspend if necessary, then return
+ bl dvmCheckSuspendPending @ do full check, suspend if necessary
+ ldmfd sp!, {r0, lr} @ restore r0 and lr
-3: @ debugger/profiler enabled, bail out
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+
+ /*
+ * Reload the debugger/profiler enable flags. We're checking to see
+ * if either of these got set while we were suspended.
+ *
+ * We can't really avoid the #ifdefs here, because the fields don't
+ * exist when the feature is disabled.
+ */
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+#else
+ mov r1, #0
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#else
+ mov r2, #0
+#endif
+
+ orrs r1, r1, r2
+ beq 2f
+
+1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
- b common_gotoBail
+ b common_gotoBail @ side exit
+
+#endif /*WITH_DEBUGGER || WITH_PROFILER*/
+
+2:
+ bx lr @ nothing to do, return
/*
@@ -9543,7 +9957,7 @@
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
- blt .LstackOverflow @ yes, this frame will overflow stack
+ blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
@@ -9718,15 +10132,12 @@
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
@@ -10163,4 +10574,3 @@
.LstrPrintLong:
.asciz "<%lld>"
-
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index 082dffd..213c513 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -20,6 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* ARMv5 definitions and declarations.
*/
@@ -205,7 +206,7 @@
#include "../common/jit-config.h"
#endif
-/* File: armv5te/platform.S */
+/* File: armv7-a/platform.S */
/*
* ===========================================================================
* CPU-version-specific defines
@@ -242,6 +243,21 @@
ldmfd sp!, {\regs,pc}
.endm
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ * If the argument is nonzero, emit barrier; otherwise, emit nothing.
+ */
+.macro SMP_DMB
+#if ANDROID_SMP != 0
+ dmb
+#else
+ /* not SMP */
+#endif
+.endm
/* File: armv5te/entry.S */
/*
@@ -314,14 +330,27 @@
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -396,7 +425,6 @@
.word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
@@ -420,7 +448,6 @@
.fnend
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
@@ -435,7 +462,6 @@
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_FROM16: /* 0x02 */
@@ -450,7 +476,6 @@
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
@@ -465,7 +490,6 @@
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE: /* 0x04 */
@@ -482,7 +506,6 @@
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
@@ -499,7 +522,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
@@ -516,7 +538,6 @@
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT: /* 0x07 */
@@ -534,7 +555,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
@@ -551,7 +571,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
@@ -568,7 +587,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT: /* 0x0a */
@@ -582,7 +600,6 @@
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
@@ -597,7 +614,6 @@
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
@@ -613,7 +629,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_EXCEPTION: /* 0x0d */
@@ -629,14 +644,12 @@
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
/* File: armv5te/OP_RETURN_VOID.S */
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -653,7 +666,6 @@
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
@@ -670,7 +682,6 @@
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_OBJECT: /* 0x11 */
@@ -689,7 +700,6 @@
b common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
@@ -703,7 +713,6 @@
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
@@ -716,7 +725,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST: /* 0x14 */
@@ -731,7 +739,6 @@
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_HIGH16: /* 0x15 */
@@ -745,7 +752,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_16: /* 0x16 */
@@ -760,7 +766,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_32: /* 0x17 */
@@ -777,7 +782,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE: /* 0x18 */
@@ -796,7 +800,6 @@
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
@@ -812,7 +815,6 @@
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
@@ -891,7 +893,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
@@ -920,7 +921,6 @@
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
-
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
@@ -995,7 +995,6 @@
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_NEW_INSTANCE: /* 0x22 */
@@ -1131,13 +1130,13 @@
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
@@ -1193,7 +1192,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO_32: /* 0x2a */
@@ -1266,7 +1264,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_SPARSE_SWITCH: /* 0x2c */
@@ -1306,7 +1303,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_CMPL_FLOAT: /* 0x2d */
@@ -1539,7 +1535,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NE: /* 0x33 */
@@ -1575,7 +1570,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LT: /* 0x34 */
@@ -1611,7 +1605,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GE: /* 0x35 */
@@ -1647,7 +1640,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GT: /* 0x36 */
@@ -1683,7 +1675,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LE: /* 0x37 */
@@ -1719,7 +1710,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_EQZ: /* 0x38 */
@@ -1756,7 +1746,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
@@ -1793,7 +1782,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
@@ -1830,7 +1818,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
@@ -1867,7 +1854,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
@@ -1904,7 +1890,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
@@ -1941,7 +1926,6 @@
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
@@ -1950,7 +1934,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
@@ -1959,7 +1942,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
@@ -1968,7 +1950,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
@@ -1977,7 +1958,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
@@ -1986,7 +1966,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
@@ -1995,7 +1974,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
@@ -2026,7 +2004,6 @@
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
@@ -2086,7 +2063,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
@@ -2119,7 +2095,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
@@ -2152,7 +2127,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
@@ -2185,7 +2159,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
@@ -2218,7 +2191,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
@@ -2249,7 +2221,6 @@
str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
@@ -2337,7 +2308,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
@@ -2370,7 +2340,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
@@ -2403,7 +2372,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
@@ -2436,7 +2404,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
@@ -2682,11 +2649,10 @@
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: armv5te/OP_IPUT_OBJECT.S */
-/* File: armv5te/OP_IPUT.S */
/*
- * General 32-bit instance field put.
+ * 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2705,7 +2671,6 @@
bne .LOP_IPUT_OBJECT_finish @ yes, finish up
b common_exceptionThrown
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2715,7 +2680,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2744,7 +2709,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2773,7 +2738,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2802,7 +2767,7 @@
/*
* General 32-bit instance field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
@@ -2840,6 +2805,7 @@
beq .LOP_SGET_resolve @ yes, do resolve
.LOP_SGET_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2861,11 +2827,16 @@
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_resolve @ yes, do resolve
.LOP_SGET_WIDE_finish:
- mov r1, rINST, lsr #8 @ r1<- AA
- ldrd r2, [r0, #offStaticField_value] @ r2/r3<- field value (aligned)
- add r1, rFP, r1, lsl #2 @ r1<- &fp[AA]
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 0
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
@@ -2888,6 +2859,7 @@
beq .LOP_SGET_OBJECT_resolve @ yes, do resolve
.LOP_SGET_OBJECT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2914,6 +2886,7 @@
beq .LOP_SGET_BOOLEAN_resolve @ yes, do resolve
.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2940,6 +2913,7 @@
beq .LOP_SGET_BYTE_resolve @ yes, do resolve
.LOP_SGET_BYTE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2966,6 +2940,7 @@
beq .LOP_SGET_CHAR_resolve @ yes, do resolve
.LOP_SGET_CHAR_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -2992,6 +2967,7 @@
beq .LOP_SGET_SHORT_resolve @ yes, do resolve
.LOP_SGET_SHORT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
@@ -3006,7 +2982,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3020,6 +2996,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3031,30 +3008,34 @@
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
- ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
- ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
- ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
- cmp r0, #0 @ is resolved entry null?
+ cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
-.LOP_SPUT_WIDE_finish: @ field ptr in r0, AA in r9
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- strd r2, [r0, #offStaticField_value] @ field<- vAA/vAA+1
- GOTO_OPCODE(ip) @ jump to next instruction
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 0
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: armv5te/OP_SPUT_OBJECT.S */
-/* File: armv5te/OP_SPUT.S */
/*
- * General 32-bit SPUT handler.
+ * 32-bit SPUT handler for objects
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3062,14 +3043,14 @@
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
- beq .LOP_SPUT_OBJECT_resolve @ yes, do resolve
-.LOP_SPUT_OBJECT_finish: @ field ptr in r0
- mov r2, rINST, lsr #8 @ r2<- AA
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
- GET_VREG(r1, r2) @ r1<- fp[AA]
- GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r1, [r0, #offStaticField_value] @ field<- vAA
- GOTO_OPCODE(ip) @ jump to next instruction
+ bne .LOP_SPUT_OBJECT_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
@@ -3080,7 +3061,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3094,6 +3075,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3106,7 +3088,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3120,6 +3102,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3132,7 +3115,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3146,6 +3129,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3158,7 +3142,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
@@ -3172,6 +3156,7 @@
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
@@ -3294,7 +3279,6 @@
bne common_invokeMethodNoRange @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE: /* 0x72 */
@@ -3321,8 +3305,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodNoRange @ jump to common handler
-
+ b common_invokeMethodNoRange @ jump to common handler
/* ------------------------------ */
.balign 64
@@ -3332,7 +3315,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
@@ -3459,7 +3441,6 @@
b common_exceptionThrown @ yes, handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
@@ -3487,8 +3468,7 @@
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
- b common_invokeMethodRange @ jump to common handler
-
+ b common_invokeMethodRange @ jump to common handler
/* ------------------------------ */
@@ -3499,7 +3479,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
@@ -3508,7 +3487,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
@@ -3588,7 +3566,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
@@ -3616,7 +3593,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
@@ -3670,7 +3646,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
@@ -3765,7 +3740,6 @@
GOTO_OPCODE(ip) @ execute next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_FLOAT: /* 0x85 */
@@ -3822,7 +3796,6 @@
/* 10-11 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
@@ -3955,7 +3928,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
@@ -4100,7 +4072,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -4142,7 +4113,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -4185,7 +4155,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT: /* 0x93 */
@@ -4227,7 +4196,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
@@ -4270,7 +4238,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT: /* 0x95 */
@@ -4312,7 +4279,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -4354,7 +4320,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -4396,7 +4361,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -4438,7 +4402,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT: /* 0x99 */
@@ -4480,7 +4443,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT: /* 0x9a */
@@ -4522,7 +4484,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG: /* 0x9b */
@@ -4567,7 +4528,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG: /* 0x9c */
@@ -4612,7 +4572,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG: /* 0x9d */
@@ -4696,7 +4655,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG: /* 0x9f */
@@ -4742,7 +4700,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG: /* 0xa0 */
@@ -4787,7 +4744,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG: /* 0xa1 */
@@ -4832,7 +4788,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG: /* 0xa2 */
@@ -4877,7 +4832,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG: /* 0xa3 */
@@ -5127,7 +5081,6 @@
/* 11-14 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
@@ -5293,7 +5246,6 @@
/* 14-17 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_2ADDR: /* 0xb0 */
@@ -5332,7 +5284,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
@@ -5371,7 +5322,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
@@ -5411,7 +5361,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_2ADDR: /* 0xb3 */
@@ -5450,7 +5399,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
@@ -5490,7 +5438,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
@@ -5529,7 +5476,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
@@ -5568,7 +5514,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
@@ -5607,7 +5552,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
@@ -5646,7 +5590,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
@@ -5685,7 +5628,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
@@ -5724,7 +5666,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
@@ -5765,7 +5706,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG_2ADDR: /* 0xbc */
@@ -5806,7 +5746,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG_2ADDR: /* 0xbd */
@@ -5836,7 +5775,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG_2ADDR: /* 0xbe */
@@ -5877,7 +5815,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG_2ADDR: /* 0xbf */
@@ -5919,7 +5856,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG_2ADDR: /* 0xc0 */
@@ -5960,7 +5896,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG_2ADDR: /* 0xc1 */
@@ -6001,7 +5936,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
@@ -6042,7 +5976,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
@@ -6269,7 +6202,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
@@ -6427,7 +6359,6 @@
/* 12-15 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT16: /* 0xd0 */
@@ -6463,7 +6394,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
@@ -6500,7 +6430,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT16: /* 0xd2 */
@@ -6537,7 +6466,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT16: /* 0xd3 */
@@ -6573,7 +6501,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT16: /* 0xd4 */
@@ -6610,7 +6537,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT16: /* 0xd5 */
@@ -6646,7 +6572,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT16: /* 0xd6 */
@@ -6682,7 +6607,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
@@ -6718,7 +6642,6 @@
/* 10-13 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT8: /* 0xd8 */
@@ -6757,7 +6680,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT_LIT8: /* 0xd9 */
@@ -6796,7 +6718,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
@@ -6836,7 +6757,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
@@ -6875,7 +6795,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT8: /* 0xdc */
@@ -6915,7 +6834,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT8: /* 0xdd */
@@ -6954,7 +6872,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT8: /* 0xde */
@@ -6993,7 +6910,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
@@ -7032,7 +6948,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_LIT8: /* 0xe0 */
@@ -7071,7 +6986,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_LIT8: /* 0xe1 */
@@ -7110,7 +7024,6 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_LIT8: /* 0xe2 */
@@ -7149,86 +7062,251 @@
/* 10-12 instructions */
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: armv5te/OP_UNUSED_E3.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: armv5te/OP_UNUSED_E4.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: armv5te/OP_UNUSED_E5.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: armv5te/OP_UNUSED_E6.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r1, [r0, #offStaticField_value] @ field<- vAA
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: armv5te/OP_UNUSED_E7.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_OBJECT_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: armv5te/OP_UNUSED_E8.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ /* iget-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IGET_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0
+ bne .LOP_IGET_WIDE_VOLATILE_finish
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: armv5te/OP_UNUSED_E9.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+ /* iput-wide vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_WIDE_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: armv5te/OP_UNUSED_EA.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ /* sget-wide vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+ mov r9, rINST, lsr #8 @ r9<- AA
+ .if 1
+ add r0, r0, #offStaticField_value @ r0<- pointer to data
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+ .endif
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: armv5te/OP_UNUSED_EB.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-wide vAA, field@BBBB */
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r2, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_VOLATILE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r2, #offStaticField_value @ r2<- pointer to data
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
@@ -7239,7 +7317,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
@@ -7257,7 +7334,6 @@
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
@@ -7336,7 +7412,6 @@
bl common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
@@ -7355,7 +7430,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
@@ -7374,7 +7448,6 @@
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
@@ -7396,7 +7469,6 @@
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
@@ -7415,7 +7487,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
@@ -7434,13 +7505,11 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
-/* File: armv5te/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
@@ -7450,13 +7519,14 @@
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
+ cmp r0, #0
+ strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -7536,7 +7606,6 @@
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodNoRange @ continue on
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -7566,31 +7635,85 @@
bl common_invokeMethodRange @ continue on
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: armv5te/OP_UNUSED_FC.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ /* op vA, vB, field@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref CCCC
+ ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+ GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ no, already resolved
+8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveInstField @ r0<- resolved InstField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_IPUT_OBJECT_VOLATILE_finish @ yes, finish up
+ b common_exceptionThrown
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: armv5te/OP_UNUSED_FD.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SGET_OBJECT_VOLATILE_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r2) @ fp[AA]<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: armv5te/OP_UNUSED_FE.S */
-/* File: armv5te/unused.S */
- bl common_abort
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+ /*
+ * 32-bit SPUT handler for objects
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
+ FETCH(r1, 1) @ r1<- field ref BBBB
+ ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ is resolved entry null?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ no, continue
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
@@ -7603,7 +7726,6 @@
-
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
@@ -7639,7 +7761,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_STRING_JUMBO */
/*
@@ -7659,7 +7780,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CONST_CLASS */
/*
@@ -7680,7 +7800,6 @@
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CHECK_CAST */
/*
@@ -7725,7 +7844,6 @@
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
-
/* continuation for OP_INSTANCE_OF */
/*
@@ -7781,7 +7899,6 @@
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .LOP_INSTANCE_OF_resolved @ pick up where we left off
-
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
@@ -7824,7 +7941,6 @@
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
-
/* continuation for OP_NEW_ARRAY */
@@ -7864,7 +7980,6 @@
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_FILLED_NEW_ARRAY */
/*
@@ -7875,15 +7990,15 @@
.LOP_FILLED_NEW_ARRAY_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 0
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -7891,7 +8006,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -7923,8 +8039,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -7943,7 +8064,6 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
/*
@@ -7954,15 +8074,15 @@
.LOP_FILLED_NEW_ARRAY_RANGE_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
- ldrb r3, [r3, #1] @ r3<- descriptor[1]
+ ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 1
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
- cmp r3, #'I' @ array of ints?
- cmpne r3, #'L' @ array of objects?
- cmpne r3, #'[' @ array of arrays?
+ cmp rINST, #'I' @ array of ints?
+ cmpne rINST, #'L' @ array of objects?
+ cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
@@ -7970,7 +8090,8 @@
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
- str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
@@ -8002,8 +8123,13 @@
.endif
2:
- GET_INST_OPCODE(ip) @ ip<- opcode from rINST
- GOTO_OPCODE(ip) @ execute it
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
+ ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ cmp r1, #'I' @ Is int array?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
+ GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
@@ -8022,31 +8148,26 @@
.word .LstrInternalError
.endif
-
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPG_FLOAT */
.LOP_CMPG_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPL_DOUBLE */
.LOP_CMPL_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMPG_DOUBLE */
.LOP_CMPG_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_CMP_LONG */
.LOP_CMP_LONG_less:
@@ -8068,7 +8189,6 @@
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_AGET_WIDE */
.LOP_AGET_WIDE_finish:
@@ -8079,7 +8199,6 @@
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
@@ -8089,7 +8208,6 @@
strd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_APUT_OBJECT */
/*
* On entry:
@@ -8105,13 +8223,19 @@
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
+ add r10, #offArrayObject_contents @ r0<- pointer to slot
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r9, [r10] @ vBB[vCC]<- vAA
+ strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
+ GOTO_OPCODE(ip) @ jump to next instruction
.LOP_APUT_OBJECT_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET */
/*
@@ -8131,7 +8255,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_WIDE */
/*
@@ -8151,7 +8274,6 @@
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_OBJECT */
/*
@@ -8165,6 +8287,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8172,7 +8295,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BOOLEAN */
/*
@@ -8186,6 +8308,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8193,7 +8316,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_BYTE */
/*
@@ -8207,6 +8329,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8214,7 +8337,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_CHAR */
/*
@@ -8228,6 +8350,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8235,7 +8358,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IGET_SHORT */
/*
@@ -8249,6 +8371,7 @@
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ @ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
@@ -8256,7 +8379,6 @@
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT */
/*
@@ -8276,7 +8398,6 @@
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_WIDE */
/*
@@ -8296,7 +8417,6 @@
strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_OBJECT */
/*
@@ -8311,13 +8431,17 @@
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
- str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ @ no-op @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BOOLEAN */
/*
@@ -8335,10 +8459,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_BYTE */
/*
@@ -8356,10 +8480,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_CHAR */
/*
@@ -8377,10 +8501,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_IPUT_SHORT */
/*
@@ -8398,10 +8522,10 @@
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
+ @ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SGET */
/*
@@ -8417,12 +8541,13 @@
bne .LOP_SGET_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8433,7 +8558,6 @@
bne .LOP_SGET_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_OBJECT */
/*
@@ -8449,7 +8573,6 @@
bne .LOP_SGET_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BOOLEAN */
/*
@@ -8465,7 +8588,6 @@
bne .LOP_SGET_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_BYTE */
/*
@@ -8481,7 +8603,6 @@
bne .LOP_SGET_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_CHAR */
/*
@@ -8497,7 +8618,6 @@
bne .LOP_SGET_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SGET_SHORT */
/*
@@ -8513,7 +8633,6 @@
bne .LOP_SGET_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT */
/*
@@ -8529,13 +8648,14 @@
bne .LOP_SPUT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
@@ -8543,25 +8663,23 @@
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_OBJECT */
-
- /*
- * Continuation if the field has not yet been resolved.
- * r1: BBBB field ref
- */
-.LOP_SPUT_OBJECT_resolve:
- ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
- EXPORT_PC() @ resolve() could throw, so export now
- ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
- bl dvmResolveStaticField @ r0<- resolved StaticField ptr
- cmp r0, #0 @ success?
- bne .LOP_SPUT_OBJECT_finish @ yes, finish
- b common_exceptionThrown @ no, handle exception
-
+.LOP_SPUT_OBJECT_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ @ no-op @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SPUT_BOOLEAN */
@@ -8578,7 +8696,6 @@
bne .LOP_SPUT_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_BYTE */
/*
@@ -8594,7 +8711,6 @@
bne .LOP_SPUT_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_CHAR */
/*
@@ -8610,7 +8726,6 @@
bne .LOP_SPUT_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_SPUT_SHORT */
/*
@@ -8626,7 +8741,6 @@
bne .LOP_SPUT_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL */
/*
@@ -8644,7 +8758,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
-
/* continuation for OP_INVOKE_SUPER */
/*
@@ -8679,7 +8792,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT */
/*
@@ -8697,7 +8809,6 @@
bne .LOP_INVOKE_DIRECT_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
/*
@@ -8715,7 +8826,6 @@
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
-
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
@@ -8750,7 +8860,6 @@
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
@@ -8768,7 +8877,6 @@
bne .LOP_INVOKE_DIRECT_RANGE_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
-
/* continuation for OP_FLOAT_TO_LONG */
/*
* Convert the float in r0 to a long in r0/r1.
@@ -8806,7 +8914,6 @@
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
-
/* continuation for OP_DOUBLE_TO_LONG */
/*
* Convert the double in r0/r1 to a long in r0/r1.
@@ -8857,7 +8964,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
/* continuation for OP_MUL_LONG */
.LOP_MUL_LONG_finish:
@@ -8865,7 +8971,6 @@
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
@@ -8874,7 +8979,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG */
.LOP_SHR_LONG_finish:
@@ -8883,7 +8987,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG */
.LOP_USHR_LONG_finish:
@@ -8892,7 +8995,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHL_LONG_2ADDR */
.LOP_SHL_LONG_2ADDR_finish:
@@ -8900,7 +9002,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_SHR_LONG_2ADDR */
.LOP_SHR_LONG_2ADDR_finish:
@@ -8908,7 +9009,6 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
-
/* continuation for OP_USHR_LONG_2ADDR */
.LOP_USHR_LONG_2ADDR_finish:
@@ -8916,6 +9016,184 @@
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
+/* continuation for OP_IGET_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SPUT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
+ SMP_DMB @ acquiring load
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_VOLATILE_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ .if 1
+ add r0, r9, r3 @ r0<- address of field
+ bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
+ .else
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ .endif
+ mov r2, rINST, lsr #8 @ r2<- A+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15 @ r2<- A
+ add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+ mov r2, rINST, lsr #8 @ r2<- A+
+ cmp r9, #0 @ check object for null
+ and r2, r2, #15 @ r2<- A
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldmia r2, {r0-r1} @ r0/r1<- fp[A]
+ GET_INST_OPCODE(r10) @ extract opcode from rINST
+ .if 1
+ add r2, r9, r3 @ r2<- target address
+ bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
+ .else
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
+ .endif
+ GOTO_OPCODE(r10) @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ *
+ * Returns StaticField pointer in r0.
+ */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ * r9: &fp[AA]
+ *
+ * Returns StaticField pointer in r2.
+ */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ mov r2, r0 @ copy to r2
+ bne .LOP_SPUT_WIDE_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
/* continuation for OP_EXECUTE_INLINE */
@@ -8952,7 +9230,6 @@
.LOP_EXECUTE_INLINE_table:
.word gDvmInlineOpsTable
-
/* continuation for OP_EXECUTE_INLINE_RANGE */
/*
@@ -8982,6 +9259,59 @@
.LOP_EXECUTE_INLINE_RANGE_table:
.word gDvmInlineOpsTable
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ @bl common_squeak0
+ mov r1, rINST, lsr #8 @ r1<- A+
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ and r1, r1, #15 @ r1<- A
+ cmp r9, #0 @ check object for null
+ GET_VREG(r0, r1) @ r0<- fp[A]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ beq common_errNullObject @ object was null
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r9, r3 @ r9<- direct ptr to target location
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SMP_DMB @ releasing store
+ str r0, [r9] @ obj.field (8/16/32 bits)<- r0
+ cmp r0, #0 @ stored a null reference?
+ strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ EXPORT_PC() @ resolve() could throw, so export now
+ ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveStaticField @ r0<- resolved StaticField ptr
+ cmp r0, #0 @ success?
+ bne .LOP_SGET_OBJECT_VOLATILE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+.LOP_SPUT_OBJECT_VOLATILE_finish: @ field ptr in r0
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r1, r2) @ r1<- fp[AA]
+ ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ add r0, #offStaticField_value @ r0<- pointer to store target
+ SMP_DMB @ releasing store
+ str r1, [r0] @ field<- vAA
+ cmp r1, #0 @ stored a null object?
+ strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
+ GOTO_OPCODE(ip) @ jump to next instruction
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
@@ -9017,12 +9347,21 @@
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9031,7 +9370,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9040,7 +9379,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9049,7 +9388,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9058,7 +9397,7 @@
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9073,7 +9412,7 @@
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
@@ -9114,7 +9453,7 @@
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9123,9 +9462,9 @@
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9137,6 +9476,7 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
+ add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
@@ -9180,7 +9520,8 @@
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
-#ifdef JIT_STATS
+ add rINST,#-4 @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
@@ -9200,9 +9541,32 @@
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
-#ifdef JIT_STATS
+#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
@@ -9227,6 +9591,7 @@
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -9347,6 +9712,11 @@
/*
* Common code when a backward branch is taken.
*
+ * TODO: we could avoid a branch by just setting r0 and falling through
+ * into the common_periodicChecks code, and having a test on r0 at the
+ * end determine if we should return to the caller or update & branch to
+ * the next instr.
+ *
* On entry:
* r9 is PC adjustment *in bytes*
*/
@@ -9369,23 +9739,25 @@
/*
* Need to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
+ * activity has begun. If so, we suspend the thread or side-exit to
+ * the debug interpreter as appropriate.
*
- * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
- * have to do the second ldr.
+ * The common case is no activity on any of these, so we want to figure
+ * that out quickly. If something is up, we can then sort out what.
+ *
+ * We want to be fast if the VM was built without debugger or profiler
+ * support, but we also need to recognize that the system is usually
+ * shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
- * r0 is reentry type, e.g. kInterpEntryInstr
+ * r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
- @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
- str r0, [rGLUE, #offGlue_entryPoint]
-
#if defined(WITH_DEBUGGER)
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
#endif
@@ -9393,33 +9765,42 @@
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
#endif
- ldr r3, [r3] @ r3<- suspendCount (int)
+ ldr ip, [r3] @ ip<- suspendCount (int)
-#if defined(WITH_DEBUGGER)
- ldrb r1, [r1] @ r1<- debuggerActive (boolean)
-#endif
-#if defined (WITH_PROFILER)
+#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
+ orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
+#elif defined(WITH_DEBUGGER)
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+ orrsne ip, ip, r1 @ yes, ip<- suspend | debugger; set Z
+ @ (if not enabled, Z was set by test for r1==0, which is what we want)
+#elif defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+ orrs ip, ip, r2 @ ip<- suspendCount | activeProfilers
+#else
+ cmp ip, #0 @ not ORing anything in; set Z
#endif
- cmp r3, #0 @ suspend pending?
- bne 2f @ yes, do full suspension check
+ bxeq lr @ all zero, return
+ /*
+ * One or more interesting events have happened. Figure out what.
+ *
+ * If debugging or profiling are compiled in, we need to disambiguate.
+ *
+ * r0 still holds the reentry type.
+ */
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
-# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
- orrs r1, r1, r2 @ r1<- r1 | r2
- cmp r1, #0 @ debugger attached or profiler started?
-# elif defined(WITH_DEBUGGER)
- cmp r1, #0 @ debugger attached?
-# elif defined(WITH_PROFILER)
- cmp r2, #0 @ profiler started?
-# endif
- bne 3f @ debugger/profiler, switch interp
+ ldr ip, [r3] @ ip<- suspendCount (int)
+ cmp ip, #0 @ want suspend?
+ beq 1f @ no, must be debugger/profiler
#endif
- bx lr @ nothing to do, return
-
-2: @ check suspend
+ stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
@@ -9434,12 +9815,45 @@
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
- b dvmCheckSuspendPending @ suspend if necessary, then return
+ bl dvmCheckSuspendPending @ do full check, suspend if necessary
+ ldmfd sp!, {r0, lr} @ restore r0 and lr
-3: @ debugger/profiler enabled, bail out
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+
+ /*
+ * Reload the debugger/profiler enable flags. We're checking to see
+ * if either of these got set while we were suspended.
+ *
+ * We can't really avoid the #ifdefs here, because the fields don't
+ * exist when the feature is disabled.
+ */
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+ cmp r1, #0 @ debugger enabled?
+ ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
+#else
+ mov r1, #0
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#else
+ mov r2, #0
+#endif
+
+ orrs r1, r1, r2
+ beq 2f
+
+1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
- b common_gotoBail
+ b common_gotoBail @ side exit
+
+#endif /*WITH_DEBUGGER || WITH_PROFILER*/
+
+2:
+ bx lr @ nothing to do, return
/*
@@ -9543,7 +9957,7 @@
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
- blt .LstackOverflow @ yes, this frame will overflow stack
+ blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
@@ -9718,15 +10132,12 @@
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
@@ -10163,4 +10574,3 @@
.LstrPrintLong:
.asciz "<%lld>"
-
diff --git a/vm/mterp/out/InterpAsm-x86-atom.S b/vm/mterp/out/InterpAsm-x86-atom.S
index 778fa48..d259f6e 100644
--- a/vm/mterp/out/InterpAsm-x86-atom.S
+++ b/vm/mterp/out/InterpAsm-x86-atom.S
@@ -528,7 +528,6 @@
MTERP_ENTRY
#endif
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
@@ -732,7 +731,6 @@
movq %xmm0, (rFP, rINST, 4) # vA<- vB
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
@@ -1153,7 +1151,6 @@
SET_VREG %edx, rINST # vAA<- glue->self->exception
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
@@ -1179,7 +1176,6 @@
jmp common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -1240,8 +1236,6 @@
jmp common_returnFromMethod # jump to common return code
-
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
@@ -1341,7 +1335,6 @@
jmp common_returnFromMethod # jump to common return code
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
@@ -1875,7 +1868,6 @@
#endif
FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
@@ -1927,7 +1919,6 @@
je common_exceptionThrown # handle exception
FINISH_JMP %edx # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
@@ -2419,7 +2410,6 @@
movl rINST, offThread_exception(%ecx) # thread->exception<- object
jmp common_exceptionThrown # handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
@@ -2461,7 +2451,6 @@
js common_periodicChecks2 # do check on backwards branch
FINISH_RB %edx, %ecx # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_GOTO_16: /* 0x29 */
@@ -2543,7 +2532,6 @@
jc common_periodicChecks2 # do check on backwards branch
FINISH_RB %edx, %ecx # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_PACKED_SWITCH: /* 0x2b */
@@ -3975,7 +3963,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
@@ -4032,7 +4019,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
@@ -4089,7 +4075,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
@@ -4146,7 +4131,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
@@ -4203,7 +4187,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
@@ -4260,7 +4243,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
@@ -5876,8 +5858,6 @@
jmp .LOP_IPUT_OBJECT_finish
-
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -6328,8 +6308,6 @@
jmp .LOP_SGET_OBJECT_finish
-
-
/* ------------------------------ */
.balign 64
.L_OP_SGET_BOOLEAN: /* 0x63 */
@@ -6395,7 +6373,6 @@
jmp .LOP_SGET_BOOLEAN_finish
-
/* ------------------------------ */
.balign 64
.L_OP_SGET_BYTE: /* 0x64 */
@@ -7377,7 +7354,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
@@ -7851,7 +7827,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
@@ -7908,7 +7883,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
@@ -8111,9 +8085,6 @@
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
@@ -8182,8 +8153,6 @@
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
@@ -8319,9 +8288,6 @@
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
@@ -8408,7 +8374,6 @@
movss %xmm0, (rFP, rINST, 4) # vA<- %xmm0
FINISH 1 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_DOUBLE: /* 0x83 */
@@ -8598,7 +8563,6 @@
fstpl (rFP, %ecx, 4) # vA<- FPU; (double) vB
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
@@ -9066,7 +9030,6 @@
SET_VREG %ecx, rINST # vA<- result
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT: /* 0x90 */
@@ -9135,8 +9098,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -9205,9 +9166,6 @@
OLD_JMP_4 %eax
-
-
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -9330,7 +9288,6 @@
.endif
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
@@ -9480,9 +9437,6 @@
OLD_JMP_4 %eax
-
-
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -9551,8 +9505,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -9621,8 +9573,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -10468,7 +10418,6 @@
movsd %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
FINISH 2 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_FLOAT: /* 0xa6 */
@@ -10751,7 +10700,6 @@
fstps (rFP, rINST, 4) # vAA<- remainder; return of fmod
FINISH 2 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
@@ -10989,7 +10937,6 @@
FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE: /* 0xaf */
@@ -11108,8 +11055,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
@@ -11180,8 +11125,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
@@ -11300,7 +11243,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
@@ -11385,7 +11327,6 @@
-
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
@@ -11456,8 +11397,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
@@ -11528,8 +11467,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
@@ -11600,8 +11537,6 @@
OLD_JMP_4 %eax
-
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
@@ -12385,7 +12320,6 @@
movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
FINISH 1 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
@@ -12479,7 +12413,6 @@
movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
FINISH 1 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
@@ -12769,9 +12702,6 @@
fstps (rFP, rINST, 4)
FINISH 1 # jump to next instruction
-
-
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
@@ -13018,7 +12948,6 @@
fstpl (rFP, %edx, 4) # vAA<- result
FINISH 1 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
@@ -13729,7 +13658,6 @@
SET_VREG %edx, rINST # vAA<- %edx; result
FINISH 2 # jump to next instruction
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
@@ -14353,8 +14281,7 @@
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: x86-atom/OP_UNUSED_E3.S */
+.L_OP_IGET_VOLATILE: /* 0xe3 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14371,47 +14298,18 @@
*/
/*
- * File: OP_UNUSED_E3.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_IGET_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: x86-atom/OP_UNUSED_E4.S */
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14428,47 +14326,18 @@
*/
/*
- * File: OP_UNUSED_E4.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_IPUT_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: x86-atom/OP_UNUSED_E5.S */
+.L_OP_SGET_VOLATILE: /* 0xe5 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14485,47 +14354,18 @@
*/
/*
- * File: OP_UNUSED_E5.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_SGET_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: x86-atom/OP_UNUSED_E6.S */
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14542,47 +14382,18 @@
*/
/*
- * File: OP_UNUSED_E6.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_SPUT_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: x86-atom/OP_UNUSED_E7.S */
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14599,47 +14410,18 @@
*/
/*
- * File: OP_UNUSED_E7.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_IGET_OBJECT_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: x86-atom/OP_UNUSED_E8.S */
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14656,47 +14438,18 @@
*/
/*
- * File: OP_UNUSED_E8.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_IGET_WIDE_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: x86-atom/OP_UNUSED_E9.S */
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14713,47 +14466,18 @@
*/
/*
- * File: OP_UNUSED_E9.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_IPUT_WIDE_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: x86-atom/OP_UNUSED_EA.S */
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14770,47 +14494,18 @@
*/
/*
- * File: OP_UNUSED_EA.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_SGET_WIDE_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: x86-atom/OP_UNUSED_EB.S */
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14827,43 +14522,15 @@
*/
/*
- * File: OP_UNUSED_EB.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_SPUT_WIDE_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_BREAKPOINT: /* 0xec */
@@ -14914,7 +14581,7 @@
/*
* File: OP_THROW_VERIFICATION_ERROR.S
*
- * Code:
+ * Code:
*
* For: throw-verification-error
*
@@ -14926,16 +14593,16 @@
* Syntax: op vAA, ref@BBBB
*/
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %ecx # %ecx<- glue->method
- EXPORT_PC # in case an exception is thrown
- FETCH 1, %eax # %eax<- BBBB
- movl %eax, -4(%esp) # push parameter BBBB; ref
- movl rINST, -8(%esp) # push parameter AA
- movl %ecx, -12(%esp) # push parameter glue->method
+ movl rGLUE, %edx # %edx<- pMterpGlue
+ movl offGlue_method(%edx), %ecx # %ecx<- glue->method
+ EXPORT_PC # in case an exception is thrown
+ FETCH 1, %eax # %eax<- BBBB
+ movl %eax, -4(%esp) # push parameter BBBB; ref
+ movl rINST, -8(%esp) # push parameter AA
+ movl %ecx, -12(%esp) # push parameter glue->method
lea -12(%esp), %esp
- call dvmThrowVerificationError # call: (const Method* method, int kind, int ref)
- jmp common_exceptionThrown # failed; handle exception
+ call dvmThrowVerificationError # call: (const Method* method, int kind, int ref)
+ jmp common_exceptionThrown # failed; handle exception
/* ------------------------------ */
.balign 64
@@ -15094,7 +14761,6 @@
call common_abort
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
@@ -15181,8 +14847,6 @@
movq %xmm0, (rFP, rINST, 4) # fp[A]<- %xmm0
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
@@ -15289,8 +14953,6 @@
movl rINST, (%eax, %ecx) # object field<- vA
FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
@@ -15334,7 +14996,6 @@
movq %xmm0, (%edx, %ecx) # object field<- %xmm0; fp[A]
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
@@ -15398,8 +15059,6 @@
FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
@@ -15442,8 +15101,6 @@
movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
jmp common_invokeMethodNoRange # invoke method common code
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
@@ -15507,8 +15164,6 @@
jmp common_invokeMethodRange # invoke method common code
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
@@ -15553,9 +15208,6 @@
je common_errNullObject # handle null object
jmp common_invokeMethodNoRange # invoke method common code
-
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -15621,13 +15273,9 @@
jmp common_invokeMethodRange # invoke method common code
-
-
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: x86-atom/OP_UNUSED_FC.S */
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -15644,47 +15292,18 @@
*/
/*
- * File: OP_UNUSED_FC.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_IPUT_OBJECT_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: x86-atom/OP_UNUSED_FD.S */
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -15701,47 +15320,18 @@
*/
/*
- * File: OP_UNUSED_FD.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_SGET_OBJECT_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: x86-atom/OP_UNUSED_FE.S */
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -15758,43 +15348,15 @@
*/
/*
- * File: OP_UNUSED_FE.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_SPUT_OBJECT_VOLATILE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_FF: /* 0xff */
@@ -15852,7 +15414,6 @@
-
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
@@ -16228,7 +15789,6 @@
SET_VREG %eax, rINST # vA<- pArray
FINISH 2 # jump to next instruction
-
/* continuation for OP_FILLED_NEW_ARRAY */
.LOP_FILLED_NEW_ARRAY_break:
@@ -16441,12 +16001,10 @@
.LOP_PACKED_SWITCH_finish:
FINISH_RB %edx, %ecx # jump to next instruction
-
/* continuation for OP_SPARSE_SWITCH */
.LOP_SPARSE_SWITCH_finish:
FINISH_RB %edx, %ecx # jump to next instruction
-
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_greater:
movl $0x1, (rFP, rINST, 4) # vAA<- greater than
@@ -16513,8 +16071,6 @@
movl $0x1, (rFP, rINST, 4) # vAA<- greater than
FINISH 2 # jump to next instruction
-
-
/* continuation for OP_APUT_OBJECT */
.LOP_APUT_OBJECT_finish:
@@ -16594,8 +16150,6 @@
movq %xmm0, (rFP, rINST, 4) # vA<- %xmm0; object field
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
/* continuation for OP_IGET_OBJECT */
.LOP_IGET_OBJECT_finish:
@@ -16760,7 +16314,6 @@
movl rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* continuation for OP_IPUT_WIDE */
.LOP_IPUT_WIDE_finish2:
@@ -16791,8 +16344,6 @@
movq %xmm0, (%ecx, %edx) # object field<- %xmm0; vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
/* continuation for OP_IPUT_OBJECT */
.LOP_IPUT_OBJECT_finish:
@@ -16822,7 +16373,6 @@
movl rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* continuation for OP_IPUT_BOOLEAN */
.LOP_IPUT_BOOLEAN_finish:
@@ -16852,7 +16402,6 @@
movl rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* continuation for OP_IPUT_BYTE */
.LOP_IPUT_BYTE_finish:
@@ -16882,7 +16431,6 @@
movl rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* continuation for OP_IPUT_CHAR */
.LOP_IPUT_CHAR_finish:
@@ -16912,7 +16460,6 @@
movl rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* continuation for OP_IPUT_SHORT */
.LOP_IPUT_SHORT_finish:
@@ -16942,7 +16489,6 @@
movl rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
/* continuation for OP_SGET */
.LOP_SGET_resolve:
@@ -17287,7 +16833,6 @@
movl (%edx, %eax, 4), %ecx # %ecx<- vtable[methodIndex]
jmp common_invokeMethodNoRange # invoke method common code
-
/* continuation for OP_INVOKE_SUPER */
.LOP_INVOKE_SUPER_continue2:
@@ -17338,7 +16883,6 @@
movl offMethod_name(%ecx), %edx # %edx<- method name
jmp common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT */
/*
@@ -17384,8 +16928,6 @@
movl %eax, %ecx # %ecx<- method
jmp common_invokeMethodNoRange # invoke method common code
-
-
/* continuation for OP_INVOKE_INTERFACE */
.LOP_INVOKE_INTERFACE_break:
movl rGLUE, %ecx # %ecx<- pMterpGlue
@@ -17439,7 +16981,6 @@
movl (%edx, %eax, 4), %ecx # %ecx<- vtable[methodIndex]
jmp common_invokeMethodRange # invoke method common code
-
/* continuation for OP_INVOKE_SUPER_RANGE */
.LOP_INVOKE_SUPER_RANGE_continue2:
@@ -17490,7 +17031,6 @@
movl offMethod_name(%ecx), %edx # %edx<- method name
jmp common_errNoSuchMethod
-
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
@@ -17536,8 +17076,6 @@
movl %eax, %ecx # %ecx<- method
jmp common_invokeMethodRange # invoke method common code
-
-
/* continuation for OP_INVOKE_INTERFACE_RANGE */
.LOP_INVOKE_INTERFACE_RANGE_break:
movl rGLUE, %ecx # %ecx<- pMterpGlue
@@ -17614,8 +17152,6 @@
movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
FINISH 1 # jump to next instruction
-
-
/* continuation for OP_DOUBLE_TO_INT */
.LOP_DOUBLE_TO_INT_break:
@@ -17644,7 +17180,6 @@
movl $0x80000000, (rFP, %edx, 4) # vA<- negInf
FINISH 1 # jump to next instruction
-
/* continuation for OP_DOUBLE_TO_LONG */
.LOP_DOUBLE_TO_LONG_break:
@@ -17676,7 +17211,6 @@
movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
FINISH 1 # jump to next instruction
-
/* continuation for OP_DIV_INT */
.LOP_DIV_INT_break:
FFETCH_ADV 2 %eax
@@ -17718,7 +17252,6 @@
movl %eax, (rFP, rINST, 4) # vAA<- results lo
FINISH 2 # jump to next instruction
-
/* continuation for OP_DIV_LONG */
.LOP_DIV_LONG_finish:
movq %xmm0, -16(%esp) # push arg vBB,vBB+1
@@ -17752,7 +17285,6 @@
movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
FINISH 2 # jump to next instruction
-
/* continuation for OP_REM_DOUBLE */
.LOP_REM_DOUBLE_break:
@@ -17762,7 +17294,6 @@
fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
FINISH 2 # jump to next instruction
-
/* continuation for OP_DIV_INT_2ADDR */
.LOP_DIV_INT_2ADDR_break:
FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
@@ -17773,7 +17304,6 @@
.endif
FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
/* continuation for OP_REM_INT_2ADDR */
.LOP_REM_INT_2ADDR_break:
FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
@@ -17784,7 +17314,6 @@
.endif
FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
/* continuation for OP_MUL_LONG_2ADDR */
/*
@@ -17808,7 +17337,6 @@
movl %eax, (rFP, %edx, 4) # vA<- results lo
FINISH 1 # jump to next instruction
-
/* continuation for OP_DIV_LONG_2ADDR */
.LOP_DIV_LONG_2ADDR_break:
movq %xmm0, -20(%esp) # push arg vA, vA+1
@@ -17842,8 +17370,6 @@
movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
FINISH 1 # jump to next instruction
-
-
/* continuation for OP_REM_DOUBLE_2ADDR */
.LOP_REM_DOUBLE_2ADDR_break:
@@ -17853,14 +17379,6 @@
fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
FINISH 1 # jump to next instruction
-
-
-
-
-
-
-
-
/* continuation for OP_DIV_INT_LIT16 */
.LOP_DIV_INT_LIT16_break:
movzbl (rPC), %edx
@@ -17872,7 +17390,6 @@
movzbl 1(rPC), rINST
jmp *dvmAsmInstructionJmpTable(, %edx, 4)
-
/* continuation for OP_REM_INT_LIT16 */
.LOP_REM_INT_LIT16_break:
movzbl (rPC), %edx
@@ -17884,7 +17401,6 @@
movzbl 1(rPC), rINST
jmp *dvmAsmInstructionJmpTable(, %edx, 4)
-
/* continuation for OP_DIV_INT_LIT8 */
.LOP_DIV_INT_LIT8_break:
movzbl (rPC), %edx
@@ -18327,14 +17843,14 @@
.long .L_OP_UNUSED_E5
.long .L_OP_UNUSED_E6
.long .L_OP_UNUSED_E7
-.long .L_OP_UNUSED_E8
-.long .L_OP_UNUSED_E9
-.long .L_OP_UNUSED_EA
-.long .L_OP_UNUSED_EB
-.long .L_OP_UNUSED_EC
+.long .L_OP_IGET_WIDE_VOLATILE
+.long .L_OP_IPUT_WIDE_VOLATILE
+.long .L_OP_SGET_WIDE_VOLATILE
+.long .L_OP_SPUT_WIDE_VOLATILE
+.long .L_OP_BREAKPOINT
.long .L_OP_THROW_VERIFICATION_ERROR
.long .L_OP_EXECUTE_INLINE
-.long .L_OP_UNUSED_EF
+.long .L_OP_EXECUTE_INLINE_RANGE
.long .L_OP_INVOKE_DIRECT_EMPTY
.long .L_OP_UNUSED_F1
.long .L_OP_IGET_QUICK
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index 1d9f36b..5dd2601 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -215,7 +215,6 @@
#include "../common/asm-constants.h"
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
@@ -258,7 +257,6 @@
SET_VREG (%ecx,%eax) # fp[AA]<- ecx]
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
@@ -355,7 +353,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
@@ -438,7 +435,6 @@
/* File: x86/OP_RETURN_VOID.S */
jmp common_returnFromMethod
-
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
@@ -506,7 +502,6 @@
SET_VREG(%eax,%ecx)
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
@@ -591,7 +586,6 @@
ADVANCE_PC(5)
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
@@ -607,7 +601,6 @@
SET_VREG_WORD(%eax,%ecx,0) # v[AA+0]<- eax
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
@@ -927,6 +920,7 @@
*/
/* throw vAA */
GET_GLUE(%ecx)
+ EXPORT_PC()
movzbl rINST_HI,rINST_FULL # rINST_FULL<- AA
GET_VREG(%eax,rINST_FULL) # eax<- exception object
movl offGlue_self(%ecx),%ecx # ecx<- glue->self
@@ -1422,7 +1416,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
@@ -1450,7 +1443,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
@@ -1478,7 +1470,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
@@ -1506,7 +1497,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
@@ -1534,7 +1524,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
@@ -1562,7 +1551,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
@@ -1637,7 +1625,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
@@ -1686,7 +1673,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
@@ -1715,7 +1701,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
@@ -1744,7 +1729,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
@@ -1773,7 +1757,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
@@ -1802,7 +1785,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
@@ -1829,7 +1811,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
@@ -1900,7 +1881,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
@@ -1929,7 +1909,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
@@ -1958,7 +1937,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
@@ -1987,7 +1965,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
@@ -2244,12 +2221,10 @@
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: x86/OP_IPUT_OBJECT.S */
-/* File: x86/OP_IPUT.S */
-
/*
- * General 32-bit instance field put.
+ * Object field put.
*
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ * for: iput-object
*/
/* op vA, vB, field@CCCC */
GET_GLUE(%ecx)
@@ -2269,7 +2244,6 @@
GET_GLUE(rIBASE)
jmp .LOP_IPUT_OBJECT_resolve
-
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
@@ -2583,7 +2557,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
@@ -2632,28 +2606,21 @@
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: x86/OP_SPUT_OBJECT.S */
-/* File: x86/OP_SPUT.S */
/*
- * General 32-bit SPUT handler.
- *
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * SPUT object handler.
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offGlue_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
- movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
+ movl (%ecx,%eax,4),%eax # eax<- resolved StaticField
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_OBJECT_resolve # if not, make it so
.LOP_SPUT_OBJECT_finish: # field ptr in eax
movzbl rINST_HI,%ecx # ecx<- AA
GET_VREG(%ecx,%ecx)
- FETCH_INST_WORD(2)
- movl %ecx,offStaticField_value(%eax)
- ADVANCE_PC(2)
- GOTO_NEXT
-
+ jmp .LOP_SPUT_OBJECT_continue
/* ------------------------------ */
.balign 64
@@ -2663,7 +2630,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
@@ -2690,7 +2657,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
@@ -2717,7 +2684,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
@@ -2744,7 +2711,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
@@ -3621,7 +3588,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
@@ -3648,7 +3614,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
@@ -3749,7 +3714,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
@@ -3776,7 +3740,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
@@ -3803,7 +3766,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
@@ -4211,7 +4173,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT: /* 0xa7 */
@@ -4234,7 +4195,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT: /* 0xa8 */
@@ -4257,7 +4217,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT: /* 0xa9 */
@@ -4280,7 +4239,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT: /* 0xaa */
@@ -4324,7 +4282,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE: /* 0xac */
@@ -4347,7 +4304,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE: /* 0xad */
@@ -4370,7 +4326,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE: /* 0xae */
@@ -4393,7 +4348,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE: /* 0xaf */
@@ -4660,7 +4614,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
@@ -4683,7 +4636,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
@@ -4706,7 +4658,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
@@ -5407,7 +5358,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
@@ -5507,7 +5457,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
@@ -5614,7 +5563,6 @@
GOTO_NEXT
-
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
@@ -5725,76 +5673,202 @@
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E3: /* 0xe3 */
-/* File: x86/OP_UNUSED_E3.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: x86/OP_IGET_VOLATILE.S */
+/* File: x86/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ GET_GLUE(%ecx)
+ SPILL(rIBASE) # need another reg
+ movzwl 2(rPC),rIBASE # rIBASE<- 0000CCCC
+ movl offGlue_methodClassDex(%ecx),%eax # eax<- DvmDex
+ movzbl rINST_HI,%ecx # ecx<- BA
+ sarl $4,%ecx # ecx<- B
+ movl offDvmDex_pResFields(%eax),%eax # eax<- pDvmDex->pResFields
+ movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
+ andb $0xf,rINST_LO # rINST_FULL<- A
+ GET_VREG(%ecx,%ecx) # ecx<- fp[B], the object ptr
+ movl (%eax,rIBASE,4),%eax # resolved entry
+ testl %eax,%eax # is resolved entry null?
+ jne .LOP_IGET_VOLATILE_finish # no, already resolved
+ movl rIBASE,OUT_ARG1(%esp) # needed by dvmResolveInstField
+ GET_GLUE(rIBASE)
+ jmp .LOP_IGET_VOLATILE_resolve
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E4: /* 0xe4 */
-/* File: x86/OP_UNUSED_E4.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: x86/OP_IPUT_VOLATILE.S */
+/* File: x86/OP_IPUT.S */
+
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ /* op vA, vB, field@CCCC */
+ GET_GLUE(%ecx)
+ SPILL(rIBASE) # need another reg
+ movzwl 2(rPC),rIBASE # rIBASE<- 0000CCCC
+ movl offGlue_methodClassDex(%ecx),%eax # eax<- DvmDex
+ movzbl rINST_HI,%ecx # ecx<- BA
+ sarl $4,%ecx # ecx<- B
+ movl offDvmDex_pResFields(%eax),%eax # eax<- pDvmDex->pResFields
+ movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
+ andb $0xf,rINST_LO # rINST_FULL<- A
+ GET_VREG(%ecx,%ecx) # ecx<- fp[B], the object ptr
+ movl (%eax,rIBASE,4),%eax # resolved entry
+ testl %eax,%eax # is resolved entry null?
+ jne .LOP_IPUT_VOLATILE_finish # no, already resolved
+ movl rIBASE,OUT_ARG1(%esp)
+ GET_GLUE(rIBASE)
+ jmp .LOP_IPUT_VOLATILE_resolve
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E5: /* 0xe5 */
-/* File: x86/OP_UNUSED_E5.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: x86/OP_SGET_VOLATILE.S */
+/* File: x86/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_methodClassDex(%ecx),%ecx # ecx<- DvmDex
+ movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+ movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
+ testl %eax,%eax # resolved entry null?
+ je .LOP_SGET_VOLATILE_resolve # if not, make it so
+.LOP_SGET_VOLATILE_finish: # field ptr in eax
+ movl offStaticField_value(%eax),%eax
+ movzbl rINST_HI,%ecx # ecx<- AA
+ FETCH_INST_WORD(2)
+ ADVANCE_PC(2)
+ SET_VREG(%eax,%ecx)
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E6: /* 0xe6 */
-/* File: x86/OP_UNUSED_E6.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: x86/OP_SPUT_VOLATILE.S */
+/* File: x86/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ /* op vAA, field@BBBB */
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_methodClassDex(%ecx),%ecx # ecx<- DvmDex
+ movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+ movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
+ testl %eax,%eax # resolved entry null?
+ je .LOP_SPUT_VOLATILE_resolve # if not, make it so
+.LOP_SPUT_VOLATILE_finish: # field ptr in eax
+ movzbl rINST_HI,%ecx # ecx<- AA
+ GET_VREG(%ecx,%ecx)
+ FETCH_INST_WORD(2)
+ movl %ecx,offStaticField_value(%eax)
+ ADVANCE_PC(2)
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E7: /* 0xe7 */
-/* File: x86/OP_UNUSED_E7.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: x86/OP_IGET_OBJECT_VOLATILE.S */
+/* File: x86/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ /* op vA, vB, field@CCCC */
+ GET_GLUE(%ecx)
+ SPILL(rIBASE) # need another reg
+ movzwl 2(rPC),rIBASE # rIBASE<- 0000CCCC
+ movl offGlue_methodClassDex(%ecx),%eax # eax<- DvmDex
+ movzbl rINST_HI,%ecx # ecx<- BA
+ sarl $4,%ecx # ecx<- B
+ movl offDvmDex_pResFields(%eax),%eax # eax<- pDvmDex->pResFields
+ movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
+ andb $0xf,rINST_LO # rINST_FULL<- A
+ GET_VREG(%ecx,%ecx) # ecx<- fp[B], the object ptr
+ movl (%eax,rIBASE,4),%eax # resolved entry
+ testl %eax,%eax # is resolved entry null?
+ jne .LOP_IGET_OBJECT_VOLATILE_finish # no, already resolved
+ movl rIBASE,OUT_ARG1(%esp) # needed by dvmResolveInstField
+ GET_GLUE(rIBASE)
+ jmp .LOP_IGET_OBJECT_VOLATILE_resolve
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E8: /* 0xe8 */
-/* File: x86/OP_UNUSED_E8.S */
-/* File: x86/unused.S */
- jmp common_abort
-
-
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+ /* (stub) */
+ GET_GLUE(%ecx)
+ SAVE_PC_TO_GLUE(%ecx) # only need to export these two
+ SAVE_FP_TO_GLUE(%ecx) # only need to export these two
+ movl %ecx,OUT_ARG0(%esp) # glue is first arg to function
+ call dvmMterp_OP_IGET_WIDE_VOLATILE # do the real work
+ GET_GLUE(%ecx)
+ LOAD_PC_FROM_GLUE(%ecx) # retrieve updated values
+ LOAD_FP_FROM_GLUE(%ecx) # retrieve updated values
+ FETCH_INST()
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_E9: /* 0xe9 */
-/* File: x86/OP_UNUSED_E9.S */
-/* File: x86/unused.S */
- jmp common_abort
-
-
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+ /* (stub) */
+ GET_GLUE(%ecx)
+ SAVE_PC_TO_GLUE(%ecx) # only need to export these two
+ SAVE_FP_TO_GLUE(%ecx) # only need to export these two
+ movl %ecx,OUT_ARG0(%esp) # glue is first arg to function
+ call dvmMterp_OP_IPUT_WIDE_VOLATILE # do the real work
+ GET_GLUE(%ecx)
+ LOAD_PC_FROM_GLUE(%ecx) # retrieve updated values
+ LOAD_FP_FROM_GLUE(%ecx) # retrieve updated values
+ FETCH_INST()
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EA: /* 0xea */
-/* File: x86/OP_UNUSED_EA.S */
-/* File: x86/unused.S */
- jmp common_abort
-
-
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+ /* (stub) */
+ GET_GLUE(%ecx)
+ SAVE_PC_TO_GLUE(%ecx) # only need to export these two
+ SAVE_FP_TO_GLUE(%ecx) # only need to export these two
+ movl %ecx,OUT_ARG0(%esp) # glue is first arg to function
+ call dvmMterp_OP_SGET_WIDE_VOLATILE # do the real work
+ GET_GLUE(%ecx)
+ LOAD_PC_FROM_GLUE(%ecx) # retrieve updated values
+ LOAD_FP_FROM_GLUE(%ecx) # retrieve updated values
+ FETCH_INST()
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EB: /* 0xeb */
-/* File: x86/OP_UNUSED_EB.S */
-/* File: x86/unused.S */
- jmp common_abort
-
-
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+ /* (stub) */
+ GET_GLUE(%ecx)
+ SAVE_PC_TO_GLUE(%ecx) # only need to export these two
+ SAVE_FP_TO_GLUE(%ecx) # only need to export these two
+ movl %ecx,OUT_ARG0(%esp) # glue is first arg to function
+ call dvmMterp_OP_SPUT_WIDE_VOLATILE # do the real work
+ GET_GLUE(%ecx)
+ LOAD_PC_FROM_GLUE(%ecx) # retrieve updated values
+ LOAD_FP_FROM_GLUE(%ecx) # retrieve updated values
+ FETCH_INST()
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
.L_OP_BREAKPOINT: /* 0xec */
@@ -5826,7 +5900,6 @@
UNSPILL(rPC)
jmp common_exceptionThrown # handle exception
-
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
@@ -5957,7 +6030,7 @@
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
/* File: x86/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-quick */
/* op vA, vB, offset@CCCC */
movzbl rINST_HI,%ecx # ecx<- BA
sarl $4,%ecx # ecx<- B
@@ -6000,8 +6073,7 @@
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: x86/OP_IPUT_OBJECT_QUICK.S */
-/* File: x86/OP_IPUT_QUICK.S */
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
movzbl rINST_HI,%ecx # ecx<- BA
sarl $4,%ecx # ecx<- B
@@ -6010,13 +6082,11 @@
andb $0xf,rINST_LO # rINST_FULL<- A
GET_VREG(rINST_FULL,rINST_FULL) # rINST_FULL<- v[A]
movzwl 2(rPC),%eax # eax<- field byte offset
- testl %ecx,%ecx # is object null?
+ testl %ecx,%ecx # is object null?
je common_errNullObject
movl rINST_FULL,(%ecx,%eax,1)
- FETCH_INST_WORD(2)
- ADVANCE_PC(2)
- GOTO_NEXT
-
+ GET_GLUE(%eax)
+ jmp .LOP_IPUT_OBJECT_QUICK_finish
/* ------------------------------ */
.balign 64
@@ -6043,8 +6113,6 @@
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
jmp common_invokeMethodNoRange
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
@@ -6072,8 +6140,6 @@
jmp common_invokeMethodRange
-
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
@@ -6102,7 +6168,6 @@
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
jmp common_invokeMethodNoRange
-
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
@@ -6133,29 +6198,82 @@
jmp common_invokeMethodRange
-
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FC: /* 0xfc */
-/* File: x86/OP_UNUSED_FC.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: x86/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: x86/OP_IPUT_OBJECT.S */
+ /*
+ * Object field put.
+ *
+ * for: iput-object
+ */
+ /* op vA, vB, field@CCCC */
+ GET_GLUE(%ecx)
+ SPILL(rIBASE) # need another reg
+ movzwl 2(rPC),rIBASE # rIBASE<- 0000CCCC
+ movl offGlue_methodClassDex(%ecx),%eax # eax<- DvmDex
+ movzbl rINST_HI,%ecx # ecx<- BA
+ sarl $4,%ecx # ecx<- B
+ movl offDvmDex_pResFields(%eax),%eax # eax<- pDvmDex->pResFields
+ movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
+ andb $0xf,rINST_LO # rINST_FULL<- A
+ GET_VREG(%ecx,%ecx) # ecx<- fp[B], the object ptr
+ movl (%eax,rIBASE,4),%eax # resolved entry
+ testl %eax,%eax # is resolved entry null?
+ jne .LOP_IPUT_OBJECT_VOLATILE_finish # no, already resolved
+ movl rIBASE,OUT_ARG1(%esp)
+ GET_GLUE(rIBASE)
+ jmp .LOP_IPUT_OBJECT_VOLATILE_resolve
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FD: /* 0xfd */
-/* File: x86/OP_UNUSED_FD.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: x86/OP_SGET_OBJECT_VOLATILE.S */
+/* File: x86/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ /* op vAA, field@BBBB */
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_methodClassDex(%ecx),%ecx # ecx<- DvmDex
+ movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+ movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
+ testl %eax,%eax # resolved entry null?
+ je .LOP_SGET_OBJECT_VOLATILE_resolve # if not, make it so
+.LOP_SGET_OBJECT_VOLATILE_finish: # field ptr in eax
+ movl offStaticField_value(%eax),%eax
+ movzbl rINST_HI,%ecx # ecx<- AA
+ FETCH_INST_WORD(2)
+ ADVANCE_PC(2)
+ SET_VREG(%eax,%ecx)
+ GOTO_NEXT
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_FE: /* 0xfe */
-/* File: x86/OP_UNUSED_FE.S */
-/* File: x86/unused.S */
- jmp common_abort
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: x86/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: x86/OP_SPUT_OBJECT.S */
+ /*
+ * SPUT object handler.
+ */
+ /* op vAA, field@BBBB */
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_methodClassDex(%ecx),%ecx # ecx<- DvmDex
+ movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+ movl (%ecx,%eax,4),%eax # eax<- resolved StaticField
+ testl %eax,%eax # resolved entry null?
+ je .LOP_SPUT_OBJECT_VOLATILE_resolve # if not, make it so
+.LOP_SPUT_OBJECT_VOLATILE_finish: # field ptr in eax
+ movzbl rINST_HI,%ecx # ecx<- AA
+ GET_VREG(%ecx,%ecx)
+ jmp .LOP_SPUT_OBJECT_VOLATILE_continue
/* ------------------------------ */
@@ -6206,7 +6324,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_CONST_STRING_JUMBO */
/* This is the less common path, so we'll redo some work
@@ -6230,7 +6347,6 @@
ADVANCE_PC(3)
GOTO_NEXT
-
/* continuation for OP_CONST_CLASS */
/* This is the less common path, so we'll redo some work
@@ -6255,7 +6371,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_MONITOR_ENTER */
.LOP_MONITOR_ENTER_continue:
@@ -6412,7 +6527,6 @@
movl offObject_clazz(%eax),%eax # eax<- obj->clazz
jmp .LOP_INSTANCE_OF_resolved
-
/* continuation for OP_NEW_INSTANCE */
.LOP_NEW_INSTANCE_initialized: # on entry, ecx<- class
@@ -6481,9 +6595,6 @@
UNSPILL(rPC)
jmp common_exceptionThrown
-
-
-
/* continuation for OP_NEW_ARRAY */
/*
@@ -6530,7 +6641,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_FILLED_NEW_ARRAY */
.LOP_FILLED_NEW_ARRAY_more:
@@ -6555,6 +6665,7 @@
movl $ALLOC_DONT_TRACK,OUT_ARG2(%esp) # arg2<- flags
movzbl 1(%ecx),%ecx # ecx<- descriptor[1]
movl %eax,OUT_ARG0(%esp) # arg0<- arrayClass
+ GET_GLUE(%eax)
cmpb $'I',%cl # supported?
je 1f
cmpb $'L',%cl
@@ -6562,6 +6673,7 @@
cmpb $'[',%cl
jne .LOP_FILLED_NEW_ARRAY_notimpl # no, not handled yet
1:
+ movl %ecx,offGlue_retval+4(%eax) # save type
.if (!0)
SPILL_TMP(rINST_FULL) # save copy, need "B" later
sarl $4,rINST_FULL
@@ -6595,7 +6707,9 @@
FETCH_INST_WORD(3)
rep
movsd
+ GET_GLUE(%ecx)
UNSPILL(rIBASE)
+ movl offGlue_retval+4(%ecx),%eax # eax<- type
UNSPILL(rFP)
.else
testl rINST_FULL,rINST_FULL
@@ -6614,10 +6728,19 @@
sub $1,rINST_FULL
jne 3b
4:
+ GET_GLUE(%ecx)
UNSPILL(rPC)
+ movl offGlue_retval+4(%ecx),%eax # eax<- type
FETCH_INST_WORD(3)
.endif
+ cmpb $'I',%al # Int array?
+ je 5f # skip card mark if so
+ movl offGlue_retval(%ecx),%eax # eax<- object head
+ movl offGlue_cardTable(%ecx),%ecx # card table base
+ shrl $GC_CARD_SHIFT,%eax # convert to card num
+ movb %cl,(%ecx,%eax) # mark card
+5:
ADVANCE_PC(3)
GOTO_NEXT
@@ -6635,7 +6758,6 @@
UNSPILL(rPC)
jmp common_exceptionThrown
-
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
.LOP_FILLED_NEW_ARRAY_RANGE_more:
@@ -6660,6 +6782,7 @@
movl $ALLOC_DONT_TRACK,OUT_ARG2(%esp) # arg2<- flags
movzbl 1(%ecx),%ecx # ecx<- descriptor[1]
movl %eax,OUT_ARG0(%esp) # arg0<- arrayClass
+ GET_GLUE(%eax)
cmpb $'I',%cl # supported?
je 1f
cmpb $'L',%cl
@@ -6667,6 +6790,7 @@
cmpb $'[',%cl
jne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl # no, not handled yet
1:
+ movl %ecx,offGlue_retval+4(%eax) # save type
.if (!1)
SPILL_TMP(rINST_FULL) # save copy, need "B" later
sarl $4,rINST_FULL
@@ -6700,7 +6824,9 @@
FETCH_INST_WORD(3)
rep
movsd
+ GET_GLUE(%ecx)
UNSPILL(rIBASE)
+ movl offGlue_retval+4(%ecx),%eax # eax<- type
UNSPILL(rFP)
.else
testl rINST_FULL,rINST_FULL
@@ -6719,10 +6845,19 @@
sub $1,rINST_FULL
jne 3b
4:
+ GET_GLUE(%ecx)
UNSPILL(rPC)
+ movl offGlue_retval+4(%ecx),%eax # eax<- type
FETCH_INST_WORD(3)
.endif
+ cmpb $'I',%al # Int array?
+ je 5f # skip card mark if so
+ movl offGlue_retval(%ecx),%eax # eax<- object head
+ movl offGlue_cardTable(%ecx),%ecx # card table base
+ shrl $GC_CARD_SHIFT,%eax # convert to card num
+ movb %cl,(%ecx,%eax) # mark card
+5:
ADVANCE_PC(3)
GOTO_NEXT
@@ -6740,7 +6875,6 @@
UNSPILL(rPC)
jmp common_exceptionThrown
-
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_isNaN:
@@ -6792,7 +6926,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
@@ -6805,7 +6938,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_APUT_OBJECT */
/* On entry:
@@ -6827,7 +6959,15 @@
UNSPILL(rPC)
UNSPILL_TMP(%ecx)
testl %eax,%eax
+ GET_GLUE(%eax)
je common_errArrayStore
+ movl offGlue_cardTable(%eax),%eax # get card table base
+ movl rINST_FULL,(%ecx)
+ FETCH_INST_WORD(2)
+ shrl $GC_CARD_SHIFT,%ecx # convert addr to card number
+ movb %al,(%eax,%ecx) # mark card
+ ADVANCE_PC(2)
+ GOTO_NEXT
.LOP_APUT_OBJECT_skip_check:
movl rINST_FULL,(%ecx)
@@ -6835,7 +6975,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET */
@@ -6873,7 +7012,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET_WIDE */
@@ -6913,7 +7051,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET_OBJECT */
@@ -6951,7 +7088,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET_BOOLEAN */
@@ -6989,7 +7125,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET_BYTE */
@@ -7027,7 +7162,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET_CHAR */
@@ -7065,7 +7199,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IGET_SHORT */
@@ -7103,7 +7236,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_IPUT */
@@ -7210,8 +7342,15 @@
UNSPILL(rIBASE)
testl %ecx,%ecx # object null?
je common_errNullObject # object was null
- movl rINST_FULL,(%ecx,%eax,1) # obj.field <- v[A](8/16/32 bits)
+ movl rINST_FULL,(%ecx,%eax) # obj.field <- v[A](8/16/32 bits)
+ GET_GLUE(%eax)
+ testl rINST_FULL,rINST_FULL # stored a NULL?
+ movl offGlue_cardTable(%eax),%eax # get card table base
FETCH_INST_WORD(2)
+ je 1f # skip card mark if null store
+ shrl $GC_CARD_SHIFT,%ecx # object head to card number
+ movb %al,(%eax,%ecx) # mark card
+1:
ADVANCE_PC(2)
GOTO_NEXT
@@ -7379,7 +7518,6 @@
jne .LOP_SGET_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SGET_WIDE */
/*
@@ -7400,7 +7538,6 @@
jne .LOP_SGET_WIDE_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SGET_OBJECT */
/*
@@ -7421,7 +7558,6 @@
jne .LOP_SGET_OBJECT_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SGET_BOOLEAN */
/*
@@ -7442,7 +7578,6 @@
jne .LOP_SGET_BOOLEAN_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SGET_BYTE */
/*
@@ -7463,7 +7598,6 @@
jne .LOP_SGET_BYTE_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SGET_CHAR */
/*
@@ -7484,7 +7618,6 @@
jne .LOP_SGET_CHAR_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SGET_SHORT */
/*
@@ -7505,7 +7638,6 @@
jne .LOP_SGET_SHORT_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT */
/*
@@ -7526,7 +7658,6 @@
jne .LOP_SPUT_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT_WIDE */
/*
@@ -7547,12 +7678,22 @@
jne .LOP_SPUT_WIDE_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT_OBJECT */
- /*
- * Go resolve the field
- */
+
+.LOP_SPUT_OBJECT_continue:
+ movl %ecx,offStaticField_value(%eax)
+ testl %ecx,%ecx
+ GET_GLUE(%ecx)
+ FETCH_INST_WORD(2)
+ je 1f
+ movl offGlue_cardTable(%ecx),%ecx # get card table base
+ shrl $GC_CARD_SHIFT,%eax # head to card number
+ movb %cl,(%ecx,%eax) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
.LOP_SPUT_OBJECT_resolve:
GET_GLUE(%ecx)
movzwl 2(rPC),%eax # eax<- field ref BBBB
@@ -7568,7 +7709,6 @@
jne .LOP_SPUT_OBJECT_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT_BOOLEAN */
/*
@@ -7589,7 +7729,6 @@
jne .LOP_SPUT_BOOLEAN_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT_BYTE */
/*
@@ -7610,7 +7749,6 @@
jne .LOP_SPUT_BYTE_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT_CHAR */
/*
@@ -7631,7 +7769,6 @@
jne .LOP_SPUT_CHAR_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_SPUT_SHORT */
/*
@@ -7652,7 +7789,6 @@
jne .LOP_SPUT_SHORT_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
/* continuation for OP_INVOKE_VIRTUAL */
@@ -7684,7 +7820,6 @@
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
jmp common_invokeMethodNoRange
-
/* continuation for OP_INVOKE_SUPER */
/*
@@ -7767,7 +7902,6 @@
jne common_invokeMethodNoRange
jmp common_exceptionThrown
-
/* continuation for OP_INVOKE_INTERFACE */
.LOP_INVOKE_INTERFACE_continue:
@@ -7777,7 +7911,6 @@
je common_exceptionThrown
jmp common_invokeMethodNoRange
-
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
@@ -7809,7 +7942,6 @@
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
jmp common_invokeMethodRange
-
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
@@ -7892,7 +8024,6 @@
jne common_invokeMethodRange
jmp common_exceptionThrown
-
/* continuation for OP_INVOKE_INTERFACE_RANGE */
.LOP_INVOKE_INTERFACE_RANGE_continue:
@@ -7902,7 +8033,6 @@
je common_exceptionThrown
jmp common_invokeMethodRange
-
/* continuation for OP_FLOAT_TO_INT */
@@ -8072,7 +8202,6 @@
ADVANCE_PC(2)
GOTO_NEXT
-
/* continuation for OP_DIV_LONG */
.LOP_DIV_LONG_continue:
@@ -8105,9 +8234,6 @@
movl $0x80000000,%edx
jmp .LOP_DIV_LONG_finish
-
-
-
/* continuation for OP_REM_LONG */
.LOP_REM_LONG_continue:
@@ -8140,9 +8266,6 @@
movl $0,%edx
jmp .LOP_REM_LONG_finish
-
-
-
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
@@ -8202,7 +8325,6 @@
ADVANCE_PC(1)
GOTO_NEXT
-
/* continuation for OP_DIV_LONG_2ADDR */
.LOP_DIV_LONG_2ADDR_continue:
@@ -8238,7 +8360,6 @@
movl $0x80000000,%edx
jmp .LOP_DIV_LONG_2ADDR_finish
-
/* continuation for OP_REM_LONG_2ADDR */
.LOP_REM_LONG_2ADDR_continue:
@@ -8274,7 +8395,6 @@
movl $0,%edx
jmp .LOP_REM_LONG_2ADDR_finish
-
/* continuation for OP_SHL_LONG_2ADDR */
@@ -8346,6 +8466,156 @@
ADVANCE_PC(2)
GOTO_NEXT
+/* continuation for OP_IGET_VOLATILE */
+
+
+.LOP_IGET_VOLATILE_resolve:
+ EXPORT_PC()
+ SPILL(rPC)
+ movl offGlue_method(rIBASE),rPC # rPC<- current method
+ UNSPILL(rIBASE)
+ movl offMethod_clazz(rPC),rPC # rPC<- method->clazz
+ SPILL_TMP(%ecx) # save object pointer across call
+ movl rPC,OUT_ARG0(%esp) # pass in method->clazz
+ call dvmResolveInstField # ... to dvmResolveInstField
+ UNSPILL_TMP(%ecx)
+ UNSPILL(rPC)
+ testl %eax,%eax # ... which returns InstrField ptr
+ jne .LOP_IGET_VOLATILE_finish
+ jmp common_exceptionThrown
+
+.LOP_IGET_VOLATILE_finish:
+ /*
+ * Currently:
+ * eax holds resolved field
+ * ecx holds object
+ * rIBASE is scratch, but needs to be unspilled
+ * rINST_FULL holds A
+ */
+ movl offInstField_byteOffset(%eax),%eax # eax<- byte offset of field
+ UNSPILL(rIBASE)
+ testl %ecx,%ecx # object null?
+ je common_errNullObject # object was null
+ movl (%ecx,%eax,1),%ecx # ecx<- obj.field (8/16/32 bits)
+ movl rINST_FULL,%eax # eax<- A
+ FETCH_INST_WORD(2)
+ SET_VREG(%ecx,%eax)
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
+/* continuation for OP_IPUT_VOLATILE */
+
+
+.LOP_IPUT_VOLATILE_resolve:
+ EXPORT_PC()
+ SPILL(rPC)
+ movl offGlue_method(rIBASE),rPC # rPC<- current method
+ UNSPILL(rIBASE)
+ movl offMethod_clazz(rPC),rPC # rPC<- method->clazz
+ SPILL_TMP(%ecx) # save object pointer across call
+ movl rPC,OUT_ARG0(%esp) # pass in method->clazz
+ call dvmResolveInstField # ... to dvmResolveInstField
+ UNSPILL_TMP(%ecx)
+ UNSPILL(rPC)
+ testl %eax,%eax # ... which returns InstrField ptr
+ jne .LOP_IPUT_VOLATILE_finish
+ jmp common_exceptionThrown
+
+.LOP_IPUT_VOLATILE_finish:
+ /*
+ * Currently:
+ * eax holds resolved field
+ * ecx holds object
+ * rIBASE is scratch, but needs to be unspilled
+ * rINST_FULL holds A
+ */
+ GET_VREG(rINST_FULL,rINST_FULL) # rINST_FULL<- v[A]
+ movl offInstField_byteOffset(%eax),%eax # eax<- byte offset of field
+ UNSPILL(rIBASE)
+ testl %ecx,%ecx # object null?
+ je common_errNullObject # object was null
+ movl rINST_FULL,(%ecx,%eax,1) # obj.field <- v[A](8/16/32 bits)
+ FETCH_INST_WORD(2)
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
+/* continuation for OP_SGET_VOLATILE */
+
+ /*
+ * Go resolve the field
+ */
+.LOP_SGET_VOLATILE_resolve:
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_method(%ecx),%ecx # ecx<- current method
+ EXPORT_PC() # could throw, need to export
+ movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+ SPILL(rPC)
+ movl %eax,OUT_ARG1(%esp)
+ movl %ecx,OUT_ARG0(%esp)
+ call dvmResolveStaticField # eax<- resolved StaticField ptr
+ UNSPILL(rPC)
+ testl %eax,%eax
+ jne .LOP_SGET_VOLATILE_finish # success, continue
+ jmp common_exceptionThrown # no, handle exception
+
+/* continuation for OP_SPUT_VOLATILE */
+
+ /*
+ * Go resolve the field
+ */
+.LOP_SPUT_VOLATILE_resolve:
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_method(%ecx),%ecx # ecx<- current method
+ EXPORT_PC() # could throw, need to export
+ movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+ SPILL(rPC)
+ movl %eax,OUT_ARG1(%esp)
+ movl %ecx,OUT_ARG0(%esp)
+ call dvmResolveStaticField # eax<- resolved StaticField ptr
+ UNSPILL(rPC)
+ testl %eax,%eax
+ jne .LOP_SPUT_VOLATILE_finish # success, continue
+ jmp common_exceptionThrown # no, handle exception
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+
+.LOP_IGET_OBJECT_VOLATILE_resolve:
+ EXPORT_PC()
+ SPILL(rPC)
+ movl offGlue_method(rIBASE),rPC # rPC<- current method
+ UNSPILL(rIBASE)
+ movl offMethod_clazz(rPC),rPC # rPC<- method->clazz
+ SPILL_TMP(%ecx) # save object pointer across call
+ movl rPC,OUT_ARG0(%esp) # pass in method->clazz
+ call dvmResolveInstField # ... to dvmResolveInstField
+ UNSPILL_TMP(%ecx)
+ UNSPILL(rPC)
+ testl %eax,%eax # ... which returns InstrField ptr
+ jne .LOP_IGET_OBJECT_VOLATILE_finish
+ jmp common_exceptionThrown
+
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ /*
+ * Currently:
+ * eax holds resolved field
+ * ecx holds object
+ * rIBASE is scratch, but needs to be unspilled
+ * rINST_FULL holds A
+ */
+ movl offInstField_byteOffset(%eax),%eax # eax<- byte offset of field
+ UNSPILL(rIBASE)
+ testl %ecx,%ecx # object null?
+ je common_errNullObject # object was null
+ movl (%ecx,%eax,1),%ecx # ecx<- obj.field (8/16/32 bits)
+ movl rINST_FULL,%eax # eax<- A
+ FETCH_INST_WORD(2)
+ SET_VREG(%ecx,%eax)
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
/* continuation for OP_EXECUTE_INLINE */
.LOP_EXECUTE_INLINE_continue:
@@ -8388,6 +8658,112 @@
jmp *gDvmInlineOpsTable(%eax)
# will return to caller of .LOP_EXECUTE_INLINE_continue
+/* continuation for OP_IPUT_OBJECT_QUICK */
+
+.LOP_IPUT_OBJECT_QUICK_finish:
+ testl rINST_FULL,rINST_FULL # did we store null?
+ FETCH_INST_WORD(2)
+ movl offGlue_cardTable(%eax),%eax # get card table base
+ je 1f # skip card mark if null store
+ shrl $GC_CARD_SHIFT,%ecx # object head to card number
+ movb %al,(%eax,%ecx) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+
+.LOP_IPUT_OBJECT_VOLATILE_resolve:
+ EXPORT_PC()
+ SPILL(rPC)
+ movl offGlue_method(rIBASE),rPC # rPC<- current method
+ UNSPILL(rIBASE)
+ movl offMethod_clazz(rPC),rPC # rPC<- method->clazz
+ SPILL_TMP(%ecx) # save object pointer across call
+ movl rPC,OUT_ARG0(%esp) # pass in method->clazz
+ call dvmResolveInstField # ... to dvmResolveInstField
+ UNSPILL_TMP(%ecx)
+ UNSPILL(rPC)
+ testl %eax,%eax # ... which returns InstrField ptr
+ jne .LOP_IPUT_OBJECT_VOLATILE_finish
+ jmp common_exceptionThrown
+
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ /*
+ * Currently:
+ * eax holds resolved field
+ * ecx holds object
+ * rIBASE is scratch, but needs to be unspilled
+ * rINST_FULL holds A
+ */
+ GET_VREG(rINST_FULL,rINST_FULL) # rINST_FULL<- v[A]
+ movl offInstField_byteOffset(%eax),%eax # eax<- byte offset of field
+ UNSPILL(rIBASE)
+ testl %ecx,%ecx # object null?
+ je common_errNullObject # object was null
+ movl rINST_FULL,(%ecx,%eax) # obj.field <- v[A](8/16/32 bits)
+ GET_GLUE(%eax)
+ testl rINST_FULL,rINST_FULL # stored a NULL?
+ movl offGlue_cardTable(%eax),%eax # get card table base
+ FETCH_INST_WORD(2)
+ je 1f # skip card mark if null store
+ shrl $GC_CARD_SHIFT,%ecx # object head to card number
+ movb %al,(%eax,%ecx) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+ /*
+ * Go resolve the field
+ */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_method(%ecx),%ecx # ecx<- current method
+ EXPORT_PC() # could throw, need to export
+ movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+ SPILL(rPC)
+ movl %eax,OUT_ARG1(%esp)
+ movl %ecx,OUT_ARG0(%esp)
+ call dvmResolveStaticField # eax<- resolved StaticField ptr
+ UNSPILL(rPC)
+ testl %eax,%eax
+ jne .LOP_SGET_OBJECT_VOLATILE_finish # success, continue
+ jmp common_exceptionThrown # no, handle exception
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_continue:
+ movl %ecx,offStaticField_value(%eax)
+ testl %ecx,%ecx
+ GET_GLUE(%ecx)
+ FETCH_INST_WORD(2)
+ je 1f
+ movl offGlue_cardTable(%ecx),%ecx # get card table base
+ shrl $GC_CARD_SHIFT,%eax # head to card number
+ movb %cl,(%ecx,%eax) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
+.LOP_SPUT_OBJECT_VOLATILE_resolve:
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_method(%ecx),%ecx # ecx<- current method
+ EXPORT_PC() # could throw, need to export
+ movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+ SPILL(rPC)
+ movl %eax,OUT_ARG1(%esp)
+ movl %ecx,OUT_ARG0(%esp)
+ call dvmResolveStaticField # eax<- resolved StaticField ptr
+ UNSPILL(rPC)
+ testl %eax,%eax
+ jne .LOP_SPUT_OBJECT_VOLATILE_finish # success, continue
+ jmp common_exceptionThrown # no, handle exception
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
@@ -8785,6 +9161,9 @@
* TUNING: Might be worthwhile to inline this.
* TODO: Basic-block style Jit will need a hook here as well. Fold it into
* the suspendCount check so we can get both in 1 shot.
+ * TODO: to match the other intepreters, this should handle suspension
+ * and then check for debugger/profiling after dvmCheckSuspendPending
+ * returns.
*/
common_periodicChecks:
movl offGlue_pSelfSuspendCount(%ecx),%eax # eax <- &suspendCount
@@ -8799,9 +9178,11 @@
movl offGlue_pActiveProfilers(%ecx),%ecx # ecx <- &ActiveProfilers
#endif
#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ # TODO: check for NULL before load
movzbl (%eax),%eax # eax <- debuggerActive (boolean)
orl (%ecx),%eax # eax <- debuggerActive || activeProfilers
#elif defined(WITH_DEBUGGER)
+ # TODO: check for NULL before load
movzbl (%eax),%eax # eax <- debuggerActive (boolean)
#elif defined(WITH_PROFILER)
movl (%ecx),%eax # eax <= activeProfilers
@@ -9046,4 +9427,3 @@
.LstrFilledNewArrayNotImpl:
.asciz "filled-new-array only implemented for 'int'"
-
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 3dbd6a4..3656713 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,7 +1201,6 @@
} \
FINISH(2);
-
/* File: c/OP_NOP.c */
HANDLE_OPCODE(OP_NOP)
FINISH(1);
@@ -1692,6 +1701,16 @@
GOTO_exceptionThrown();
/*
+ * The JIT needs dvmDexGetResolvedClass() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (!dvmDexGetResolvedClass(methodClassDex, ref)) {
+ /* Class initialization is still ongoing - abandon the trace */
+ ABORT_JIT_TSELECT();
+ }
+
+ /*
* Verifier now tests for interface/abstract class.
*/
//if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
@@ -1744,7 +1763,6 @@
FINISH(2);
OP_END
-
/* File: c/OP_FILLED_NEW_ARRAY.c */
HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
GOTO_invoke(filledNewArray, false);
@@ -1772,7 +1790,7 @@
arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
{
/* should have been caught in verifier */
- dvmThrowException("Ljava/lang/InternalError;",
+ dvmThrowException("Ljava/lang/InternalError;",
"bad fill array data");
GOTO_exceptionThrown();
}
@@ -1790,10 +1808,17 @@
{
Object* obj;
+ /*
+ * We don't create an exception here, but the process of searching
+ * for a catch block can do class lookups and throw exceptions.
+ * We need to update the saved PC.
+ */
+ EXPORT_PC();
+
vsrc1 = INST_AA(inst);
ILOGV("|throw v%d (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
obj = (Object*) GET_REGISTER(vsrc1);
- if (!checkForNullExportPC(obj, fp, pc)) {
+ if (!checkForNull(obj)) {
/* will throw a null pointer exception */
LOGVV("Bad exception\n");
} else {
@@ -2075,8 +2100,9 @@
}
}
ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
- ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
- GET_REGISTER(vdst);
+ dvmSetObjectArrayElement(arrayObj,
+ GET_REGISTER(vsrc2),
+ (Object *)GET_REGISTER(vdst));
}
FINISH(2);
OP_END
@@ -2754,40 +2780,40 @@
HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8, "ushr", (u4), >>)
OP_END
-/* File: c/OP_UNUSED_E3.c */
-HANDLE_OPCODE(OP_UNUSED_E3)
+/* File: c/OP_IGET_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E4.c */
-HANDLE_OPCODE(OP_UNUSED_E4)
+/* File: c/OP_IPUT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E5.c */
-HANDLE_OPCODE(OP_UNUSED_E5)
+/* File: c/OP_SGET_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E6.c */
-HANDLE_OPCODE(OP_UNUSED_E6)
+/* File: c/OP_SPUT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E7.c */
-HANDLE_OPCODE(OP_UNUSED_E7)
+/* File: c/OP_IGET_OBJECT_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_E8.c */
-HANDLE_OPCODE(OP_UNUSED_E8)
+/* File: c/OP_IGET_WIDE_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_E9.c */
-HANDLE_OPCODE(OP_UNUSED_E9)
+/* File: c/OP_IPUT_WIDE_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_EA.c */
-HANDLE_OPCODE(OP_UNUSED_EA)
+/* File: c/OP_SGET_WIDE_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_EB.c */
-HANDLE_OPCODE(OP_UNUSED_EB)
+/* File: c/OP_SPUT_WIDE_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
/* File: c/OP_BREAKPOINT.c */
@@ -3001,16 +3027,16 @@
GOTO_invoke(invokeSuperQuick, true);
OP_END
-/* File: c/OP_UNUSED_FC.c */
-HANDLE_OPCODE(OP_UNUSED_FC)
+/* File: c/OP_IPUT_OBJECT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_FD.c */
-HANDLE_OPCODE(OP_UNUSED_FD)
+/* File: c/OP_SGET_OBJECT_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_FE.c */
-HANDLE_OPCODE(OP_UNUSED_FE)
+/* File: c/OP_SPUT_OBJECT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
/* File: c/OP_UNUSED_FF.c */
@@ -3105,7 +3131,6 @@
longjmp(*pJmpBuf, ((int)changeInterp)+1);
}
-
/* File: c/gotoTargets.c */
/*
* C footer. This has some common code shared by the various targets.
@@ -3203,6 +3228,9 @@
vdst >>= 4;
}
}
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
retval.l = newArray;
}
@@ -3260,6 +3288,10 @@
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -3411,6 +3443,10 @@
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -3482,6 +3518,16 @@
ILOGV("+ unknown method\n");
GOTO_exceptionThrown();
}
+
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) {
+ /* Class initialization is still ongoing */
+ ABORT_JIT_TSELECT();
+ }
}
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
GOTO_TARGET_END
@@ -3515,6 +3561,10 @@
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
@@ -3603,7 +3653,6 @@
GOTO_TARGET_END
-
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
@@ -3643,7 +3692,7 @@
LOGVV("+++ returned into break frame\n");
#if defined(WITH_JIT)
/* Let the Jit know the return is terminating normally */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
GOTO_bail();
}
@@ -3831,6 +3880,7 @@
GOTO_TARGET_END
+
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
@@ -4013,12 +4063,14 @@
TRACE_METHOD_ENTER(self, methodToCall);
#endif
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
+ {
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+ }
#if defined(WITH_JIT)
/* Allow the Jit to end any pending trace building */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
/*
diff --git a/vm/mterp/out/InterpC-armv4t.c b/vm/mterp/out/InterpC-armv4t.c
index 6c7c2e7..55a020d 100644
--- a/vm/mterp/out/InterpC-armv4t.c
+++ b/vm/mterp/out/InterpC-armv4t.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,7 +1201,6 @@
} \
FINISH(2);
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
@@ -1224,15 +1233,15 @@
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
- extern char dvmAsmInstructionStart[];
+ //extern char dvmAsmInstructionStart[];
printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
printf(" : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
rPC, rFP, rGLUE, rINST);
printf(" : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
- MterpGlue* glue = (MterpGlue*) rGLUE;
- const Method* method = glue->method;
+ //MterpGlue* glue = (MterpGlue*) rGLUE;
+ //const Method* method = glue->method;
printf(" + self is %p\n", dvmThreadSelf());
//printf(" + currently in %s.%s %s\n",
// method->clazz->descriptor, method->name, method->shorty);
diff --git a/vm/mterp/out/InterpC-armv5te-vfp.c b/vm/mterp/out/InterpC-armv5te-vfp.c
index 2d2de9a..8e58f8b 100644
--- a/vm/mterp/out/InterpC-armv5te-vfp.c
+++ b/vm/mterp/out/InterpC-armv5te-vfp.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,7 +1201,6 @@
} \
FINISH(2);
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
@@ -1224,15 +1233,15 @@
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
- extern char dvmAsmInstructionStart[];
+ //extern char dvmAsmInstructionStart[];
printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
printf(" : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
rPC, rFP, rGLUE, rINST);
printf(" : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
- MterpGlue* glue = (MterpGlue*) rGLUE;
- const Method* method = glue->method;
+ //MterpGlue* glue = (MterpGlue*) rGLUE;
+ //const Method* method = glue->method;
printf(" + self is %p\n", dvmThreadSelf());
//printf(" + currently in %s.%s %s\n",
// method->clazz->descriptor, method->name, method->shorty);
diff --git a/vm/mterp/out/InterpC-armv5te.c b/vm/mterp/out/InterpC-armv5te.c
index b2a16aa..d3c041f 100644
--- a/vm/mterp/out/InterpC-armv5te.c
+++ b/vm/mterp/out/InterpC-armv5te.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,7 +1201,6 @@
} \
FINISH(2);
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
@@ -1224,15 +1233,15 @@
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
- extern char dvmAsmInstructionStart[];
+ //extern char dvmAsmInstructionStart[];
printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
printf(" : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
rPC, rFP, rGLUE, rINST);
printf(" : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
- MterpGlue* glue = (MterpGlue*) rGLUE;
- const Method* method = glue->method;
+ //MterpGlue* glue = (MterpGlue*) rGLUE;
+ //const Method* method = glue->method;
printf(" + self is %p\n", dvmThreadSelf());
//printf(" + currently in %s.%s %s\n",
// method->clazz->descriptor, method->name, method->shorty);
diff --git a/vm/mterp/out/InterpC-armv7-a-neon.c b/vm/mterp/out/InterpC-armv7-a-neon.c
index 0930f28..77b1fce 100644
--- a/vm/mterp/out/InterpC-armv7-a-neon.c
+++ b/vm/mterp/out/InterpC-armv7-a-neon.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,7 +1201,6 @@
} \
FINISH(2);
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
@@ -1224,15 +1233,15 @@
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
- extern char dvmAsmInstructionStart[];
+ //extern char dvmAsmInstructionStart[];
printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
printf(" : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
rPC, rFP, rGLUE, rINST);
printf(" : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
- MterpGlue* glue = (MterpGlue*) rGLUE;
- const Method* method = glue->method;
+ //MterpGlue* glue = (MterpGlue*) rGLUE;
+ //const Method* method = glue->method;
printf(" + self is %p\n", dvmThreadSelf());
//printf(" + currently in %s.%s %s\n",
// method->clazz->descriptor, method->name, method->shorty);
diff --git a/vm/mterp/out/InterpC-armv7-a.c b/vm/mterp/out/InterpC-armv7-a.c
index da058b2..7f46f4f 100644
--- a/vm/mterp/out/InterpC-armv7-a.c
+++ b/vm/mterp/out/InterpC-armv7-a.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,7 +1201,6 @@
} \
FINISH(2);
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
@@ -1224,15 +1233,15 @@
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
- extern char dvmAsmInstructionStart[];
+ //extern char dvmAsmInstructionStart[];
printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
printf(" : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
rPC, rFP, rGLUE, rINST);
printf(" : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
- MterpGlue* glue = (MterpGlue*) rGLUE;
- const Method* method = glue->method;
+ //MterpGlue* glue = (MterpGlue*) rGLUE;
+ //const Method* method = glue->method;
printf(" + self is %p\n", dvmThreadSelf());
//printf(" + currently in %s.%s %s\n",
// method->clazz->descriptor, method->name, method->shorty);
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index c27582b..47b3d7f 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -425,10 +425,14 @@
checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
#if defined(WITH_JIT)
-#define CHECK_JIT() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
#define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
#else
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT(x) ((void)0)
#endif
@@ -465,7 +469,7 @@
inst = FETCH(0); \
CHECK_DEBUG_AND_PROF(); \
CHECK_TRACKED_REFS(); \
- if (CHECK_JIT()) GOTO_bail_switch(); \
+ if (CHECK_JIT_BOOL()) GOTO_bail_switch(); \
goto *handlerTable[INST_INST(inst)]; \
}
# define FINISH_BKPT(_opcode) { \
@@ -1135,6 +1139,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1148,6 +1157,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1169,6 +1181,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1177,7 +1192,6 @@
} \
FINISH(2);
-
/* File: portable/debug.c */
/* code in here is only included in portable-debug interpreter */
@@ -1241,7 +1255,7 @@
*/
const StepControl* pCtrl = &gDvm.stepControl;
if (pCtrl->active && pCtrl->thread == self) {
- int line, frameDepth;
+ int frameDepth;
bool doStop = false;
const char* msg = NULL;
@@ -1282,7 +1296,7 @@
if (pCtrl->size == SS_MIN) {
doStop = true;
msg = "new instruction";
- } else if (!dvmAddressSetGet(pCtrl->pAddressSet,
+ } else if (!dvmAddressSetGet(pCtrl->pAddressSet,
pc - method->insns)) {
doStop = true;
msg = "new line";
@@ -1432,7 +1446,6 @@
#endif
}
-
/* File: portable/entry.c */
/*
* Main interpreter loop.
@@ -1445,7 +1458,10 @@
StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->curFrame);
#endif
#if INTERP_TYPE == INTERP_DBG
- bool debugIsMethodEntry = interpState->debugIsMethodEntry;
+ bool debugIsMethodEntry = false;
+# if defined(WITH_DEBUGGER) || defined(WITH_PROFILER) // implied by INTERP_DBG??
+ debugIsMethodEntry = interpState->debugIsMethodEntry;
+# endif
#endif
#if defined(WITH_TRACKREF_CHECKS)
int debugTrackedRefStart = interpState->debugTrackedRefStart;
@@ -1479,6 +1495,14 @@
interpState->method->name);
#endif
#if INTERP_TYPE == INTERP_DBG
+ const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (interpState->jitState != kJitSelfVerification) {
+ interpState->self->shadowSpace->jitExitState = kSVSIdle;
+ }
+#endif
+
/* Check to see if we've got a trace selection request. */
if (
/*
@@ -1530,7 +1554,7 @@
/* just fall through to instruction loop or threaded kickstart */
break;
case kInterpEntryReturn:
- CHECK_JIT();
+ CHECK_JIT_VOID();
goto returnFromMethod;
case kInterpEntryThrow:
goto exceptionThrown;
@@ -2053,6 +2077,16 @@
GOTO_exceptionThrown();
/*
+ * The JIT needs dvmDexGetResolvedClass() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (!dvmDexGetResolvedClass(methodClassDex, ref)) {
+ /* Class initialization is still ongoing - abandon the trace */
+ ABORT_JIT_TSELECT();
+ }
+
+ /*
* Verifier now tests for interface/abstract class.
*/
//if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
@@ -2105,7 +2139,6 @@
FINISH(2);
OP_END
-
/* File: c/OP_FILLED_NEW_ARRAY.c */
HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
GOTO_invoke(filledNewArray, false);
@@ -2133,7 +2166,7 @@
arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
{
/* should have been caught in verifier */
- dvmThrowException("Ljava/lang/InternalError;",
+ dvmThrowException("Ljava/lang/InternalError;",
"bad fill array data");
GOTO_exceptionThrown();
}
@@ -2151,10 +2184,17 @@
{
Object* obj;
+ /*
+ * We don't create an exception here, but the process of searching
+ * for a catch block can do class lookups and throw exceptions.
+ * We need to update the saved PC.
+ */
+ EXPORT_PC();
+
vsrc1 = INST_AA(inst);
ILOGV("|throw v%d (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
obj = (Object*) GET_REGISTER(vsrc1);
- if (!checkForNullExportPC(obj, fp, pc)) {
+ if (!checkForNull(obj)) {
/* will throw a null pointer exception */
LOGVV("Bad exception\n");
} else {
@@ -2436,8 +2476,9 @@
}
}
ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
- ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
- GET_REGISTER(vdst);
+ dvmSetObjectArrayElement(arrayObj,
+ GET_REGISTER(vsrc2),
+ (Object *)GET_REGISTER(vdst));
}
FINISH(2);
OP_END
@@ -3115,40 +3156,40 @@
HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8, "ushr", (u4), >>)
OP_END
-/* File: c/OP_UNUSED_E3.c */
-HANDLE_OPCODE(OP_UNUSED_E3)
+/* File: c/OP_IGET_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E4.c */
-HANDLE_OPCODE(OP_UNUSED_E4)
+/* File: c/OP_IPUT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E5.c */
-HANDLE_OPCODE(OP_UNUSED_E5)
+/* File: c/OP_SGET_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E6.c */
-HANDLE_OPCODE(OP_UNUSED_E6)
+/* File: c/OP_SPUT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E7.c */
-HANDLE_OPCODE(OP_UNUSED_E7)
+/* File: c/OP_IGET_OBJECT_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_E8.c */
-HANDLE_OPCODE(OP_UNUSED_E8)
+/* File: c/OP_IGET_WIDE_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_E9.c */
-HANDLE_OPCODE(OP_UNUSED_E9)
+/* File: c/OP_IPUT_WIDE_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_EA.c */
-HANDLE_OPCODE(OP_UNUSED_EA)
+/* File: c/OP_SGET_WIDE_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_EB.c */
-HANDLE_OPCODE(OP_UNUSED_EB)
+/* File: c/OP_SPUT_WIDE_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
/* File: c/OP_BREAKPOINT.c */
@@ -3362,16 +3403,16 @@
GOTO_invoke(invokeSuperQuick, true);
OP_END
-/* File: c/OP_UNUSED_FC.c */
-HANDLE_OPCODE(OP_UNUSED_FC)
+/* File: c/OP_IPUT_OBJECT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_FD.c */
-HANDLE_OPCODE(OP_UNUSED_FD)
+/* File: c/OP_SGET_OBJECT_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_FE.c */
-HANDLE_OPCODE(OP_UNUSED_FE)
+/* File: c/OP_SPUT_OBJECT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
/* File: c/OP_UNUSED_FF.c */
@@ -3481,6 +3522,9 @@
vdst >>= 4;
}
}
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
retval.l = newArray;
}
@@ -3538,6 +3582,10 @@
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -3689,6 +3737,10 @@
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -3760,6 +3812,16 @@
ILOGV("+ unknown method\n");
GOTO_exceptionThrown();
}
+
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) {
+ /* Class initialization is still ongoing */
+ ABORT_JIT_TSELECT();
+ }
}
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
GOTO_TARGET_END
@@ -3793,6 +3855,10 @@
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
@@ -3881,7 +3947,6 @@
GOTO_TARGET_END
-
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
@@ -3921,7 +3986,7 @@
LOGVV("+++ returned into break frame\n");
#if defined(WITH_JIT)
/* Let the Jit know the return is terminating normally */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
GOTO_bail();
}
@@ -4109,6 +4174,7 @@
GOTO_TARGET_END
+
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
@@ -4291,12 +4357,14 @@
TRACE_METHOD_ENTER(self, methodToCall);
#endif
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
+ {
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+ }
#if defined(WITH_JIT)
/* Allow the Jit to end any pending trace building */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
/*
@@ -4395,4 +4463,3 @@
return true;
}
-
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 1e7550c..165c032 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -423,7 +423,8 @@
#define CHECK_DEBUG_AND_PROF() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
/* File: portable/stubdefs.c */
@@ -459,7 +460,7 @@
inst = FETCH(0); \
CHECK_DEBUG_AND_PROF(); \
CHECK_TRACKED_REFS(); \
- if (CHECK_JIT()) GOTO_bail_switch(); \
+ if (CHECK_JIT_BOOL()) GOTO_bail_switch(); \
goto *handlerTable[INST_INST(inst)]; \
}
# define FINISH_BKPT(_opcode) { \
@@ -1129,6 +1130,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1142,6 +1148,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1163,6 +1172,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1171,7 +1183,6 @@
} \
FINISH(2);
-
/* File: portable/entry.c */
/*
* Main interpreter loop.
@@ -1184,7 +1195,10 @@
StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->curFrame);
#endif
#if INTERP_TYPE == INTERP_DBG
- bool debugIsMethodEntry = interpState->debugIsMethodEntry;
+ bool debugIsMethodEntry = false;
+# if defined(WITH_DEBUGGER) || defined(WITH_PROFILER) // implied by INTERP_DBG??
+ debugIsMethodEntry = interpState->debugIsMethodEntry;
+# endif
#endif
#if defined(WITH_TRACKREF_CHECKS)
int debugTrackedRefStart = interpState->debugTrackedRefStart;
@@ -1218,6 +1232,14 @@
interpState->method->name);
#endif
#if INTERP_TYPE == INTERP_DBG
+ const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (interpState->jitState != kJitSelfVerification) {
+ interpState->self->shadowSpace->jitExitState = kSVSIdle;
+ }
+#endif
+
/* Check to see if we've got a trace selection request. */
if (
/*
@@ -1269,7 +1291,7 @@
/* just fall through to instruction loop or threaded kickstart */
break;
case kInterpEntryReturn:
- CHECK_JIT();
+ CHECK_JIT_VOID();
goto returnFromMethod;
case kInterpEntryThrow:
goto exceptionThrown;
@@ -1792,6 +1814,16 @@
GOTO_exceptionThrown();
/*
+ * The JIT needs dvmDexGetResolvedClass() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (!dvmDexGetResolvedClass(methodClassDex, ref)) {
+ /* Class initialization is still ongoing - abandon the trace */
+ ABORT_JIT_TSELECT();
+ }
+
+ /*
* Verifier now tests for interface/abstract class.
*/
//if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
@@ -1844,7 +1876,6 @@
FINISH(2);
OP_END
-
/* File: c/OP_FILLED_NEW_ARRAY.c */
HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
GOTO_invoke(filledNewArray, false);
@@ -1872,7 +1903,7 @@
arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
{
/* should have been caught in verifier */
- dvmThrowException("Ljava/lang/InternalError;",
+ dvmThrowException("Ljava/lang/InternalError;",
"bad fill array data");
GOTO_exceptionThrown();
}
@@ -1890,10 +1921,17 @@
{
Object* obj;
+ /*
+ * We don't create an exception here, but the process of searching
+ * for a catch block can do class lookups and throw exceptions.
+ * We need to update the saved PC.
+ */
+ EXPORT_PC();
+
vsrc1 = INST_AA(inst);
ILOGV("|throw v%d (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
obj = (Object*) GET_REGISTER(vsrc1);
- if (!checkForNullExportPC(obj, fp, pc)) {
+ if (!checkForNull(obj)) {
/* will throw a null pointer exception */
LOGVV("Bad exception\n");
} else {
@@ -2175,8 +2213,9 @@
}
}
ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
- ((u4*) arrayObj->contents)[GET_REGISTER(vsrc2)] =
- GET_REGISTER(vdst);
+ dvmSetObjectArrayElement(arrayObj,
+ GET_REGISTER(vsrc2),
+ (Object *)GET_REGISTER(vdst));
}
FINISH(2);
OP_END
@@ -2854,40 +2893,40 @@
HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8, "ushr", (u4), >>)
OP_END
-/* File: c/OP_UNUSED_E3.c */
-HANDLE_OPCODE(OP_UNUSED_E3)
+/* File: c/OP_IGET_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E4.c */
-HANDLE_OPCODE(OP_UNUSED_E4)
+/* File: c/OP_IPUT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E5.c */
-HANDLE_OPCODE(OP_UNUSED_E5)
+/* File: c/OP_SGET_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E6.c */
-HANDLE_OPCODE(OP_UNUSED_E6)
+/* File: c/OP_SPUT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE, "-volatile", IntVolatile, )
OP_END
-/* File: c/OP_UNUSED_E7.c */
-HANDLE_OPCODE(OP_UNUSED_E7)
+/* File: c/OP_IGET_OBJECT_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_E8.c */
-HANDLE_OPCODE(OP_UNUSED_E8)
+/* File: c/OP_IGET_WIDE_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_E9.c */
-HANDLE_OPCODE(OP_UNUSED_E9)
+/* File: c/OP_IPUT_WIDE_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_EA.c */
-HANDLE_OPCODE(OP_UNUSED_EA)
+/* File: c/OP_SGET_WIDE_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
-/* File: c/OP_UNUSED_EB.c */
-HANDLE_OPCODE(OP_UNUSED_EB)
+/* File: c/OP_SPUT_WIDE_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
OP_END
/* File: c/OP_BREAKPOINT.c */
@@ -3101,16 +3140,16 @@
GOTO_invoke(invokeSuperQuick, true);
OP_END
-/* File: c/OP_UNUSED_FC.c */
-HANDLE_OPCODE(OP_UNUSED_FC)
+/* File: c/OP_IPUT_OBJECT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_FD.c */
-HANDLE_OPCODE(OP_UNUSED_FD)
+/* File: c/OP_SGET_OBJECT_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_UNUSED_FE.c */
-HANDLE_OPCODE(OP_UNUSED_FE)
+/* File: c/OP_SPUT_OBJECT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
/* File: c/OP_UNUSED_FF.c */
@@ -3220,6 +3259,9 @@
vdst >>= 4;
}
}
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
retval.l = newArray;
}
@@ -3277,6 +3319,10 @@
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -3428,6 +3474,10 @@
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -3499,6 +3549,16 @@
ILOGV("+ unknown method\n");
GOTO_exceptionThrown();
}
+
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) {
+ /* Class initialization is still ongoing */
+ ABORT_JIT_TSELECT();
+ }
}
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
GOTO_TARGET_END
@@ -3532,6 +3592,10 @@
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
@@ -3620,7 +3684,6 @@
GOTO_TARGET_END
-
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
@@ -3660,7 +3723,7 @@
LOGVV("+++ returned into break frame\n");
#if defined(WITH_JIT)
/* Let the Jit know the return is terminating normally */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
GOTO_bail();
}
@@ -3848,6 +3911,7 @@
GOTO_TARGET_END
+
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
@@ -4030,12 +4094,14 @@
TRACE_METHOD_ENTER(self, methodToCall);
#endif
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
+ {
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+ }
#if defined(WITH_JIT)
/* Allow the Jit to end any pending trace building */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
/*
@@ -4134,4 +4200,3 @@
return true;
}
-
diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c
index 1a8a61a..3b85384 100644
--- a/vm/mterp/out/InterpC-x86-atom.c
+++ b/vm/mterp/out/InterpC-x86-atom.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,6 +1201,41 @@
} \
FINISH(2);
+/* File: c/OP_IGET_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_VOLATILE, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_VOLATILE, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
/* File: c/OP_BREAKPOINT.c */
HANDLE_OPCODE(OP_BREAKPOINT)
@@ -1268,6 +1313,18 @@
FINISH(3);
OP_END
+/* File: c/OP_IPUT_OBJECT_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
/* File: c/gotoTargets.c */
/*
* C footer. This has some common code shared by the various targets.
@@ -1365,6 +1422,9 @@
vdst >>= 4;
}
}
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
retval.l = newArray;
}
@@ -1422,6 +1482,10 @@
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -1573,6 +1637,10 @@
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -1644,6 +1712,16 @@
ILOGV("+ unknown method\n");
GOTO_exceptionThrown();
}
+
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) {
+ /* Class initialization is still ongoing */
+ ABORT_JIT_TSELECT();
+ }
}
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
GOTO_TARGET_END
@@ -1677,6 +1755,10 @@
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
@@ -1765,7 +1847,6 @@
GOTO_TARGET_END
-
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
@@ -1805,7 +1886,7 @@
LOGVV("+++ returned into break frame\n");
#if defined(WITH_JIT)
/* Let the Jit know the return is terminating normally */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
GOTO_bail();
}
@@ -1993,6 +2074,7 @@
GOTO_TARGET_END
+
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
@@ -2175,12 +2257,14 @@
TRACE_METHOD_ENTER(self, methodToCall);
#endif
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
+ {
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+ }
#if defined(WITH_JIT)
/* Allow the Jit to end any pending trace building */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
/*
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index 6a3c442..ec07691 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -422,10 +422,9 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
-#if defined(WITH_JIT)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
-#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -1149,6 +1148,11 @@
} \
FINISH(2);
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Since we use the portable interpreter to build the trace, the extra
+ * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
+ */
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
@@ -1162,6 +1166,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
@@ -1183,6 +1190,9 @@
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ ABORT_JIT_TSELECT(); \
+ } \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
@@ -1191,6 +1201,21 @@
} \
FINISH(2);
+/* File: c/OP_IGET_WIDE_VOLATILE.c */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE.c */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE.c */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE.c */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
+OP_END
/* File: c/OP_EXECUTE_INLINE_RANGE.c */
HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
@@ -1334,6 +1359,9 @@
vdst >>= 4;
}
}
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
retval.l = newArray;
}
@@ -1391,6 +1419,10 @@
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -1542,6 +1574,10 @@
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -1613,6 +1649,16 @@
ILOGV("+ unknown method\n");
GOTO_exceptionThrown();
}
+
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Since we use the portable interpreter to build the trace, this extra
+ * check is not needed for mterp.
+ */
+ if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) {
+ /* Class initialization is still ongoing */
+ ABORT_JIT_TSELECT();
+ }
}
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
GOTO_TARGET_END
@@ -1646,6 +1692,10 @@
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
@@ -1734,7 +1784,6 @@
GOTO_TARGET_END
-
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
@@ -1774,7 +1823,7 @@
LOGVV("+++ returned into break frame\n");
#if defined(WITH_JIT)
/* Let the Jit know the return is terminating normally */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
GOTO_bail();
}
@@ -1962,6 +2011,7 @@
GOTO_TARGET_END
+
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
@@ -2144,12 +2194,14 @@
TRACE_METHOD_ENTER(self, methodToCall);
#endif
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
+ {
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+ }
#if defined(WITH_JIT)
/* Allow the Jit to end any pending trace building */
- CHECK_JIT();
+ CHECK_JIT_VOID();
#endif
/*
diff --git a/vm/mterp/portable/debug.c b/vm/mterp/portable/debug.c
index 6716aba..94f735a 100644
--- a/vm/mterp/portable/debug.c
+++ b/vm/mterp/portable/debug.c
@@ -60,7 +60,7 @@
*/
const StepControl* pCtrl = &gDvm.stepControl;
if (pCtrl->active && pCtrl->thread == self) {
- int line, frameDepth;
+ int frameDepth;
bool doStop = false;
const char* msg = NULL;
@@ -101,7 +101,7 @@
if (pCtrl->size == SS_MIN) {
doStop = true;
msg = "new instruction";
- } else if (!dvmAddressSetGet(pCtrl->pAddressSet,
+ } else if (!dvmAddressSetGet(pCtrl->pAddressSet,
pc - method->insns)) {
doStop = true;
msg = "new line";
@@ -250,4 +250,3 @@
}
#endif
}
-
diff --git a/vm/mterp/portable/enddefs.c b/vm/mterp/portable/enddefs.c
index 5ddde3c..af8606e 100644
--- a/vm/mterp/portable/enddefs.c
+++ b/vm/mterp/portable/enddefs.c
@@ -40,4 +40,3 @@
pc - curMethod->insns, fp);
return true;
}
-
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index dbd5561..6b989a2 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -9,7 +9,10 @@
StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->curFrame);
#endif
#if INTERP_TYPE == INTERP_DBG
- bool debugIsMethodEntry = interpState->debugIsMethodEntry;
+ bool debugIsMethodEntry = false;
+# if defined(WITH_DEBUGGER) || defined(WITH_PROFILER) // implied by INTERP_DBG??
+ debugIsMethodEntry = interpState->debugIsMethodEntry;
+# endif
#endif
#if defined(WITH_TRACKREF_CHECKS)
int debugTrackedRefStart = interpState->debugTrackedRefStart;
@@ -43,6 +46,14 @@
interpState->method->name);
#endif
#if INTERP_TYPE == INTERP_DBG
+ const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (interpState->jitState != kJitSelfVerification) {
+ interpState->self->shadowSpace->jitExitState = kSVSIdle;
+ }
+#endif
+
/* Check to see if we've got a trace selection request. */
if (
/*
@@ -94,7 +105,7 @@
/* just fall through to instruction loop or threaded kickstart */
break;
case kInterpEntryReturn:
- CHECK_JIT();
+ CHECK_JIT_VOID();
goto returnFromMethod;
case kInterpEntryThrow:
goto exceptionThrown;
diff --git a/vm/mterp/portable/portdbg.c b/vm/mterp/portable/portdbg.c
index 030a515..65349e9 100644
--- a/vm/mterp/portable/portdbg.c
+++ b/vm/mterp/portable/portdbg.c
@@ -5,9 +5,13 @@
checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
#if defined(WITH_JIT)
-#define CHECK_JIT() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
#define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
#else
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT(x) ((void)0)
#endif
diff --git a/vm/mterp/portable/portstd.c b/vm/mterp/portable/portstd.c
index e2d8b10..f37c22b 100644
--- a/vm/mterp/portable/portstd.c
+++ b/vm/mterp/portable/portstd.c
@@ -3,5 +3,6 @@
#define CHECK_DEBUG_AND_PROF() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
#define ABORT_JIT_TSELECT() ((void)0)
diff --git a/vm/mterp/portable/stubdefs.c b/vm/mterp/portable/stubdefs.c
index 29258fc..b46bb3a 100644
--- a/vm/mterp/portable/stubdefs.c
+++ b/vm/mterp/portable/stubdefs.c
@@ -30,7 +30,7 @@
inst = FETCH(0); \
CHECK_DEBUG_AND_PROF(); \
CHECK_TRACKED_REFS(); \
- if (CHECK_JIT()) GOTO_bail_switch(); \
+ if (CHECK_JIT_BOOL()) GOTO_bail_switch(); \
goto *handlerTable[INST_INST(inst)]; \
}
# define FINISH_BKPT(_opcode) { \
diff --git a/vm/mterp/x86-atom/OP_AND_INT.S b/vm/mterp/x86-atom/OP_AND_INT.S
index 84d8eb6..2f84b34 100644
--- a/vm/mterp/x86-atom/OP_AND_INT.S
+++ b/vm/mterp/x86-atom/OP_AND_INT.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/binop.S" {"instr":"andl (rFP, %edx, 4), %ecx"}
-
diff --git a/vm/mterp/x86-atom/OP_CMP_LONG.S b/vm/mterp/x86-atom/OP_CMP_LONG.S
index 2ce2a19..cf021a3 100644
--- a/vm/mterp/x86-atom/OP_CMP_LONG.S
+++ b/vm/mterp/x86-atom/OP_CMP_LONG.S
@@ -53,5 +53,3 @@
.L${opcode}_greater:
movl $$0x1, (rFP, rINST, 4) # vAA<- greater than
FINISH 2 # jump to next instruction
-
-
diff --git a/vm/mterp/x86-atom/OP_DIV_DOUBLE.S b/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
index 3220f36..418a230 100644
--- a/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
+++ b/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
@@ -35,4 +35,3 @@
fstpl (rFP, rINST, 4) # vAA<- result
FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
index b3173c7..7003e30 100644
--- a/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
@@ -35,4 +35,3 @@
fdivl (rFP, rINST, 4) # divide double; vA/vB
fstpl (rFP, %edx, 4) # vAA<- result
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_DIV_INT.S b/vm/mterp/x86-atom/OP_DIV_INT.S
index dd4b514..c7f5b27 100644
--- a/vm/mterp/x86-atom/OP_DIV_INT.S
+++ b/vm/mterp/x86-atom/OP_DIV_INT.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/binopD.S"
-
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
index 1ec4eb9..762d82f 100644
--- a/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/binopD2addr.S"
-
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
index e5494fa..f377762 100644
--- a/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
+++ b/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
@@ -66,4 +66,3 @@
fstps (rFP, %edx, 4)
movl $$0x80000000, (rFP, %edx, 4) # vA<- negInf
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
index c12f159..2ce9bcc 100644
--- a/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
+++ b/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
@@ -69,4 +69,3 @@
fstpl (rFP, %edx, 4) # move converted int
movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S b/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
index 2a78424..9a50b78 100644
--- a/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
+++ b/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
@@ -69,5 +69,3 @@
fstpl (rFP, %edx, 4) # move converted int
movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
FINISH 1 # jump to next instruction
-
-
diff --git a/vm/mterp/x86-atom/OP_GOTO.S b/vm/mterp/x86-atom/OP_GOTO.S
index cb70859..12d847e 100644
--- a/vm/mterp/x86-atom/OP_GOTO.S
+++ b/vm/mterp/x86-atom/OP_GOTO.S
@@ -34,4 +34,3 @@
shl $$1, %edx # %edx is shifted for byte offset
js common_periodicChecks2 # do check on backwards branch
FINISH_RB %edx, %ecx # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_GOTO_32.S b/vm/mterp/x86-atom/OP_GOTO_32.S
index 9409400..4c56915 100644
--- a/vm/mterp/x86-atom/OP_GOTO_32.S
+++ b/vm/mterp/x86-atom/OP_GOTO_32.S
@@ -35,4 +35,3 @@
shl $$1, %edx # %edx is doubled to get the byte offset
jc common_periodicChecks2 # do check on backwards branch
FINISH_RB %edx, %ecx # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE.S b/vm/mterp/x86-atom/OP_IGET_WIDE.S
index 74973b1..370b0b0 100644
--- a/vm/mterp/x86-atom/OP_IGET_WIDE.S
+++ b/vm/mterp/x86-atom/OP_IGET_WIDE.S
@@ -72,5 +72,3 @@
movq (%ecx, %edx), %xmm0 # %xmm0<- object field
movq %xmm0, (rFP, rINST, 4) # vA<- %xmm0; object field
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S b/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
index 85f1fbe..08a57f6 100644
--- a/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
+++ b/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
@@ -36,5 +36,3 @@
movq (%ecx, %edx), %xmm0 # %xmm0<- object field
movq %xmm0, (rFP, rINST, 4) # fp[A]<- %xmm0
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
diff --git a/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S b/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
index 23c70cf..52ce729 100644
--- a/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
+++ b/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
@@ -34,4 +34,3 @@
cvtsi2ss (rFP,%eax,4), %xmm0 # %xmm0<- vB
movss %xmm0, (rFP, rINST, 4) # vA<- %xmm0
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_INT_TO_SHORT.S b/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
index da6ca95..f2b0b87 100644
--- a/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
+++ b/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/unop.S" { "preinstr":"sal $16, %ecx", "instr":"sar $16, %ecx" }
-
diff --git a/vm/mterp/x86-atom/OP_INVOKE_STATIC.S b/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
index c9ac5ff..30b6d8c 100644
--- a/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
+++ b/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
@@ -68,5 +68,3 @@
je common_exceptionThrown
movl %eax, %ecx # %ecx<- method
jmp common_invokeMethod${routine} # invoke method common code
-
-
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
index 684a0e9..539bea1 100644
--- a/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
@@ -103,4 +103,3 @@
.L${opcode}_nsm:
movl offMethod_name(%ecx), %edx # %edx<- method name
jmp common_errNoSuchMethod
-
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
index 3da7346..55c7e94 100644
--- a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
@@ -38,6 +38,3 @@
movl (%eax, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
je common_errNullObject # handle null object
jmp common_invokeMethod${routine} # invoke method common code
-
-
-
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S
index b88928b..46c9265 100644
--- a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S
@@ -91,4 +91,3 @@
movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
movl (%edx, %eax, 4), %ecx # %ecx<- vtable[methodIndex]
jmp common_invokeMethod${routine} # invoke method common code
-
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
index efa5fb2..16a4e40 100644
--- a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
@@ -36,5 +36,3 @@
movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
jmp common_invokeMethod${routine} # invoke method common code
-
-
diff --git a/vm/mterp/x86-atom/OP_IPUT.S b/vm/mterp/x86-atom/OP_IPUT.S
index eb893f7..4c029be 100644
--- a/vm/mterp/x86-atom/OP_IPUT.S
+++ b/vm/mterp/x86-atom/OP_IPUT.S
@@ -74,4 +74,3 @@
GET_VREG rINST # rINST<- vA
mov$mov rINST, (%edx, %ecx) # object field<- vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
index 0f9cc32..33727ca 100644
--- a/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
+++ b/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
@@ -18,5 +18,3 @@
*/
%include "x86-atom/OP_IPUT.S"
-
-
diff --git a/vm/mterp/x86-atom/OP_IPUT_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_QUICK.S
index 1c5962d..572291e 100644
--- a/vm/mterp/x86-atom/OP_IPUT_QUICK.S
+++ b/vm/mterp/x86-atom/OP_IPUT_QUICK.S
@@ -35,5 +35,3 @@
GET_VREG rINST # rINST<- vA
movl rINST, (%eax, %ecx) # object field<- vA
FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE.S b/vm/mterp/x86-atom/OP_IPUT_WIDE.S
index 498ebd9..1686219 100644
--- a/vm/mterp/x86-atom/OP_IPUT_WIDE.S
+++ b/vm/mterp/x86-atom/OP_IPUT_WIDE.S
@@ -72,5 +72,3 @@
movq (rFP, rINST, 4), %xmm0 # %xmm0<- vA
movq %xmm0, (%ecx, %edx) # object field<- %xmm0; vA
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
index 5eedbb9..5880231 100644
--- a/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
+++ b/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
@@ -36,4 +36,3 @@
movq (rFP, rINST, 4), %xmm0 # %xmm0<- fp[A]
movq %xmm0, (%edx, %ecx) # object field<- %xmm0; fp[A]
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
index c21014a..5705e25 100644
--- a/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
+++ b/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
@@ -35,4 +35,3 @@
fildll (rFP, rINST, 4) # FPU<- vB
fstpl (rFP, %ecx, 4) # vA<- FPU; (double) vB
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_MONITOR_ENTER.S b/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
index ed33258..d3fada3 100644
--- a/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
+++ b/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
@@ -56,4 +56,3 @@
jne common_exceptionThrown # handle exception
#endif
FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_MONITOR_EXIT.S b/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
index 98f062b..31e1165 100644
--- a/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
+++ b/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
@@ -44,4 +44,3 @@
lea 8(%esp), %esp
je common_exceptionThrown # handle exception
FINISH_JMP %edx # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S b/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
index b6e37ce..76e700d 100644
--- a/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
+++ b/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
@@ -36,4 +36,3 @@
movl $$0, offThread_exception(%ecx) # clear exception
SET_VREG %edx, rINST # vAA<- glue->self->exception
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
index c9aa966..4056b34 100644
--- a/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
+++ b/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
@@ -32,4 +32,3 @@
movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
movq %xmm0, (rFP, rINST, 4) # vA<- vB
FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/OP_MUL_LONG.S b/vm/mterp/x86-atom/OP_MUL_LONG.S
index 24b6c29..85cccf2 100644
--- a/vm/mterp/x86-atom/OP_MUL_LONG.S
+++ b/vm/mterp/x86-atom/OP_MUL_LONG.S
@@ -69,4 +69,3 @@
movl %ecx, 4(rFP, rINST, 4) # vAA+1<- results hi
movl %eax, (rFP, rINST, 4) # vAA<- results lo
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
index 78befcd..d6b8c16 100644
--- a/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
@@ -70,4 +70,3 @@
movl %ecx, 4(rFP, %edx, 4) # vA+1<- results hi
movl %eax, (rFP, %edx, 4) # vA<- results lo
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_NEG_DOUBLE.S b/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
index e53cdf1..b6fb070 100644
--- a/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
+++ b/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/unopWide.S" { "preinstr":"movq .LdoubNeg, %xmm1", "instr":"pxor %xmm1, %xmm0" }
-
diff --git a/vm/mterp/x86-atom/OP_NEG_LONG.S b/vm/mterp/x86-atom/OP_NEG_LONG.S
index 28f66d0..3f500bb 100644
--- a/vm/mterp/x86-atom/OP_NEG_LONG.S
+++ b/vm/mterp/x86-atom/OP_NEG_LONG.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/unopWide.S" {"preinstr":"xorps %xmm1, %xmm1", "instr":"psubq %xmm0, %xmm1", "result":"%xmm1"}
-
diff --git a/vm/mterp/x86-atom/OP_NEW_ARRAY.S b/vm/mterp/x86-atom/OP_NEW_ARRAY.S
index bb1ef69..a6d5fd3 100644
--- a/vm/mterp/x86-atom/OP_NEW_ARRAY.S
+++ b/vm/mterp/x86-atom/OP_NEW_ARRAY.S
@@ -90,4 +90,3 @@
je common_exceptionThrown # handle exception
SET_VREG %eax, rINST # vA<- pArray
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_NOP.S b/vm/mterp/x86-atom/OP_NOP.S
index 8460045..9911da3 100644
--- a/vm/mterp/x86-atom/OP_NOP.S
+++ b/vm/mterp/x86-atom/OP_NOP.S
@@ -39,4 +39,3 @@
dalvik_inst:
MTERP_ENTRY
#endif
-
diff --git a/vm/mterp/x86-atom/OP_PACKED_SWITCH.S b/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
index 37a40da..7cb6d64 100644
--- a/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
+++ b/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
@@ -50,4 +50,3 @@
%break
.L${opcode}_finish:
FINISH_RB %edx, %ecx # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_REM_DOUBLE.S b/vm/mterp/x86-atom/OP_REM_DOUBLE.S
index d9f15da..aa7d332 100644
--- a/vm/mterp/x86-atom/OP_REM_DOUBLE.S
+++ b/vm/mterp/x86-atom/OP_REM_DOUBLE.S
@@ -49,4 +49,3 @@
lea 16(%esp), %esp
fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
index 6fe7169..434c878 100644
--- a/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
@@ -50,11 +50,3 @@
lea 20(%esp), %esp
fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
FINISH 1 # jump to next instruction
-
-
-
-
-
-
-
-
diff --git a/vm/mterp/x86-atom/OP_REM_FLOAT.S b/vm/mterp/x86-atom/OP_REM_FLOAT.S
index 733c636..de5e161 100644
--- a/vm/mterp/x86-atom/OP_REM_FLOAT.S
+++ b/vm/mterp/x86-atom/OP_REM_FLOAT.S
@@ -41,4 +41,3 @@
lea 8(%esp), %esp
fstps (rFP, rINST, 4) # vAA<- remainder; return of fmod
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
index d225851..5ff5af5 100644
--- a/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
@@ -42,6 +42,3 @@
lea 8(%esp), %esp
fstps (rFP, rINST, 4)
FINISH 1 # jump to next instruction
-
-
-
diff --git a/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S b/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
index 534eed7..369ea5c 100644
--- a/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/binopD2addr.S" {"div":"0"}
-
diff --git a/vm/mterp/x86-atom/OP_RETURN.S b/vm/mterp/x86-atom/OP_RETURN.S
index 55af81b..48d7e34 100644
--- a/vm/mterp/x86-atom/OP_RETURN.S
+++ b/vm/mterp/x86-atom/OP_RETURN.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/OP_RETURN_COMMON.S"
-
diff --git a/vm/mterp/x86-atom/OP_RETURN_COMMON.S b/vm/mterp/x86-atom/OP_RETURN_COMMON.S
index cda3fea..d58a16c 100644
--- a/vm/mterp/x86-atom/OP_RETURN_COMMON.S
+++ b/vm/mterp/x86-atom/OP_RETURN_COMMON.S
@@ -32,4 +32,3 @@
GET_VREG rINST # rINST<- vAA
movl rINST, offGlue_retval(%edx) # glue->retval<- vAA
jmp common_returnFromMethod # jump to common return code
-
diff --git a/vm/mterp/x86-atom/OP_RETURN_VOID.S b/vm/mterp/x86-atom/OP_RETURN_VOID.S
index 8bc786d..4d8c92b 100644
--- a/vm/mterp/x86-atom/OP_RETURN_VOID.S
+++ b/vm/mterp/x86-atom/OP_RETURN_VOID.S
@@ -18,4 +18,3 @@
*/
jmp common_returnFromMethod
-
diff --git a/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S b/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
index b3633e6..d6114dd 100644
--- a/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
+++ b/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
@@ -34,4 +34,3 @@
sub %ecx, %edx # %edx<- +CC sub vBB
SET_VREG %edx, rINST # vAA<- %edx; result
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
index f262b41..8e383b4 100644
--- a/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
+++ b/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/OP_SGET.S"
-
diff --git a/vm/mterp/x86-atom/OP_SGET_OBJECT.S b/vm/mterp/x86-atom/OP_SGET_OBJECT.S
index d893676..5145f14 100644
--- a/vm/mterp/x86-atom/OP_SGET_OBJECT.S
+++ b/vm/mterp/x86-atom/OP_SGET_OBJECT.S
@@ -18,5 +18,3 @@
*/
%include "x86-atom/OP_SGET.S"
-
-
diff --git a/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
index 5bc4870..28dfaf2 100644
--- a/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
@@ -39,4 +39,3 @@
psllq %xmm0, %xmm1 # %xmm1<- shifted vA
movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_SHR_LONG.S b/vm/mterp/x86-atom/OP_SHR_LONG.S
index 7745cdb..be893ef 100644
--- a/vm/mterp/x86-atom/OP_SHR_LONG.S
+++ b/vm/mterp/x86-atom/OP_SHR_LONG.S
@@ -51,4 +51,3 @@
.L${opcode}_final:
movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
index bc98be9..38aefcf 100644
--- a/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
@@ -52,5 +52,3 @@
.L${opcode}_final:
movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
FINISH 1 # jump to next instruction
-
-
diff --git a/vm/mterp/x86-atom/OP_SUB_INT.S b/vm/mterp/x86-atom/OP_SUB_INT.S
index aab64fc..be530aa 100644
--- a/vm/mterp/x86-atom/OP_SUB_INT.S
+++ b/vm/mterp/x86-atom/OP_SUB_INT.S
@@ -18,4 +18,3 @@
*/
%include "x86-atom/binop.S" {"instr":"subl (rFP, %edx, 4), %ecx"}
-
diff --git a/vm/mterp/x86-atom/OP_THROW.S b/vm/mterp/x86-atom/OP_THROW.S
index 2b87c88..85afa7a 100644
--- a/vm/mterp/x86-atom/OP_THROW.S
+++ b/vm/mterp/x86-atom/OP_THROW.S
@@ -34,4 +34,3 @@
je common_errNullObject # handle null object
movl rINST, offThread_exception(%ecx) # thread->exception<- object
jmp common_exceptionThrown # handle exception
-
diff --git a/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
index 94b7ec6..fcd42c7 100644
--- a/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
+++ b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
@@ -16,7 +16,7 @@
/*
* File: OP_THROW_VERIFICATION_ERROR.S
*
- * Code:
+ * Code:
*
* For: throw-verification-error
*
@@ -28,13 +28,13 @@
* Syntax: op vAA, ref@BBBB
*/
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %ecx # %ecx<- glue->method
- EXPORT_PC # in case an exception is thrown
- FETCH 1, %eax # %eax<- BBBB
- movl %eax, -4(%esp) # push parameter BBBB; ref
- movl rINST, -8(%esp) # push parameter AA
- movl %ecx, -12(%esp) # push parameter glue->method
+ movl rGLUE, %edx # %edx<- pMterpGlue
+ movl offGlue_method(%edx), %ecx # %ecx<- glue->method
+ EXPORT_PC # in case an exception is thrown
+ FETCH 1, %eax # %eax<- BBBB
+ movl %eax, -4(%esp) # push parameter BBBB; ref
+ movl rINST, -8(%esp) # push parameter AA
+ movl %ecx, -12(%esp) # push parameter glue->method
lea -12(%esp), %esp
- call dvmThrowVerificationError # call: (const Method* method, int kind, int ref)
- jmp common_exceptionThrown # failed; handle exception
+ call dvmThrowVerificationError # call: (const Method* method, int kind, int ref)
+ jmp common_exceptionThrown # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E8.S b/vm/mterp/x86-atom/OP_UNUSED_E8.S
deleted file mode 100644
index e83b199..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_E8.S
+++ /dev/null
@@ -1,20 +0,0 @@
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: OP_UNUSED_E8.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E9.S b/vm/mterp/x86-atom/OP_UNUSED_E9.S
deleted file mode 100644
index fcc21fd..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_E9.S
+++ /dev/null
@@ -1,20 +0,0 @@
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: OP_UNUSED_E9.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EA.S b/vm/mterp/x86-atom/OP_UNUSED_EA.S
deleted file mode 100644
index 804ea60..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_EA.S
+++ /dev/null
@@ -1,20 +0,0 @@
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: OP_UNUSED_EA.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EB.S b/vm/mterp/x86-atom/OP_UNUSED_EB.S
deleted file mode 100644
index 0438867..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_EB.S
+++ /dev/null
@@ -1,20 +0,0 @@
- /* Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: OP_UNUSED_EB.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_USHR_LONG.S b/vm/mterp/x86-atom/OP_USHR_LONG.S
index 35e8d69..1c404f0 100644
--- a/vm/mterp/x86-atom/OP_USHR_LONG.S
+++ b/vm/mterp/x86-atom/OP_USHR_LONG.S
@@ -37,4 +37,3 @@
psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
movsd %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
FINISH 2 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
index d3a215f..31cb5bc 100644
--- a/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
+++ b/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
@@ -39,4 +39,3 @@
psrlq %xmm0, %xmm1 # %xmm1<- shifted vA
movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
FINISH 1 # jump to next instruction
-
diff --git a/vm/mterp/x86-atom/TODO.txt b/vm/mterp/x86-atom/TODO.txt
index dea2285..abeee31 100644
--- a/vm/mterp/x86-atom/TODO.txt
+++ b/vm/mterp/x86-atom/TODO.txt
@@ -1,10 +1,15 @@
Items requiring attention:
+(hi) Add gc card marking to aput/iput/sput/new_filled_array
(hi) Correct stack overflow handling (dvmCleanupStackOverflow takes an
additional argument now)
+(hi) "debugger active" test in common_periodicChecks must handle
+ the case where glue->pDebuggerActive is a NULL pointer (used to
+ skip a memory load when debugger support is completely disabled)
(md) Correct OP_MONITOR_EXIT (need to adjust PC before throw)
+(md) OP_THROW needs to export the PC
(lo) Implement OP_BREAKPOINT
(lo) Implement OP_EXECUTE_INLINE_RANGE
-
+(lo) Implement OP_*_VOLATILE (12 instructions)
diff --git a/vm/mterp/x86-atom/binop.S b/vm/mterp/x86-atom/binop.S
index 7fc6de2..0343190 100644
--- a/vm/mterp/x86-atom/binop.S
+++ b/vm/mterp/x86-atom/binop.S
@@ -40,5 +40,3 @@
$instr # %ecx<- vBB op vCC
SET_VREG %ecx, rINST # vAA<- %ecx; result
OLD_JMP_4 %eax
-
-
diff --git a/vm/mterp/x86-atom/binop2addr.S b/vm/mterp/x86-atom/binop2addr.S
index 2aa55a1..af135a7 100644
--- a/vm/mterp/x86-atom/binop2addr.S
+++ b/vm/mterp/x86-atom/binop2addr.S
@@ -42,5 +42,3 @@
$instr # %ecx<- vA op vB
#FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
OLD_JMP_4 %eax
-
-
diff --git a/vm/mterp/x86-atom/binopD2addr.S b/vm/mterp/x86-atom/binopD2addr.S
index 789f899..a4fcf65 100644
--- a/vm/mterp/x86-atom/binopD2addr.S
+++ b/vm/mterp/x86-atom/binopD2addr.S
@@ -66,4 +66,3 @@
movl $$0, (rFP, rINST, 4) # vAA<- 0
.endif
FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/binopDLit16.S b/vm/mterp/x86-atom/binopDLit16.S
index 7c1a3b3..86bb937 100644
--- a/vm/mterp/x86-atom/binopDLit16.S
+++ b/vm/mterp/x86-atom/binopDLit16.S
@@ -69,4 +69,3 @@
.endif
movzbl 1(rPC), rINST
jmp *dvmAsmInstructionJmpTable(, %edx, 4)
-
diff --git a/vm/mterp/x86-atom/entry.S b/vm/mterp/x86-atom/entry.S
index e33cf39..8a3c9c1 100644
--- a/vm/mterp/x86-atom/entry.S
+++ b/vm/mterp/x86-atom/entry.S
@@ -365,14 +365,14 @@
.long .L_OP_UNUSED_E5
.long .L_OP_UNUSED_E6
.long .L_OP_UNUSED_E7
-.long .L_OP_UNUSED_E8
-.long .L_OP_UNUSED_E9
-.long .L_OP_UNUSED_EA
-.long .L_OP_UNUSED_EB
-.long .L_OP_UNUSED_EC
+.long .L_OP_IGET_WIDE_VOLATILE
+.long .L_OP_IPUT_WIDE_VOLATILE
+.long .L_OP_SGET_WIDE_VOLATILE
+.long .L_OP_SPUT_WIDE_VOLATILE
+.long .L_OP_BREAKPOINT
.long .L_OP_THROW_VERIFICATION_ERROR
.long .L_OP_EXECUTE_INLINE
-.long .L_OP_UNUSED_EF
+.long .L_OP_EXECUTE_INLINE_RANGE
.long .L_OP_INVOKE_DIRECT_EMPTY
.long .L_OP_UNUSED_F1
.long .L_OP_IGET_QUICK
diff --git a/vm/mterp/x86-atom/unopWide.S b/vm/mterp/x86-atom/unopWide.S
index 1e4795c..3790a2c 100644
--- a/vm/mterp/x86-atom/unopWide.S
+++ b/vm/mterp/x86-atom/unopWide.S
@@ -41,5 +41,3 @@
$instr # do operation part 2
movq $result, (rFP, %ecx, 4) # vA<- result
FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
diff --git a/vm/mterp/x86-atom/unused.S b/vm/mterp/x86-atom/unused.S
index 8898f1e..8267709 100644
--- a/vm/mterp/x86-atom/unused.S
+++ b/vm/mterp/x86-atom/unused.S
@@ -28,4 +28,3 @@
*/
call common_abort
-
diff --git a/vm/mterp/x86/OP_AGET.S b/vm/mterp/x86/OP_AGET.S
index d83786b..fe87037 100644
--- a/vm/mterp/x86/OP_AGET.S
+++ b/vm/mterp/x86/OP_AGET.S
@@ -21,4 +21,3 @@
SET_VREG(%eax,%ecx)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_AGET_WIDE.S b/vm/mterp/x86/OP_AGET_WIDE.S
index 2470bc5..c050156 100644
--- a/vm/mterp/x86/OP_AGET_WIDE.S
+++ b/vm/mterp/x86/OP_AGET_WIDE.S
@@ -25,4 +25,3 @@
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_APUT.S b/vm/mterp/x86/OP_APUT.S
index b99c1b2..b9a660f 100644
--- a/vm/mterp/x86/OP_APUT.S
+++ b/vm/mterp/x86/OP_APUT.S
@@ -21,4 +21,3 @@
$store $reg,(%eax)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_APUT_OBJECT.S b/vm/mterp/x86/OP_APUT_OBJECT.S
index 640894e..d2ec565 100644
--- a/vm/mterp/x86/OP_APUT_OBJECT.S
+++ b/vm/mterp/x86/OP_APUT_OBJECT.S
@@ -37,11 +37,18 @@
UNSPILL(rPC)
UNSPILL_TMP(%ecx)
testl %eax,%eax
+ GET_GLUE(%eax)
je common_errArrayStore
+ movl offGlue_cardTable(%eax),%eax # get card table base
+ movl rINST_FULL,(%ecx)
+ FETCH_INST_WORD(2)
+ shrl $$GC_CARD_SHIFT,%ecx # convert addr to card number
+ movb %al,(%eax,%ecx) # mark card
+ ADVANCE_PC(2)
+ GOTO_NEXT
.L${opcode}_skip_check:
movl rINST_FULL,(%ecx)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_APUT_WIDE.S b/vm/mterp/x86/OP_APUT_WIDE.S
index 1f67057..658ca7c 100644
--- a/vm/mterp/x86/OP_APUT_WIDE.S
+++ b/vm/mterp/x86/OP_APUT_WIDE.S
@@ -25,4 +25,3 @@
movl %ecx,(%eax)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_CONST_4.S b/vm/mterp/x86/OP_CONST_4.S
index 284a30b..499f7c3 100644
--- a/vm/mterp/x86/OP_CONST_4.S
+++ b/vm/mterp/x86/OP_CONST_4.S
@@ -8,4 +8,3 @@
sarl $$4,%eax
SET_VREG(%eax,%ecx)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_CONST_CLASS.S b/vm/mterp/x86/OP_CONST_CLASS.S
index 4d76a7c..fa37917 100644
--- a/vm/mterp/x86/OP_CONST_CLASS.S
+++ b/vm/mterp/x86/OP_CONST_CLASS.S
@@ -39,4 +39,3 @@
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_CONST_STRING.S b/vm/mterp/x86/OP_CONST_STRING.S
index 68e71e6..96e5dcd 100644
--- a/vm/mterp/x86/OP_CONST_STRING.S
+++ b/vm/mterp/x86/OP_CONST_STRING.S
@@ -38,4 +38,3 @@
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_CONST_STRING_JUMBO.S b/vm/mterp/x86/OP_CONST_STRING_JUMBO.S
index 2ccfdb4..45316f9 100644
--- a/vm/mterp/x86/OP_CONST_STRING_JUMBO.S
+++ b/vm/mterp/x86/OP_CONST_STRING_JUMBO.S
@@ -38,4 +38,3 @@
FETCH_INST_WORD(3)
ADVANCE_PC(3)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_CONST_WIDE.S b/vm/mterp/x86/OP_CONST_WIDE.S
index 55145de..aa582b8 100644
--- a/vm/mterp/x86/OP_CONST_WIDE.S
+++ b/vm/mterp/x86/OP_CONST_WIDE.S
@@ -9,4 +9,3 @@
movl %eax,(%ecx)
ADVANCE_PC(5)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S b/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S
index 00d1e97..1d726f4 100644
--- a/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S
+++ b/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S
@@ -9,4 +9,3 @@
xorl %eax,%eax
SET_VREG_WORD(%eax,%ecx,0) # v[AA+0]<- eax
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_DIV_LONG.S b/vm/mterp/x86/OP_DIV_LONG.S
index 6d408ab..f324be3 100644
--- a/vm/mterp/x86/OP_DIV_LONG.S
+++ b/vm/mterp/x86/OP_DIV_LONG.S
@@ -50,6 +50,3 @@
xorl %eax,%eax
movl $special,%edx
jmp .L${opcode}_finish
-
-
-
diff --git a/vm/mterp/x86/OP_DIV_LONG_2ADDR.S b/vm/mterp/x86/OP_DIV_LONG_2ADDR.S
index 01de27c..128ede0 100644
--- a/vm/mterp/x86/OP_DIV_LONG_2ADDR.S
+++ b/vm/mterp/x86/OP_DIV_LONG_2ADDR.S
@@ -52,4 +52,3 @@
xorl %eax,%eax
movl $special,%edx
jmp .L${opcode}_finish
-
diff --git a/vm/mterp/x86/OP_EXECUTE_INLINE.S b/vm/mterp/x86/OP_EXECUTE_INLINE.S
index 9567b74..1eca6e2 100644
--- a/vm/mterp/x86/OP_EXECUTE_INLINE.S
+++ b/vm/mterp/x86/OP_EXECUTE_INLINE.S
@@ -64,4 +64,3 @@
sall $$4,%eax # index *= sizeof(table entry)
jmp *gDvmInlineOpsTable(%eax)
# will return to caller of .L${opcode}_continue
-
diff --git a/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S b/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
index aa247a8..b990aeb 100644
--- a/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
+++ b/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
@@ -48,6 +48,7 @@
movl $$ALLOC_DONT_TRACK,OUT_ARG2(%esp) # arg2<- flags
movzbl 1(%ecx),%ecx # ecx<- descriptor[1]
movl %eax,OUT_ARG0(%esp) # arg0<- arrayClass
+ GET_GLUE(%eax)
cmpb $$'I',%cl # supported?
je 1f
cmpb $$'L',%cl
@@ -55,6 +56,7 @@
cmpb $$'[',%cl
jne .L${opcode}_notimpl # no, not handled yet
1:
+ movl %ecx,offGlue_retval+4(%eax) # save type
.if (!$isrange)
SPILL_TMP(rINST_FULL) # save copy, need "B" later
sarl $$4,rINST_FULL
@@ -88,7 +90,9 @@
FETCH_INST_WORD(3)
rep
movsd
+ GET_GLUE(%ecx)
UNSPILL(rIBASE)
+ movl offGlue_retval+4(%ecx),%eax # eax<- type
UNSPILL(rFP)
.else
testl rINST_FULL,rINST_FULL
@@ -107,10 +111,19 @@
sub $$1,rINST_FULL
jne 3b
4:
+ GET_GLUE(%ecx)
UNSPILL(rPC)
+ movl offGlue_retval+4(%ecx),%eax # eax<- type
FETCH_INST_WORD(3)
.endif
+ cmpb $$'I',%al # Int array?
+ je 5f # skip card mark if so
+ movl offGlue_retval(%ecx),%eax # eax<- object head
+ movl offGlue_cardTable(%ecx),%ecx # card table base
+ shrl $$GC_CARD_SHIFT,%eax # convert to card num
+ movb %cl,(%ecx,%eax) # mark card
+5:
ADVANCE_PC(3)
GOTO_NEXT
@@ -127,4 +140,3 @@
call dvmThrowException
UNSPILL(rPC)
jmp common_exceptionThrown
-
diff --git a/vm/mterp/x86/OP_IGET.S b/vm/mterp/x86/OP_IGET.S
index 38a67cd..cd8033f 100644
--- a/vm/mterp/x86/OP_IGET.S
+++ b/vm/mterp/x86/OP_IGET.S
@@ -62,4 +62,3 @@
SET_VREG(%ecx,%eax)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_IGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..4576d39
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_OBJECT_VOLATILE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86/OP_IGET_VOLATILE.S b/vm/mterp/x86/OP_IGET_VOLATILE.S
new file mode 100644
index 0000000..4576d39
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_VOLATILE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86/OP_IGET_WIDE.S b/vm/mterp/x86/OP_IGET_WIDE.S
index 4a91d1b..77a5994 100644
--- a/vm/mterp/x86/OP_IGET_WIDE.S
+++ b/vm/mterp/x86/OP_IGET_WIDE.S
@@ -62,4 +62,3 @@
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_INSTANCE_OF.S b/vm/mterp/x86/OP_INSTANCE_OF.S
index 1f52b56..71b92d3 100644
--- a/vm/mterp/x86/OP_INSTANCE_OF.S
+++ b/vm/mterp/x86/OP_INSTANCE_OF.S
@@ -100,4 +100,3 @@
GET_VREG(%eax,%eax) # eax<- vB (obj)
movl offObject_clazz(%eax),%eax # eax<- obj->clazz
jmp .L${opcode}_resolved
-
diff --git a/vm/mterp/x86/OP_INVOKE_INTERFACE.S b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
index 1631177..ff48ab8 100644
--- a/vm/mterp/x86/OP_INVOKE_INTERFACE.S
+++ b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
@@ -36,4 +36,3 @@
testl %eax,%eax
je common_exceptionThrown
jmp common_invokeMethod${routine}
-
diff --git a/vm/mterp/x86/OP_INVOKE_STATIC.S b/vm/mterp/x86/OP_INVOKE_STATIC.S
index 40dac06..a8a8d77 100644
--- a/vm/mterp/x86/OP_INVOKE_STATIC.S
+++ b/vm/mterp/x86/OP_INVOKE_STATIC.S
@@ -34,4 +34,3 @@
testl %eax,%eax # got null?
jne common_invokeMethod${routine}
jmp common_exceptionThrown
-
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
index 7545eb0..96c662a 100644
--- a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
@@ -24,4 +24,3 @@
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
jmp common_invokeMethod${routine}
-
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
index 20d9120..85fcf83 100644
--- a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
@@ -53,4 +53,3 @@
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
jmp common_invokeMethod${routine}
-
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
index f36ed2d..1ba93eb 100644
--- a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
@@ -21,5 +21,3 @@
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
jmp common_invokeMethod${routine}
-
-
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT.S b/vm/mterp/x86/OP_IPUT_OBJECT.S
index caf007e..39c64e7 100644
--- a/vm/mterp/x86/OP_IPUT_OBJECT.S
+++ b/vm/mterp/x86/OP_IPUT_OBJECT.S
@@ -1,2 +1,70 @@
+%default { "sqnum":"0" }
%verify "executed"
-%include "x86/OP_IPUT.S"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Object field put.
+ *
+ * for: iput-object
+ */
+ /* op vA, vB, field@CCCC */
+ GET_GLUE(%ecx)
+ SPILL(rIBASE) # need another reg
+ movzwl 2(rPC),rIBASE # rIBASE<- 0000CCCC
+ movl offGlue_methodClassDex(%ecx),%eax # eax<- DvmDex
+ movzbl rINST_HI,%ecx # ecx<- BA
+ sarl $$4,%ecx # ecx<- B
+ movl offDvmDex_pResFields(%eax),%eax # eax<- pDvmDex->pResFields
+ movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
+ andb $$0xf,rINST_LO # rINST_FULL<- A
+ GET_VREG(%ecx,%ecx) # ecx<- fp[B], the object ptr
+ movl (%eax,rIBASE,4),%eax # resolved entry
+ testl %eax,%eax # is resolved entry null?
+ jne .L${opcode}_finish # no, already resolved
+ movl rIBASE,OUT_ARG1(%esp)
+ GET_GLUE(rIBASE)
+ jmp .L${opcode}_resolve
+%break
+
+
+.L${opcode}_resolve:
+ EXPORT_PC()
+ SPILL(rPC)
+ movl offGlue_method(rIBASE),rPC # rPC<- current method
+ UNSPILL(rIBASE)
+ movl offMethod_clazz(rPC),rPC # rPC<- method->clazz
+ SPILL_TMP(%ecx) # save object pointer across call
+ movl rPC,OUT_ARG0(%esp) # pass in method->clazz
+ call dvmResolveInstField # ... to dvmResolveInstField
+ UNSPILL_TMP(%ecx)
+ UNSPILL(rPC)
+ testl %eax,%eax # ... which returns InstrField ptr
+ jne .L${opcode}_finish
+ jmp common_exceptionThrown
+
+.L${opcode}_finish:
+ /*
+ * Currently:
+ * eax holds resolved field
+ * ecx holds object
+ * rIBASE is scratch, but needs to be unspilled
+ * rINST_FULL holds A
+ */
+ GET_VREG(rINST_FULL,rINST_FULL) # rINST_FULL<- v[A]
+ movl offInstField_byteOffset(%eax),%eax # eax<- byte offset of field
+ UNSPILL(rIBASE)
+ testl %ecx,%ecx # object null?
+ je common_errNullObject # object was null
+ movl rINST_FULL,(%ecx,%eax) # obj.field <- v[A](8/16/32 bits)
+ GET_GLUE(%eax)
+ testl rINST_FULL,rINST_FULL # stored a NULL?
+ movl offGlue_cardTable(%eax),%eax # get card table base
+ FETCH_INST_WORD(2)
+ je 1f # skip card mark if null store
+ shrl $$GC_CARD_SHIFT,%ecx # object head to card number
+ movb %al,(%eax,%ecx) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S
index a8e851c..fb7205b 100644
--- a/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S
+++ b/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S
@@ -1,2 +1,28 @@
%verify "executed"
-%include "x86/OP_IPUT_QUICK.S"
+%verify "null object"
+ /* For: iput-object-quick */
+ /* op vA, vB, offset@CCCC */
+ movzbl rINST_HI,%ecx # ecx<- BA
+ sarl $$4,%ecx # ecx<- B
+ GET_VREG(%ecx,%ecx) # vB (object we're operating on)
+ movzbl rINST_HI,rINST_FULL
+ andb $$0xf,rINST_LO # rINST_FULL<- A
+ GET_VREG(rINST_FULL,rINST_FULL) # rINST_FULL<- v[A]
+ movzwl 2(rPC),%eax # eax<- field byte offset
+ testl %ecx,%ecx # is object null?
+ je common_errNullObject
+ movl rINST_FULL,(%ecx,%eax,1)
+ GET_GLUE(%eax)
+ jmp .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+ testl rINST_FULL,rINST_FULL # did we store null?
+ FETCH_INST_WORD(2)
+ movl offGlue_cardTable(%eax),%eax # get card table base
+ je 1f # skip card mark if null store
+ shrl $$GC_CARD_SHIFT,%ecx # object head to card number
+ movb %al,(%eax,%ecx) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_IPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..3959c06
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT_OBJECT.S"
diff --git a/vm/mterp/x86/OP_IPUT_QUICK.S b/vm/mterp/x86/OP_IPUT_QUICK.S
index 60d6fad..e62ec00 100644
--- a/vm/mterp/x86/OP_IPUT_QUICK.S
+++ b/vm/mterp/x86/OP_IPUT_QUICK.S
@@ -1,6 +1,6 @@
%verify "executed"
%verify "null object"
- /* For: iput-quick, iput-object-quick */
+ /* For: iput-quick */
/* op vA, vB, offset@CCCC */
movzbl rINST_HI,%ecx # ecx<- BA
sarl $$4,%ecx # ecx<- B
diff --git a/vm/mterp/x86/OP_IPUT_VOLATILE.S b/vm/mterp/x86/OP_IPUT_VOLATILE.S
new file mode 100644
index 0000000..caf007e
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT.S"
diff --git a/vm/mterp/x86/OP_MOVE_FROM16.S b/vm/mterp/x86/OP_MOVE_FROM16.S
index e14817d..35d3147 100644
--- a/vm/mterp/x86/OP_MOVE_FROM16.S
+++ b/vm/mterp/x86/OP_MOVE_FROM16.S
@@ -8,4 +8,3 @@
ADVANCE_PC(2)
SET_VREG (%ecx,%eax) # fp[AA]<- ecx]
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_MUL_INT_LIT8.S b/vm/mterp/x86/OP_MUL_INT_LIT8.S
index 8a046c3..2cf11b3 100644
--- a/vm/mterp/x86/OP_MUL_INT_LIT8.S
+++ b/vm/mterp/x86/OP_MUL_INT_LIT8.S
@@ -11,4 +11,3 @@
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_MUL_LONG.S b/vm/mterp/x86/OP_MUL_LONG.S
index 3bee2c6..fd151e0 100644
--- a/vm/mterp/x86/OP_MUL_LONG.S
+++ b/vm/mterp/x86/OP_MUL_LONG.S
@@ -41,4 +41,3 @@
movl %eax,(rFP,%ecx,4) # v[B]<- %eax
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_MUL_LONG_2ADDR.S b/vm/mterp/x86/OP_MUL_LONG_2ADDR.S
index 83a042a..5651dfe 100644
--- a/vm/mterp/x86/OP_MUL_LONG_2ADDR.S
+++ b/vm/mterp/x86/OP_MUL_LONG_2ADDR.S
@@ -39,4 +39,3 @@
UNSPILL(rIBASE)
ADVANCE_PC(1)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_NEW_ARRAY.S b/vm/mterp/x86/OP_NEW_ARRAY.S
index cb07aed..74d72ed 100644
--- a/vm/mterp/x86/OP_NEW_ARRAY.S
+++ b/vm/mterp/x86/OP_NEW_ARRAY.S
@@ -70,4 +70,3 @@
SET_VREG(%eax,%ecx)
ADVANCE_PC(2)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/OP_NEW_INSTANCE.S b/vm/mterp/x86/OP_NEW_INSTANCE.S
index d56d55c..e11e518 100644
--- a/vm/mterp/x86/OP_NEW_INSTANCE.S
+++ b/vm/mterp/x86/OP_NEW_INSTANCE.S
@@ -91,6 +91,3 @@
call dvmThrowExceptionWithClassMessage
UNSPILL(rPC)
jmp common_exceptionThrown
-
-
-
diff --git a/vm/mterp/x86/OP_OR_INT_LIT16.S b/vm/mterp/x86/OP_OR_INT_LIT16.S
index ec4f9c1..fa70e99 100644
--- a/vm/mterp/x86/OP_OR_INT_LIT16.S
+++ b/vm/mterp/x86/OP_OR_INT_LIT16.S
@@ -1,3 +1,2 @@
%verify "executed"
%include "x86/binopLit16.S" {"instr":"orl %ecx,%eax"}
-
diff --git a/vm/mterp/x86/OP_OR_INT_LIT8.S b/vm/mterp/x86/OP_OR_INT_LIT8.S
index d4cc0b4..5761806 100644
--- a/vm/mterp/x86/OP_OR_INT_LIT8.S
+++ b/vm/mterp/x86/OP_OR_INT_LIT8.S
@@ -1,3 +1,2 @@
%verify "executed"
%include "x86/binopLit8.S" {"instr":"orl %ecx,%eax"}
-
diff --git a/vm/mterp/x86/OP_RETURN_VOID.S b/vm/mterp/x86/OP_RETURN_VOID.S
index 48aaba9..4d4291f 100644
--- a/vm/mterp/x86/OP_RETURN_VOID.S
+++ b/vm/mterp/x86/OP_RETURN_VOID.S
@@ -1,3 +1,2 @@
%verify "executed"
jmp common_returnFromMethod
-
diff --git a/vm/mterp/x86/OP_SGET.S b/vm/mterp/x86/OP_SGET.S
index 7c17579..f05eae7 100644
--- a/vm/mterp/x86/OP_SGET.S
+++ b/vm/mterp/x86/OP_SGET.S
@@ -41,4 +41,3 @@
testl %eax,%eax
jne .L${opcode}_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
diff --git a/vm/mterp/x86/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_SGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_VOLATILE.S b/vm/mterp/x86/OP_SGET_VOLATILE.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_WIDE.S b/vm/mterp/x86/OP_SGET_WIDE.S
index 17c71fb..5c038a7 100644
--- a/vm/mterp/x86/OP_SGET_WIDE.S
+++ b/vm/mterp/x86/OP_SGET_WIDE.S
@@ -42,4 +42,3 @@
testl %eax,%eax
jne .L${opcode}_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
diff --git a/vm/mterp/x86/OP_SPUT.S b/vm/mterp/x86/OP_SPUT.S
index d880422..440dcfb 100644
--- a/vm/mterp/x86/OP_SPUT.S
+++ b/vm/mterp/x86/OP_SPUT.S
@@ -5,7 +5,7 @@
/*
* General 32-bit SPUT handler.
*
- * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ * for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
GET_GLUE(%ecx)
@@ -41,4 +41,3 @@
testl %eax,%eax
jne .L${opcode}_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
diff --git a/vm/mterp/x86/OP_SPUT_OBJECT.S b/vm/mterp/x86/OP_SPUT_OBJECT.S
index ec0489f..f55d151 100644
--- a/vm/mterp/x86/OP_SPUT_OBJECT.S
+++ b/vm/mterp/x86/OP_SPUT_OBJECT.S
@@ -1,2 +1,49 @@
%verify "executed"
-%include "x86/OP_SPUT.S"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * SPUT object handler.
+ */
+ /* op vAA, field@BBBB */
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_methodClassDex(%ecx),%ecx # ecx<- DvmDex
+ movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+ movl (%ecx,%eax,4),%eax # eax<- resolved StaticField
+ testl %eax,%eax # resolved entry null?
+ je .L${opcode}_resolve # if not, make it so
+.L${opcode}_finish: # field ptr in eax
+ movzbl rINST_HI,%ecx # ecx<- AA
+ GET_VREG(%ecx,%ecx)
+ jmp .L${opcode}_continue
+%break
+
+
+.L${opcode}_continue:
+ movl %ecx,offStaticField_value(%eax)
+ testl %ecx,%ecx
+ GET_GLUE(%ecx)
+ FETCH_INST_WORD(2)
+ je 1f
+ movl offGlue_cardTable(%ecx),%ecx # get card table base
+ shrl $$GC_CARD_SHIFT,%eax # head to card number
+ movb %cl,(%ecx,%eax) # mark card
+1:
+ ADVANCE_PC(2)
+ GOTO_NEXT
+
+.L${opcode}_resolve:
+ GET_GLUE(%ecx)
+ movzwl 2(rPC),%eax # eax<- field ref BBBB
+ movl offGlue_method(%ecx),%ecx # ecx<- current method
+ EXPORT_PC() # could throw, need to export
+ movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+ SPILL(rPC)
+ movl %eax,OUT_ARG1(%esp)
+ movl %ecx,OUT_ARG0(%esp)
+ call dvmResolveStaticField # eax<- resolved StaticField ptr
+ UNSPILL(rPC)
+ testl %eax,%eax
+ jne .L${opcode}_finish # success, continue
+ jmp common_exceptionThrown # no, handle exception
diff --git a/vm/mterp/x86/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_SPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..afc6668
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT_OBJECT.S"
diff --git a/vm/mterp/x86/OP_SPUT_VOLATILE.S b/vm/mterp/x86/OP_SPUT_VOLATILE.S
new file mode 100644
index 0000000..ec0489f
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86/OP_SPUT_WIDE.S b/vm/mterp/x86/OP_SPUT_WIDE.S
index 584ce9d..5a48c2e 100644
--- a/vm/mterp/x86/OP_SPUT_WIDE.S
+++ b/vm/mterp/x86/OP_SPUT_WIDE.S
@@ -43,4 +43,3 @@
testl %eax,%eax
jne .L${opcode}_finish # success, continue
jmp common_exceptionThrown # no, handle exception
-
diff --git a/vm/mterp/x86/OP_THROW.S b/vm/mterp/x86/OP_THROW.S
index 7ed2ead..d7e1574 100644
--- a/vm/mterp/x86/OP_THROW.S
+++ b/vm/mterp/x86/OP_THROW.S
@@ -5,6 +5,7 @@
*/
/* throw vAA */
GET_GLUE(%ecx)
+ EXPORT_PC()
movzbl rINST_HI,rINST_FULL # rINST_FULL<- AA
GET_VREG(%eax,rINST_FULL) # eax<- exception object
movl offGlue_self(%ecx),%ecx # ecx<- glue->self
diff --git a/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S
index c3b5063..e492e2d 100644
--- a/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S
+++ b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S
@@ -17,4 +17,3 @@
call dvmThrowVerificationError # call(method, kind, ref)
UNSPILL(rPC)
jmp common_exceptionThrown # handle exception
-
diff --git a/vm/mterp/x86/OP_UNUSED_E8.S b/vm/mterp/x86/OP_UNUSED_E8.S
deleted file mode 100644
index 31d98c1..0000000
--- a/vm/mterp/x86/OP_UNUSED_E8.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E9.S b/vm/mterp/x86/OP_UNUSED_E9.S
deleted file mode 100644
index 31d98c1..0000000
--- a/vm/mterp/x86/OP_UNUSED_E9.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EA.S b/vm/mterp/x86/OP_UNUSED_EA.S
deleted file mode 100644
index 31d98c1..0000000
--- a/vm/mterp/x86/OP_UNUSED_EA.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EB.S b/vm/mterp/x86/OP_UNUSED_EB.S
deleted file mode 100644
index 31d98c1..0000000
--- a/vm/mterp/x86/OP_UNUSED_EB.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/vm/mterp/x86/binflop.S b/vm/mterp/x86/binflop.S
index 6f251ee..233799c 100644
--- a/vm/mterp/x86/binflop.S
+++ b/vm/mterp/x86/binflop.S
@@ -13,4 +13,3 @@
ADVANCE_PC(2)
$store (rFP,%ecx,4) # %st to vAA
GOTO_NEXT
-
diff --git a/vm/mterp/x86/binop.S b/vm/mterp/x86/binop.S
index 1370c8f..00d9118 100644
--- a/vm/mterp/x86/binop.S
+++ b/vm/mterp/x86/binop.S
@@ -18,4 +18,3 @@
ADVANCE_PC(2)
SET_VREG($result,%ecx)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/footer.S b/vm/mterp/x86/footer.S
index 8ed6c66..09eeb6e 100644
--- a/vm/mterp/x86/footer.S
+++ b/vm/mterp/x86/footer.S
@@ -276,6 +276,9 @@
* TUNING: Might be worthwhile to inline this.
* TODO: Basic-block style Jit will need a hook here as well. Fold it into
* the suspendCount check so we can get both in 1 shot.
+ * TODO: to match the other intepreters, this should handle suspension
+ * and then check for debugger/profiling after dvmCheckSuspendPending
+ * returns.
*/
common_periodicChecks:
movl offGlue_pSelfSuspendCount(%ecx),%eax # eax <- &suspendCount
@@ -290,9 +293,11 @@
movl offGlue_pActiveProfilers(%ecx),%ecx # ecx <- &ActiveProfilers
#endif
#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+ # TODO: check for NULL before load
movzbl (%eax),%eax # eax <- debuggerActive (boolean)
orl (%ecx),%eax # eax <- debuggerActive || activeProfilers
#elif defined(WITH_DEBUGGER)
+ # TODO: check for NULL before load
movzbl (%eax),%eax # eax <- debuggerActive (boolean)
#elif defined(WITH_PROFILER)
movl (%ecx),%eax # eax <= activeProfilers
@@ -536,4 +541,3 @@
.asciz "Ljava/lang/InternalError;"
.LstrFilledNewArrayNotImpl:
.asciz "filled-new-array only implemented for 'int'"
-
diff --git a/vm/mterp/x86/header.S b/vm/mterp/x86/header.S
index ff90d77..bb043ba 100644
--- a/vm/mterp/x86/header.S
+++ b/vm/mterp/x86/header.S
@@ -206,4 +206,3 @@
* to expand the macros into assembler assignment statements.
*/
#include "../common/asm-constants.h"
-
diff --git a/vm/mterp/x86/shop2addr.S b/vm/mterp/x86/shop2addr.S
index 63efeee..9e8bd56 100644
--- a/vm/mterp/x86/shop2addr.S
+++ b/vm/mterp/x86/shop2addr.S
@@ -14,4 +14,3 @@
FETCH_INST_WORD(1)
ADVANCE_PC(1)
GOTO_NEXT
-
diff --git a/vm/mterp/x86/zcmp.S b/vm/mterp/x86/zcmp.S
index 3acd093..221822d 100644
--- a/vm/mterp/x86/zcmp.S
+++ b/vm/mterp/x86/zcmp.S
@@ -20,4 +20,3 @@
FETCH_INST_INDEXED(%eax)
ADVANCE_PC_INDEXED(%eax)
GOTO_NEXT
-
diff --git a/vm/native/InternalNative.c b/vm/native/InternalNative.c
index 9b6b801..700c8af 100644
--- a/vm/native/InternalNative.c
+++ b/vm/native/InternalNative.c
@@ -56,7 +56,7 @@
{ "Ldalvik/system/VMStack;", dvm_dalvik_system_VMStack, 0 },
{ "Lorg/apache/harmony/dalvik/ddmc/DdmServer;",
dvm_org_apache_harmony_dalvik_ddmc_DdmServer, 0 },
- { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;",
+ { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;",
dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal, 0 },
{ "Lorg/apache/harmony/dalvik/NativeTestTarget;",
dvm_org_apache_harmony_dalvik_NativeTestTarget, 0 },
@@ -264,7 +264,7 @@
* check the access flags at the time of the method call. This results in
* "native abstract" methods, which can't exist. If we see the "abstract"
* flag set, clear the "native" flag.
- *
+ *
* We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
* position, because the callers of this function are trying to convey
* the "traditional" meaning of the flags to their callers.
@@ -276,11 +276,11 @@
}
flags &= ~ACC_SYNCHRONIZED;
-
+
if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
flags |= ACC_SYNCHRONIZED;
}
-
+
return flags & JAVA_FLAGS_MASK;
}
@@ -346,4 +346,3 @@
}
return false;
}
-
diff --git a/vm/native/InternalNativePriv.h b/vm/native/InternalNativePriv.h
index bcd9119..6f8d6c9 100644
--- a/vm/native/InternalNativePriv.h
+++ b/vm/native/InternalNativePriv.h
@@ -55,7 +55,7 @@
* check the access flags at the time of the method call. This results in
* "native abstract" methods, which can't exist. If we see the "abstract"
* flag set, clear the "native" flag.
- *
+ *
* We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
* position, because the callers of this function are trying to convey
* the "traditional" meaning of the flags to their callers.
diff --git a/vm/native/README.txt b/vm/native/README.txt
index 78630eb..bc8912f 100644
--- a/vm/native/README.txt
+++ b/vm/native/README.txt
@@ -21,4 +21,3 @@
JNI performance be deemed insufficient. The Bridge version is used as
an optimization for a few high-volume Object calls, and should generally
not be used as we may drop support for it at some point.
-
diff --git a/vm/native/dalvik_system_DexFile.c b/vm/native/dalvik_system_DexFile.c
index 95e01aa..25c9dfb 100644
--- a/vm/native/dalvik_system_DexFile.c
+++ b/vm/native/dalvik_system_DexFile.c
@@ -111,7 +111,6 @@
{
StringObject* sourceNameObj = (StringObject*) args[0];
StringObject* outputNameObj = (StringObject*) args[1];
- int flags = args[2];
DexOrJar* pDexOrJar = NULL;
JarFile* pJarFile;
RawDexFile* pRawDexFile;
@@ -336,6 +335,7 @@
DvmDex* pDvmDex;
DexFile* pDexFile;
ArrayObject* stringArray;
+ Thread* self = dvmThreadSelf();
if (!validateCookie(cookie))
RETURN_VOID();
@@ -350,10 +350,13 @@
int count = pDexFile->pHeader->classDefsSize;
stringArray = dvmAllocObjectArray(gDvm.classJavaLangString, count,
ALLOC_DEFAULT);
- if (stringArray == NULL)
- RETURN_VOID(); // should be an OOM pending
+ if (stringArray == NULL) {
+ /* probably OOM */
+ LOGD("Failed allocating array of %d strings\n", count);
+ assert(dvmCheckException(self));
+ RETURN_VOID();
+ }
- StringObject** contents = (StringObject**) stringArray->contents;
int i;
for (i = 0; i < count; i++) {
const DexClassDef* pClassDef = dexGetClassDef(pDexFile, i);
@@ -361,12 +364,13 @@
dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
char* className = dvmDescriptorToDot(descriptor);
- contents[i] = dvmCreateStringFromCstr(className, ALLOC_DEFAULT);
- dvmReleaseTrackedAlloc((Object*) contents[i], NULL);
+ StringObject* str = dvmCreateStringFromCstr(className);
+ dvmSetObjectArrayElement(stringArray, i, (Object *)str);
+ dvmReleaseTrackedAlloc((Object *)str, self);
free(className);
}
- dvmReleaseTrackedAlloc((Object*)stringArray, NULL);
+ dvmReleaseTrackedAlloc((Object*)stringArray, self);
RETURN_PTR(stringArray);
}
@@ -448,4 +452,3 @@
Dalvik_dalvik_system_DexFile_isDexOptNeeded },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index 34398d0..2f79033 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -20,16 +20,48 @@
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
+#include <string.h>
+#include <unistd.h>
#include <errno.h>
/*
+ * Extracts the fd from a FileDescriptor object.
+ *
+ * If an error is encountered, or the extracted descriptor is numerically
+ * invalid, this returns -1 with an exception raised.
+ */
+static int getFileDescriptor(Object* obj)
+{
+ assert(obj != NULL);
+ assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
+
+ InstField* field = dvmFindInstanceField(obj->clazz, "descriptor", "I");
+ if (field == NULL) {
+ dvmThrowException("Ljava/lang/NoSuchFieldException;",
+ "No FileDescriptor.descriptor field");
+ return -1;
+ }
+
+ int fd = dvmGetFieldInt(obj, field->byteOffset);
+ if (fd < 0) {
+ dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
+ "Invalid file descriptor");
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
* Convert an array of char* into a String[].
*
* Returns NULL on failure, with an exception raised.
*/
static ArrayObject* convertStringArray(char** strings, size_t count)
{
+ Thread* self = dvmThreadSelf();
+
/*
* Allocate an array to hold the String objects.
*/
@@ -46,27 +78,26 @@
if (stringArray == NULL) {
/* probably OOM */
LOGD("Failed allocating array of %d strings\n", count);
+ assert(dvmCheckException(self));
return NULL;
}
- Thread* self = dvmThreadSelf();
-
/*
* Create the individual String objects and add them to the array.
*/
- StringObject** contents = (StringObject**) stringArray->contents;
size_t i;
for (i = 0; i < count; i++) {
- contents[i] = dvmCreateStringFromCstr(strings[i], ALLOC_DEFAULT);
- if (contents[i] == NULL) {
+ Object *str =
+ (Object *)dvmCreateStringFromCstr(strings[i]);
+ if (str == NULL) {
/* probably OOM; drop out now */
- assert(dvmCheckException(dvmThreadSelf()));
+ assert(dvmCheckException(self));
dvmReleaseTrackedAlloc((Object*)stringArray, self);
return NULL;
}
-
+ dvmSetObjectArrayElement(stringArray, i, str);
/* stored in tracked array, okay to release */
- dvmReleaseTrackedAlloc((Object*)contents[i], self);
+ dvmReleaseTrackedAlloc(str, self);
}
dvmReleaseTrackedAlloc((Object*)stringArray, self);
@@ -325,7 +356,7 @@
{
#ifdef WITH_PROFILER
StringObject* traceFileStr = (StringObject*) args[0];
- DataObject* traceFd = (DataObject*) args[1];
+ Object* traceFd = (Object*) args[1];
int bufferSize = args[2];
int flags = args[3];
@@ -345,21 +376,18 @@
int fd = -1;
if (traceFd != NULL) {
- InstField* field =
- dvmFindInstanceField(traceFd->obj.clazz, "descriptor", "I");
- if (field == NULL) {
- dvmThrowException("Ljava/lang/NoSuchFieldException;",
- "No FileDescriptor.descriptor field");
+ int origFd = getFileDescriptor(traceFd);
+ if (origFd < 0)
RETURN_VOID();
- }
- fd = dup(dvmGetFieldInt(&traceFd->obj, field->byteOffset));
+
+ fd = dup(origFd);
if (fd < 0) {
dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
- "dup() failed: %s", strerror(errno));
+ "dup(%d) failed: %s", origFd, strerror(errno));
RETURN_VOID();
}
}
-
+
dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]",
fd, bufferSize, flags, (traceFileName == NULL && fd == -1));
free(traceFileName);
@@ -659,7 +687,7 @@
}
/*
- * static void dumpHprofData(String fileName)
+ * static void dumpHprofData(String fileName, FileDescriptor fd)
*
* Cause "hprof" data to be dumped. We can throw an IOException if an
* error occurs during file handling.
@@ -669,22 +697,37 @@
{
#ifdef WITH_HPROF
StringObject* fileNameStr = (StringObject*) args[0];
+ Object* fileDescriptor = (Object*) args[1];
char* fileName;
int result;
- if (fileNameStr == NULL) {
+ /*
+ * Only one of these may be NULL.
+ */
+ if (fileNameStr == NULL && fileDescriptor == NULL) {
dvmThrowException("Ljava/lang/NullPointerException;", NULL);
RETURN_VOID();
}
- fileName = dvmCreateCstrFromString(fileNameStr);
- if (fileName == NULL) {
- /* unexpected -- malloc failure? */
- dvmThrowException("Ljava/lang/RuntimeException;", "malloc failure?");
- RETURN_VOID();
+ if (fileNameStr != NULL) {
+ fileName = dvmCreateCstrFromString(fileNameStr);
+ if (fileName == NULL) {
+ /* unexpected -- malloc failure? */
+ dvmThrowException("Ljava/lang/RuntimeException;", "malloc failure?");
+ RETURN_VOID();
+ }
+ } else {
+ fileName = strdup("[fd]");
}
- result = hprofDumpHeap(fileName, false);
+ int fd = -1;
+ if (fileDescriptor != NULL) {
+ fd = getFileDescriptor(fileDescriptor);
+ if (fd < 0)
+ RETURN_VOID();
+ }
+
+ result = hprofDumpHeap(fileName, fd, false);
free(fileName);
if (result != 0) {
@@ -711,7 +754,7 @@
#ifdef WITH_HPROF
int result;
- result = hprofDumpHeap("[DDMS]", true);
+ result = hprofDumpHeap("[DDMS]", -1, true);
if (result != 0) {
/* ideally we'd throw something more specific based on actual failure */
@@ -937,7 +980,7 @@
Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
{ "threadCpuTimeNanos", "()J",
Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
- { "dumpHprofData", "(Ljava/lang/String;)V",
+ { "dumpHprofData", "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
Dalvik_dalvik_system_VMDebug_dumpHprofData },
{ "dumpHprofDataDdms", "()V",
Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
diff --git a/vm/native/dalvik_system_VMStack.c b/vm/native/dalvik_system_VMStack.c
index d62fea9..8db4a6b 100644
--- a/vm/native/dalvik_system_VMStack.c
+++ b/vm/native/dalvik_system_VMStack.c
@@ -150,18 +150,16 @@
/*
* Fill in the array.
*/
- ClassObject** objects = (ClassObject**) classes->contents;
-
- unsigned int sidx = 0;
- for (idx = kSkip; (int) idx < methodCount && sidx < size; idx++) {
- const Method* meth = methods[idx];
-
- if (dvmIsReflectionMethod(meth))
+ unsigned int objCount = 0;
+ for (idx = kSkip; (int) idx < methodCount; idx++) {
+ if (dvmIsReflectionMethod(methods[idx])) {
continue;
-
- *objects++ = meth->clazz;
- sidx++;
+ }
+ dvmSetObjectArrayElement(classes, objCount,
+ (Object *)methods[idx]->clazz);
+ objCount++;
}
+ assert(objCount == classes->length);
bail:
free(methods);
@@ -235,4 +233,3 @@
Dalvik_dalvik_system_VMStack_getThreadStackTrace },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/dalvik_system_Zygote.c b/vm/native/dalvik_system_Zygote.c
index f8e8250..8b09b96 100644
--- a/vm/native/dalvik_system_Zygote.c
+++ b/vm/native/dalvik_system_Zygote.c
@@ -88,14 +88,14 @@
#endif /* ifdef WCOREDUMP */
}
- /*
+ /*
* If the just-crashed process is the system_server, bring down zygote
* so that it is restarted by init and system server will be restarted
* from there.
*/
if (pid == gDvm.systemServerPid) {
LOG(LOG_INFO, ZYGOTE_LOG_TAG,
- "Exit zygote because system server (%d) has terminated\n",
+ "Exit zygote because system server (%d) has terminated\n",
(int) pid);
kill(getpid(), SIGKILL);
}
@@ -103,7 +103,7 @@
if (pid < 0) {
LOG(LOG_WARN, ZYGOTE_LOG_TAG,
- "Zygote SIGCHLD error (%d) in waitpid\n",errno);
+ "Zygote SIGCHLD error in waitpid: %s\n",strerror(errno));
}
}
@@ -116,7 +116,7 @@
* This ends up being called repeatedly before each fork(), but there's
* no real harm in that.
*/
-static void setSignalHandler()
+static void setSignalHandler()
{
int err;
struct sigaction sa;
@@ -126,9 +126,9 @@
sa.sa_handler = sigchldHandler;
err = sigaction (SIGCHLD, &sa, NULL);
-
+
if (err < 0) {
- LOGW("Error setting SIGCHLD handler errno: %d", errno);
+ LOGW("Error setting SIGCHLD handler: %s", strerror(errno));
}
}
@@ -145,13 +145,13 @@
sa.sa_handler = SIG_DFL;
err = sigaction (SIGCHLD, &sa, NULL);
-
+
if (err < 0) {
- LOGW("Error unsetting SIGCHLD handler errno: %d", errno);
+ LOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
}
}
-/*
+/*
* Calls POSIX setgroups() using the int[] object as an argument.
* A NULL argument is tolerated.
*/
@@ -217,7 +217,7 @@
return -1;
}
}
-
+
return 0;
}
@@ -225,7 +225,6 @@
static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue* pResult)
{
pid_t pid;
- int err;
if (!gDvm.zygote) {
dvmThrowException("Ljava/lang/IllegalStateException;",
@@ -239,7 +238,7 @@
dvmAbort();
}
- setSignalHandler();
+ setSignalHandler();
dvmDumpLoaderStats("zygote");
pid = fork();
@@ -309,22 +308,22 @@
* to disable that
*/
if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
- LOGE("could not set dumpable bit flag for pid %d, errno=%d",
- getpid(), errno);
+ LOGE("could not set dumpable bit flag for pid %d: %s",
+ getpid(), strerror(errno));
} else {
struct rlimit rl;
rl.rlim_cur = 0;
rl.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rl) < 0) {
- LOGE("could not disable core file generation "
- "for pid %d, errno=%d", getpid(), errno);
+ LOGE("could not disable core file generation for pid %d: %s",
+ getpid(), strerror(errno));
}
}
}
#endif
}
-/*
+/*
* Utility routine to fork zygote and specialize the child process.
*/
static pid_t forkAndSpecializeCommon(const u4* args)
@@ -349,7 +348,7 @@
dvmAbort();
}
- setSignalHandler();
+ setSignalHandler();
dvmDumpLoaderStats("zygote");
pid = fork();
@@ -367,7 +366,7 @@
err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
if (err < 0) {
- LOGW("cannot PR_SET_KEEPCAPS errno: %d", errno);
+ LOGW("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
}
}
@@ -376,23 +375,23 @@
err = setgroupsIntarray(gids);
if (err < 0) {
- LOGW("cannot setgroups() errno: %d", errno);
+ LOGW("cannot setgroups(): %s", strerror(errno));
}
err = setrlimitsFromArray(rlimits);
if (err < 0) {
- LOGW("cannot setrlimit() errno: %d", errno);
+ LOGW("cannot setrlimit(): %s", strerror(errno));
}
err = setgid(gid);
if (err < 0) {
- LOGW("cannot setgid(%d) errno: %d", gid, errno);
+ LOGW("cannot setgid(%d): %s", gid, strerror(errno));
}
err = setuid(uid);
if (err < 0) {
- LOGW("cannot setuid(%d) errno: %d", uid, errno);
+ LOGW("cannot setuid(%d): %s", uid, strerror(errno));
}
/*
@@ -404,7 +403,7 @@
/* configure additional debug options */
enableDebugFeatures(debugFlags);
- unsetSignalHandler();
+ unsetSignalHandler();
gDvm.zygote = false;
if (!dvmInitAfterZygote()) {
LOGE("error in post-zygote initialization\n");
@@ -417,8 +416,8 @@
return pid;
}
-/* native public static int forkAndSpecialize(int uid, int gid,
- * int[] gids, int debugFlags);
+/* native public static int forkAndSpecialize(int uid, int gid,
+ * int[] gids, int debugFlags);
*/
static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
JValue* pResult)
@@ -430,8 +429,8 @@
RETURN_INT(pid);
}
-/* native public static int forkSystemServer(int uid, int gid,
- * int[] gids, int debugFlags);
+/* native public static int forkSystemServer(int uid, int gid,
+ * int[] gids, int debugFlags);
*/
static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const u4* args, JValue* pResult)
diff --git a/vm/native/java_lang_Class.c b/vm/native/java_lang_Class.c
index 09b440f..3c772d9 100644
--- a/vm/native/java_lang_Class.c
+++ b/vm/native/java_lang_Class.c
@@ -191,12 +191,13 @@
0, ALLOC_DEFAULT);
}
} else if (publicOnly) {
- int i, newIdx, publicCount = 0;
+ u4 count, newIdx, publicCount = 0;
ClassObject** pSource = (ClassObject**) classes->contents;
+ u4 length = classes->length;
/* count up public classes */
- for (i = 0; i < (int)classes->length; i++) {
- if (dvmIsPublicClass(pSource[i]))
+ for (count = 0; count < length; count++) {
+ if (dvmIsPublicClass(pSource[count]))
publicCount++;
}
@@ -206,12 +207,13 @@
publicCount, ALLOC_DEFAULT);
/* copy them over */
- ClassObject** pDest = (ClassObject**) newClasses->contents;
- for (i = newIdx = 0; i < (int)classes->length; i++) {
- if (dvmIsPublicClass(pSource[i]))
- pDest[newIdx++] = pSource[i];
+ for (count = newIdx = 0; count < length; count++) {
+ if (dvmIsPublicClass(pSource[count])) {
+ dvmSetObjectArrayElement(newClasses, newIdx,
+ (Object *)pSource[count]);
+ newIdx++;
+ }
}
-
assert(newIdx == publicCount);
dvmReleaseTrackedAlloc((Object*) classes, NULL);
classes = newClasses;
@@ -318,11 +320,11 @@
}
/*
- * public String getName()
+ * private native String getNameNative()
*
* Return the class' name.
*/
-static void Dalvik_java_lang_Class_getName(const u4* args, JValue* pResult)
+static void Dalvik_java_lang_Class_getNameNative(const u4* args, JValue* pResult)
{
ClassObject* clazz = (ClassObject*) args[0];
const char* descriptor = clazz->descriptor;
@@ -351,7 +353,7 @@
}
}
- nameObj = dvmCreateStringFromCstr(name, ALLOC_DEFAULT);
+ nameObj = dvmCreateStringFromCstr(name);
} else {
/*
* Convert the UTF-8 name to a java.lang.String. The
@@ -363,7 +365,7 @@
* say, 128 bytes).
*/
char* dotName = dvmDescriptorToDot(clazz->descriptor);
- nameObj = dvmCreateStringFromCstr(dotName, ALLOC_DEFAULT);
+ nameObj = dvmCreateStringFromCstr(dotName);
free(dotName);
}
@@ -385,7 +387,7 @@
const DexFile* pDexFile = clazz->pDexFile;
const DexClassDef* pClassDef;
const DexClassId* pClassId;
-
+
pDexFile = clazz->pDexFile;
pClassDef = dvmDexFindClass(pDexFile, clazz->descriptor);
pClassId = dvmDexGetClassId(pDexFile, pClassDef->classIdx);
@@ -717,7 +719,7 @@
/*
* public String getInnerClassName()
*
- * Returns the simple name of a member class or local class, or null otherwise.
+ * Returns the simple name of a member class or local class, or null otherwise.
*/
static void Dalvik_java_lang_Class_getInnerClassName(const u4* args,
JValue* pResult)
@@ -725,7 +727,7 @@
ClassObject* clazz = (ClassObject*) args[0];
StringObject* nameObj;
int flags;
-
+
if (dvmGetInnerClass(clazz, &nameObj, &flags)) {
dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
RETURN_PTR(nameObj);
@@ -770,8 +772,8 @@
Dalvik_java_lang_Class_getInterfaces },
{ "getModifiers", "(Ljava/lang/Class;Z)I",
Dalvik_java_lang_Class_getModifiers },
- { "getName", "()Ljava/lang/String;",
- Dalvik_java_lang_Class_getName },
+ { "getNameNative", "()Ljava/lang/String;",
+ Dalvik_java_lang_Class_getNameNative },
{ "getSuperclass", "()Ljava/lang/Class;",
Dalvik_java_lang_Class_getSuperclass },
{ "isAssignableFrom", "(Ljava/lang/Class;)Z",
@@ -810,4 +812,3 @@
Dalvik_java_lang_Class_setAccessibleNoCheck },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_Object.c b/vm/native/java_lang_Object.c
index 44f581e..f2adf52 100644
--- a/vm/native/java_lang_Object.c
+++ b/vm/native/java_lang_Object.c
@@ -109,4 +109,3 @@
Dalvik_java_lang_Object_getClass },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_String.c b/vm/native/java_lang_String.c
index 48a8f83..b3cb7ec 100644
--- a/vm/native/java_lang_String.c
+++ b/vm/native/java_lang_String.c
@@ -40,4 +40,3 @@
Dalvik_java_lang_String_intern },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_System.c b/vm/native/java_lang_System.c
index e2533ed..96cc144 100644
--- a/vm/native/java_lang_System.c
+++ b/vm/native/java_lang_System.c
@@ -59,7 +59,10 @@
}
/* make sure it's an array */
if (!dvmIsArray(srcArray) || !dvmIsArray(dstArray)) {
- dvmThrowException("Ljava/lang/ArrayStoreException;", NULL);
+ dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
+ "source and destination must be arrays, but were %s and %s",
+ ((Object*)srcArray)->clazz->descriptor,
+ ((Object*)dstArray)->clazz->descriptor);
RETURN_VOID();
}
@@ -68,7 +71,9 @@
srcPos > (int) srcArray->length - length ||
dstPos > (int) dstArray->length - length)
{
- dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
+ dvmThrowExceptionFmt("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
+ srcArray->length, srcPos, dstArray->length, dstPos, length);
RETURN_VOID();
}
@@ -87,7 +92,9 @@
int width;
if (srcPrim != dstPrim || srcType != dstType) {
- dvmThrowException("Ljava/lang/ArrayStoreException;", NULL);
+ dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
+ "source and destination arrays are incompatible: %s and %s",
+ srcClass->descriptor, dstClass->descriptor);
RETURN_VOID();
}
@@ -143,6 +150,7 @@
(*copyFunc)((u1*)dstArray->contents + dstPos * width,
(const u1*)srcArray->contents + srcPos * width,
length * width);
+ dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
} else {
/*
* The arrays are not fundamentally compatible. However, we may
@@ -189,9 +197,12 @@
(*copyFunc)((u1*)dstArray->contents + dstPos * width,
(const u1*)srcArray->contents + srcPos * width,
copyCount * width);
-
+ dvmWriteBarrierArray(dstArray, 0, copyCount);
if (copyCount != length) {
- dvmThrowException("Ljava/lang/ArrayStoreException;", NULL);
+ dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
+ "source[%d] of type %s cannot be stored in destination array of type %s",
+ copyCount, srcObj[copyCount]->clazz->descriptor,
+ dstClass->descriptor);
RETURN_VOID();
}
}
@@ -267,7 +278,7 @@
name = dvmCreateCstrFromString(nameObj);
mappedName = dvmCreateSystemLibraryName(name);
if (mappedName != NULL) {
- result = dvmCreateStringFromCstr(mappedName, ALLOC_DEFAULT);
+ result = dvmCreateStringFromCstr(mappedName);
dvmReleaseTrackedAlloc((Object*) result, NULL);
}
@@ -289,4 +300,3 @@
Dalvik_java_lang_System_mapLibraryName },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_SystemProperties.c b/vm/native/java_lang_SystemProperties.c
index d3501f4..bbcf25e 100644
--- a/vm/native/java_lang_SystemProperties.c
+++ b/vm/native/java_lang_SystemProperties.c
@@ -62,4 +62,3 @@
Dalvik_java_lang_SystemProperties_postInit },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_Throwable.c b/vm/native/java_lang_Throwable.c
index cb94f0f..f96ee6d 100644
--- a/vm/native/java_lang_Throwable.c
+++ b/vm/native/java_lang_Throwable.c
@@ -63,4 +63,3 @@
Dalvik_java_lang_Throwable_nativeGetStackTrace },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_VMClassLoader.c b/vm/native/java_lang_VMClassLoader.c
index 2d4e4b3..e8dbc6e 100644
--- a/vm/native/java_lang_VMClassLoader.c
+++ b/vm/native/java_lang_VMClassLoader.c
@@ -85,7 +85,6 @@
ClassObject* clazz = NULL;
char* name = NULL;
char* descriptor = NULL;
- char* cp;
if (nameObj == NULL) {
dvmThrowException("Ljava/lang/NullPointerException;", NULL);
@@ -200,4 +199,3 @@
Dalvik_java_lang_VMClassLoader_loadClass },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_VMThread.c b/vm/native/java_lang_VMThread.c
index 459fd35..3b7331b 100644
--- a/vm/native/java_lang_VMThread.c
+++ b/vm/native/java_lang_VMThread.c
@@ -33,6 +33,7 @@
Object* threadObj = (Object*) args[0];
s8 stackSize = GET_ARG_LONG(args, 1);
+ /* copying collector will pin threadObj for us since it was an argument */
dvmCreateInterpThread(threadObj, (int) stackSize);
RETURN_VOID();
}
@@ -67,7 +68,7 @@
else
result = THREAD_ZOMBIE; // assume it used to exist and is now gone
dvmUnlockThreadList();
-
+
RETURN_INT(result);
}
@@ -197,7 +198,7 @@
Object* thisPtr = (Object*) args[0];
int newPriority = args[1];
Thread* thread;
-
+
dvmLockThreadList(NULL);
thread = dvmGetThreadFromThreadObject(thisPtr);
if (thread != NULL)
@@ -213,7 +214,6 @@
*/
static void Dalvik_java_lang_VMThread_sleep(const u4* args, JValue* pResult)
{
- Thread* self = dvmThreadSelf();
dvmThreadSleep(GET_ARG_LONG(args,0), args[2]);
RETURN_VOID();
}
@@ -260,4 +260,3 @@
Dalvik_java_lang_VMThread_yield },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_reflect_AccessibleObject.c b/vm/native/java_lang_reflect_AccessibleObject.c
index 3843f26..46a1357 100644
--- a/vm/native/java_lang_reflect_AccessibleObject.c
+++ b/vm/native/java_lang_reflect_AccessibleObject.c
@@ -42,4 +42,3 @@
Dalvik_java_lang_reflect_AccessibleObject_getClassSignatureAnnotation },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_reflect_Array.c b/vm/native/java_lang_reflect_Array.c
index ddd608e..e7713f6 100644
--- a/vm/native/java_lang_reflect_Array.c
+++ b/vm/native/java_lang_reflect_Array.c
@@ -144,4 +144,3 @@
Dalvik_java_lang_reflect_Array_createMultiArray },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_reflect_Constructor.c b/vm/native/java_lang_reflect_Constructor.c
index 6878f7b..76f69a9 100644
--- a/vm/native/java_lang_reflect_Constructor.c
+++ b/vm/native/java_lang_reflect_Constructor.c
@@ -162,4 +162,3 @@
Dalvik_java_lang_reflect_Constructor_getSignatureAnnotation },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_reflect_Field.c b/vm/native/java_lang_reflect_Field.c
index 72f4c65..cb9f2bf 100644
--- a/vm/native/java_lang_reflect_Field.c
+++ b/vm/native/java_lang_reflect_Field.c
@@ -231,6 +231,17 @@
fieldType->primitiveType == PRIM_DOUBLE)
{
fieldPtr->j = value.j;
+ } else if (fieldType->primitiveType == PRIM_NOT) {
+ if (slot < 0) {
+ StaticField *sfield;
+ sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
+ assert(fieldPtr == &sfield->value);
+ dvmSetStaticFieldObject(sfield, value.l);
+ } else {
+ int offset = declaringClass->ifields[slot].byteOffset;
+ assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
+ dvmSetFieldObject(obj, offset, value.l);
+ }
} else {
fieldPtr->i = value.i;
}
@@ -445,4 +456,3 @@
Dalvik_java_lang_reflect_Field_getSignatureAnnotation },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_reflect_Method.c b/vm/native/java_lang_reflect_Method.c
index 760a090..f73c8d0 100644
--- a/vm/native/java_lang_reflect_Method.c
+++ b/vm/native/java_lang_reflect_Method.c
@@ -217,4 +217,3 @@
Dalvik_java_lang_reflect_Method_getSignatureAnnotation },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_lang_reflect_Proxy.c b/vm/native/java_lang_reflect_Proxy.c
index e71e11d..da1232c 100644
--- a/vm/native/java_lang_reflect_Proxy.c
+++ b/vm/native/java_lang_reflect_Proxy.c
@@ -45,4 +45,3 @@
Dalvik_java_lang_reflect_Proxy_generateProxy },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_security_AccessController.c b/vm/native/java_security_AccessController.c
index e0699f5..378fb94 100644
--- a/vm/native/java_security_AccessController.c
+++ b/vm/native/java_security_AccessController.c
@@ -121,9 +121,8 @@
}
/* copy the ProtectionDomain objects out */
- Object** objects = (Object**) domains->contents;
- for (idx = 0; idx < subIdx; idx++)
- *objects++ = subSet[idx];
+ memcpy(domains->contents, subSet, subIdx * sizeof(Object *));
+ dvmWriteBarrierArray(domains, 0, subIdx);
bail:
free(subSet);
@@ -137,4 +136,3 @@
Dalvik_java_security_AccessController_getStackDomains },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/java_util_concurrent_atomic_AtomicLong.c b/vm/native/java_util_concurrent_atomic_AtomicLong.c
index c46631f..eb1d0de 100644
--- a/vm/native/java_util_concurrent_atomic_AtomicLong.c
+++ b/vm/native/java_util_concurrent_atomic_AtomicLong.c
@@ -36,4 +36,3 @@
Dalvik_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8 },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/org_apache_harmony_dalvik_NativeTestTarget.c b/vm/native/org_apache_harmony_dalvik_NativeTestTarget.c
index 131acd3..ccc9467 100644
--- a/vm/native/org_apache_harmony_dalvik_NativeTestTarget.c
+++ b/vm/native/org_apache_harmony_dalvik_NativeTestTarget.c
@@ -40,4 +40,3 @@
Dalvik_org_apache_harmony_dalvik_NativeTestTarget_emptyInternalMethod },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.c b/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.c
index 9c940d4..570d469 100644
--- a/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.c
+++ b/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.c
@@ -46,4 +46,3 @@
Dalvik_org_apache_harmony_dalvik_ddmc_DdmServer_nativeSendChunk },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.c b/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.c
index 5868a8b..caa280b 100644
--- a/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.c
+++ b/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.c
@@ -167,4 +167,3 @@
Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getRecentAllocations },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/native/sun_misc_Unsafe.c b/vm/native/sun_misc_Unsafe.c
index 9adebc8..7a64c46 100644
--- a/vm/native/sun_misc_Unsafe.c
+++ b/vm/native/sun_misc_Unsafe.c
@@ -84,8 +84,8 @@
s4 newValue = args[5];
volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
- // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
- int result = android_atomic_cmpxchg(expectedValue, newValue, address);
+ // Note: android_atomic_release_cas() returns 0 on success, not failure.
+ int result = android_atomic_release_cas(expectedValue, newValue, address);
RETURN_BOOLEAN(result == 0);
}
@@ -106,7 +106,7 @@
// Note: android_atomic_cmpxchg() returns 0 on success, not failure.
int result =
- android_quasiatomic_cmpxchg_64(expectedValue, newValue, address);
+ dvmQuasiAtomicCas64(expectedValue, newValue, address);
RETURN_BOOLEAN(result == 0);
}
@@ -126,9 +126,9 @@
int32_t* address = (int32_t*) (((u1*) obj) + offset);
// Note: android_atomic_cmpxchg() returns 0 on success, not failure.
- int result = android_atomic_cmpxchg((int32_t) expectedValue,
+ int result = android_atomic_release_cas((int32_t) expectedValue,
(int32_t) newValue, address);
-
+ dvmWriteBarrierField(obj, address);
RETURN_BOOLEAN(result == 0);
}
@@ -141,9 +141,10 @@
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
- volatile s4* address = (volatile s4*) (((u1*) obj) + offset);
+ volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
- RETURN_INT(*address);
+ int32_t value = android_atomic_acquire_load(address);
+ RETURN_INT(value);
}
/*
@@ -156,9 +157,9 @@
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s4 value = (s4) args[4];
- volatile s4* address = (volatile s4*) (((u1*) obj) + offset);
+ volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
- *address = value;
+ android_atomic_release_store(value, address);
RETURN_VOID();
}
@@ -171,9 +172,9 @@
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
- volatile s8* address = (volatile s8*) (((u1*) obj) + offset);
+ volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
- RETURN_LONG(android_quasiatomic_read_64(address));
+ RETURN_LONG(dvmQuasiAtomicRead64(address));
}
/*
@@ -186,9 +187,9 @@
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s8 value = GET_ARG_LONG(args, 4);
- volatile s8* address = (volatile s8*) (((u1*) obj) + offset);
+ volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
- android_quasiatomic_swap_64(value, address);
+ dvmQuasiAtomicSwap64(value, address);
RETURN_VOID();
}
@@ -201,9 +202,9 @@
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
- volatile Object** address = (volatile Object**) (((u1*) obj) + offset);
+ volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
- RETURN_PTR((void*) *address);
+ RETURN_PTR((Object*) android_atomic_acquire_load(address));
}
/*
@@ -217,12 +218,13 @@
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
Object* value = (Object*) args[4];
- volatile Object** address = (volatile Object**) (((u1*) obj) + offset);
+ volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
- *address = value;
+ android_atomic_release_store((int32_t)value, address);
+ dvmWriteBarrierField(obj, (void *)address);
RETURN_VOID();
}
-
+
/*
* public native int getInt(Object obj, long offset);
*/
@@ -304,6 +306,7 @@
Object** address = (Object**) (((u1*) obj) + offset);
*address = value;
+ dvmWriteBarrierField(obj, address);
RETURN_VOID();
}
@@ -347,4 +350,3 @@
Dalvik_sun_misc_Unsafe_putObject },
{ NULL, NULL, NULL },
};
-
diff --git a/vm/oo/AccessCheck.c b/vm/oo/AccessCheck.c
index e3a6946..95b7f3e 100644
--- a/vm/oo/AccessCheck.c
+++ b/vm/oo/AccessCheck.c
@@ -148,4 +148,3 @@
// field->clazz->descriptor, field->accessFlags);
return checkAccess(accessFrom, field->clazz, field->accessFlags);
}
-
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
index 4af03a9..9749f77 100644
--- a/vm/oo/Array.c
+++ b/vm/oo/Array.c
@@ -222,7 +222,7 @@
* The dimension we're creating is in dimensions[0], so when we recurse
* we advance the pointer.
*/
-ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim,
+ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim,
const int* dimensions)
{
ArrayObject* newArray;
@@ -246,7 +246,6 @@
}
} else {
ClassObject* subArrayClass;
- Object** contents;
int i;
/* if we have X[][], find X[] */
@@ -269,19 +268,16 @@
/*
* Create a new sub-array in every element of the array.
*/
- contents = (Object**) newArray->contents;
for (i = 0; i < *dimensions; i++) {
- ArrayObject* newSubArray;
-
- newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
- dimensions+1);
+ ArrayObject* newSubArray;
+ newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
+ dimensions+1);
if (newSubArray == NULL) {
dvmReleaseTrackedAlloc((Object*) newArray, NULL);
assert(dvmCheckException(dvmThreadSelf()));
return NULL;
}
-
- *contents++ = (Object*) newSubArray;
+ dvmSetObjectArrayElement(newArray, i, (Object *)newSubArray);
dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
}
}
@@ -423,16 +419,22 @@
newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
if (newClass == NULL)
return NULL;
- DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
+ DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
dvmSetClassSerialNumber(newClass);
newClass->descriptorAlloc = strdup(descriptor);
newClass->descriptor = newClass->descriptorAlloc;
- newClass->super = gDvm.classJavaLangObject;
+ dvmSetFieldObject((Object *)newClass,
+ offsetof(ClassObject, super),
+ (Object *)gDvm.classJavaLangObject);
newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
newClass->vtable = gDvm.classJavaLangObject->vtable;
newClass->primitiveType = PRIM_NOT;
- newClass->elementClass = elementClass;
- newClass->classLoader = elementClass->classLoader;
+ dvmSetFieldObject((Object *)newClass,
+ offsetof(ClassObject, elementClass),
+ (Object *)elementClass);
+ dvmSetFieldObject((Object *)newClass,
+ offsetof(ClassObject, classLoader),
+ (Object *)elementClass->classLoader);
newClass->arrayDim = arrayDim;
newClass->status = CLASS_INITIALIZED;
#if WITH_HPROF && WITH_HPROF_STACK
@@ -518,7 +520,6 @@
/* Clean up the class before letting the
* GC get its hands on it.
*/
- assert(newClass->obj.clazz == gDvm.unlinkedJavaLangClass);
dvmFreeClassInnards(newClass);
/* Let the GC free the class.
@@ -531,9 +532,6 @@
assert(newClass != NULL);
return newClass;
}
-
- /* make it available to the GC */
- newClass->obj.clazz = gDvm.classJavaLangClass;
dvmReleaseTrackedAlloc((Object*) newClass, NULL);
LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n",
@@ -599,8 +597,8 @@
ClassObject* primClass = createPrimitiveClass(idx);
dvmReleaseTrackedAlloc((Object*) primClass, NULL);
- if (!ATOMIC_CMP_SWAP((int*) &gDvm.primitiveClass[idx],
- 0, (int) primClass))
+ if (android_atomic_release_cas(0, (int) primClass,
+ (int*) &gDvm.primitiveClass[idx]) != 0)
{
/*
* Looks like somebody beat us to it. Free up the one we
@@ -616,9 +614,6 @@
/*
* Synthesize a primitive class.
*
- * The spec for java.lang.Class.isPrimitive describes the names to
- * be used for these classes.
- *
* Just creates the class and returns it (does not add it to the class list).
*/
static ClassObject* createPrimitiveClass(int idx)
@@ -668,21 +663,21 @@
ClassObject* dstElemClass)
{
Object** src = (Object**)srcArray->contents;
- Object** dst = (Object**)dstArray->contents;
- u4 count = dstArray->length;
+ u4 length, count;
assert(srcArray->length == dstArray->length);
assert(dstArray->obj.clazz->elementClass == dstElemClass ||
(dstArray->obj.clazz->elementClass == dstElemClass->elementClass &&
dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1));
- while (count--) {
- if (!dvmInstanceof((*src)->clazz, dstElemClass)) {
+ length = dstArray->length;
+ for (count = 0; count < length; count++) {
+ if (!dvmInstanceof(src[count]->clazz, dstElemClass)) {
LOGW("dvmCopyObjectArray: can't store %s in %s\n",
- (*src)->clazz->descriptor, dstElemClass->descriptor);
+ src[count]->clazz->descriptor, dstElemClass->descriptor);
return false;
}
- *dst++ = *src++;
+ dvmSetObjectArrayElement(dstArray, count, src[count]);
}
return true;
@@ -764,6 +759,41 @@
return true;
}
+static size_t arrayElementWidth(const ArrayObject *array)
+{
+ const char *descriptor;
+
+ if (dvmIsObjectArray(array)) {
+ return sizeof(Object *);
+ } else {
+ descriptor = array->obj.clazz->descriptor;
+ switch (descriptor[1]) {
+ case 'B': return 1; /* byte */
+ case 'C': return 2; /* char */
+ case 'D': return 8; /* double */
+ case 'F': return 4; /* float */
+ case 'I': return 4; /* int */
+ case 'J': return 8; /* long */
+ case 'S': return 2; /* short */
+ case 'Z': return 1; /* boolean */
+ }
+ }
+ LOGE("object %p has an unhandled descriptor '%s'", array, descriptor);
+ dvmDumpThread(dvmThreadSelf(), false);
+ dvmAbort();
+ return 0; /* Quiet the compiler. */
+}
+
+size_t dvmArrayObjectSize(const ArrayObject *array)
+{
+ size_t size;
+
+ assert(array != NULL);
+ size = offsetof(ArrayObject, contents);
+ size += array->length * arrayElementWidth(array);
+ return size;
+}
+
/*
* Add all primitive classes to the root set of objects.
TODO: do these belong to the root class loader?
diff --git a/vm/oo/Array.h b/vm/oo/Array.h
index 161b1c6..36a847e 100644
--- a/vm/oo/Array.h
+++ b/vm/oo/Array.h
@@ -152,4 +152,9 @@
bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
ClassObject* dstElemClass);
+/*
+ * Returns the size of the given array object in bytes.
+ */
+size_t dvmArrayObjectSize(const ArrayObject *array);
+
#endif /*_DALVIK_OO_ARRAY*/
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index 625a572..f10a9c6 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -23,6 +23,7 @@
#include "Dalvik.h"
#include "libdex/DexClass.h"
+#include "analysis/Optimize.h"
#include <stdlib.h>
#include <stddef.h>
@@ -164,6 +165,8 @@
*/
#define ZYGOTE_CLASS_CUTOFF 2304
+#define CLASS_SFIELD_SLOTS 1
+
static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap);
static void freeCpeArray(ClassPathEntry* cpe);
@@ -283,6 +286,21 @@
dvmLinearFree(NULL, str);
}
+static size_t classObjectSize(size_t sfieldCount)
+{
+ size_t size;
+
+ size = offsetof(ClassObject, sfields);
+ size += sizeof(StaticField) * sfieldCount;
+ return size;
+}
+
+size_t dvmClassObjectSize(const ClassObject *clazz)
+{
+ assert(clazz != NULL);
+ return classObjectSize(clazz->sfieldCount);
+}
+
/*
* Initialize the bootstrap class loader.
*
@@ -290,8 +308,6 @@
*/
bool dvmClassStartup(void)
{
- ClassObject* unlinkedClass;
-
/* make this a requirement -- don't currently support dirs in path */
if (strcmp(gDvm.bootClassPathStr, ".") == 0) {
LOGE("ERROR: must specify non-'.' bootclasspath\n");
@@ -324,23 +340,10 @@
gDvm.initiatingLoaderList =
calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
- /* This placeholder class is used while a ClassObject is
- * loading/linking so those not in the know can still say
- * "obj->clazz->...".
- */
- unlinkedClass = &gDvm.unlinkedJavaLangClassObject;
-
- memset(unlinkedClass, 0, sizeof(*unlinkedClass));
-
- /* Set obj->clazz to NULL so anyone who gets too interested
- * in the fake class will crash.
- */
- DVM_OBJECT_INIT(&unlinkedClass->obj, NULL);
- unlinkedClass->descriptor = "!unlinkedClass";
- dvmSetClassSerialNumber(unlinkedClass);
-
- gDvm.unlinkedJavaLangClass = unlinkedClass;
-
+ gDvm.classJavaLangClass = (ClassObject*) dvmMalloc(
+ classObjectSize(CLASS_SFIELD_SLOTS), ALLOC_DEFAULT);
+ DVM_OBJECT_INIT(&gDvm.classJavaLangClass->obj, gDvm.classJavaLangClass);
+ gDvm.classJavaLangClass->descriptor = "Ljava/lang/Class;";
/*
* Process the bootstrap class path. This means opening the specified
* DEX or Jar files and possibly running them through the optimizer.
@@ -799,7 +802,7 @@
}
LOGV("+++ using URL='%s'\n", urlBuf);
- urlObj = dvmCreateStringFromCstr(urlBuf, ALLOC_DEFAULT);
+ urlObj = dvmCreateStringFromCstr(urlBuf);
bail:
return urlObj;
@@ -822,7 +825,7 @@
static InitiatingLoaderList *dvmGetInitiatingLoaderList(ClassObject* clazz)
{
- assert(clazz->serialNumber > INITIAL_CLASS_SERIAL_NUMBER);
+ assert(clazz->serialNumber >= INITIAL_CLASS_SERIAL_NUMBER);
int classIndex = clazz->serialNumber-INITIAL_CLASS_SERIAL_NUMBER;
if (gDvm.initiatingLoaderList != NULL &&
classIndex < ZYGOTE_CLASS_CUTOFF) {
@@ -1127,7 +1130,8 @@
do {
oldValue = gDvm.classSerialNumber;
newValue = oldValue + 1;
- } while (!ATOMIC_CMP_SWAP(&gDvm.classSerialNumber, oldValue, newValue));
+ } while (android_atomic_release_cas(oldValue, newValue,
+ &gDvm.classSerialNumber) != 0);
clazz->serialNumber = (u4) oldValue;
}
@@ -1242,7 +1246,7 @@
dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
goto bail;
}
- nameObj = dvmCreateStringFromCstr(dotName, ALLOC_DEFAULT);
+ nameObj = dvmCreateStringFromCstr(dotName);
if (nameObj == NULL) {
assert(dvmCheckException(self));
goto bail;
@@ -1288,8 +1292,11 @@
dvmReleaseTrackedAlloc(excep, self);
clazz = NULL;
goto bail;
- } else {
- assert(clazz != NULL);
+ } else if (clazz == NULL) {
+ LOGW("ClassLoader returned NULL w/o exception pending\n");
+ dvmThrowException("Ljava/lang/NullPointerException;",
+ "ClassLoader returned null");
+ goto bail;
}
dvmAddInitiatingLoader(clazz, loader);
@@ -1469,7 +1476,6 @@
/* Let the GC free the class.
*/
- assert(clazz->obj.clazz == gDvm.unlinkedJavaLangClass);
dvmReleaseTrackedAlloc((Object*) clazz, NULL);
/* Grab the winning class.
@@ -1486,7 +1492,7 @@
/*
* Prepare and resolve.
*/
- if (!dvmLinkClass(clazz, false)) {
+ if (!dvmLinkClass(clazz)) {
assert(dvmCheckException(self));
/* Make note of the error and clean up the class.
@@ -1675,25 +1681,30 @@
* Note that we assume that java.lang.Class does not override
* finalize().
*/
- newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
+ /* TODO: Can there be fewer special checks in the usual path? */
+ assert(descriptor != NULL);
+ if (classLoader == NULL &&
+ strcmp(descriptor, "Ljava/lang/Class;") == 0) {
+ assert(gDvm.classJavaLangClass != NULL);
+ newClass = gDvm.classJavaLangClass;
+ } else {
+ size_t size = classObjectSize(pHeader->staticFieldsSize);
+ newClass = (ClassObject*) dvmMalloc(size, ALLOC_DEFAULT);
+ }
if (newClass == NULL)
return NULL;
- /* Until the class is loaded and linked, use a placeholder
- * obj->clazz value as a hint to the GC. We don't want
- * the GC trying to scan the object while it's full of Idx
- * values. Also, the real java.lang.Class may not exist
- * yet.
- */
- DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
-
+ DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
dvmSetClassSerialNumber(newClass);
newClass->descriptor = descriptor;
assert(newClass->descriptorAlloc == NULL);
newClass->accessFlags = pClassDef->accessFlags;
- newClass->classLoader = classLoader;
+ dvmSetFieldObject((Object *)newClass,
+ offsetof(ClassObject, classLoader),
+ (Object *)classLoader);
newClass->pDvmDex = pDvmDex;
newClass->primitiveType = PRIM_NOT;
+ newClass->status = CLASS_IDX;
/*
* Stuff the superclass index into the object pointer field. The linker
@@ -1704,7 +1715,7 @@
* newClass->super is not traversed or freed by dvmFreeClassInnards, so
* this is safe.
*/
- assert(sizeof(u4) == sizeof(ClassObject*));
+ assert(sizeof(u4) == sizeof(ClassObject*)); /* 32-bit check */
newClass->super = (ClassObject*) pClassDef->superclassIdx;
/*
@@ -1730,11 +1741,12 @@
/* load field definitions */
/*
- * TODO: consider over-allocating the class object and appending the
- * static field info onto the end. It's fixed-size and known at alloc
- * time. This would save a couple of native heap allocations, but it
- * would also make heap compaction more difficult because we pass Field
- * pointers around internally.
+ * Over-allocate the class object and append static field info
+ * onto the end. It's fixed-size and known at alloc time. This
+ * seems to increase zygote sharing. Heap compaction will have to
+ * be careful if it ever tries to move ClassObject instances,
+ * because we pass Field pointers around internally. But at least
+ * now these Field pointers are in the object heap.
*/
if (pHeader->staticFieldsSize != 0) {
@@ -1744,8 +1756,6 @@
DexField field;
newClass->sfieldCount = count;
- newClass->sfields =
- (StaticField*) calloc(count, sizeof(StaticField));
for (i = 0; i < count; i++) {
dexReadClassDataField(&pEncodedData, &field, &lastIndex);
loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
@@ -1850,7 +1860,6 @@
}
newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);
- newClass->status = CLASS_LOADED;
/* caller must call dvmReleaseTrackedAlloc */
return newClass;
@@ -1919,8 +1928,7 @@
if (clazz == NULL)
return;
- assert(clazz->obj.clazz == gDvm.classJavaLangClass ||
- clazz->obj.clazz == gDvm.unlinkedJavaLangClass);
+ assert(clazz->obj.clazz == gDvm.classJavaLangClass);
/* Guarantee that dvmFreeClassInnards can be called on a given
* class multiple times by clearing things out as we free them.
@@ -1951,11 +1959,9 @@
} while (0)
/* arrays just point at Object's vtable; don't free vtable in this case.
- * dvmIsArrayClass() checks clazz->descriptor, so we have to do this check
- * before freeing the name.
*/
clazz->vtableCount = -1;
- if (dvmIsArrayClass(clazz)) {
+ if (clazz->vtable == gDvm.classJavaLangObject->vtable) {
clazz->vtable = NULL;
} else {
NULL_AND_LINEAR_FREE(clazz->vtable);
@@ -2003,7 +2009,8 @@
NULL_AND_LINEAR_FREE(clazz->ifviPool);
clazz->sfieldCount = -1;
- NULL_AND_FREE(clazz->sfields);
+ /* The sfields are attached to the ClassObject, and will be freed
+ * with it. */
clazz->ifieldCount = -1;
NULL_AND_LINEAR_FREE(clazz->ifields);
@@ -2186,9 +2193,7 @@
static int computeJniArgInfo(const DexProto* proto)
{
const char* sig = dexProtoGetShorty(proto);
- int returnType, padFlags, jniArgInfo;
- char sigByte;
- int stackOffset, padMask;
+ int returnType, jniArgInfo;
u4 hints;
/* The first shorty character is the return type. */
@@ -2367,10 +2372,10 @@
"queueNext", "Ljava/lang/ref/Reference;");
assert(gDvm.offJavaLangRefReference_queueNext >= 0);
- gDvm.offJavaLangRefReference_vmData =
+ gDvm.offJavaLangRefReference_pendingNext =
dvmFindFieldOffset(gDvm.classJavaLangRefReference,
- "vmData", "I");
- assert(gDvm.offJavaLangRefReference_vmData >= 0);
+ "pendingNext", "Ljava/lang/ref/Reference;");
+ assert(gDvm.offJavaLangRefReference_pendingNext >= 0);
/* enqueueInternal() is private and thus a direct method. */
meth = dvmFindDirectMethodByDescriptor(clazz, "enqueueInternal", "()Z");
@@ -2432,81 +2437,155 @@
* This converts symbolic references into pointers. It's independent of
* the source file format.
*
- * If "classesResolved" is false, we assume that superclassIdx and
- * interfaces[] are holding class reference indices rather than pointers.
- * The class references will be resolved during link. (This is done when
- * loading from DEX to avoid having to create additional storage to pass
- * the indices around.)
+ * If clazz->status is CLASS_IDX, then clazz->super and interfaces[] are
+ * holding class reference indices rather than pointers. The class
+ * references will be resolved during link. (This is done when
+ * loading from DEX to avoid having to create additional storage to
+ * pass the indices around.)
*
* Returns "false" with an exception pending on failure.
*/
-bool dvmLinkClass(ClassObject* clazz, bool classesResolved)
+bool dvmLinkClass(ClassObject* clazz)
{
u4 superclassIdx = 0;
+ u4 *interfaceIdxArray = NULL;
bool okay = false;
- bool resolve_okay;
- int numInterfacesResolved = 0;
int i;
+ assert(clazz != NULL);
+ assert(clazz->descriptor != NULL);
+ assert(clazz->status == CLASS_IDX || clazz->status == CLASS_LOADED);
if (gDvm.verboseClass)
LOGV("CLASS: linking '%s'...\n", clazz->descriptor);
- /* "Resolve" the class.
- *
- * At this point, clazz's reference fields contain Dex
- * file indices instead of direct object references.
- * We need to translate those indices into real references,
- * while making sure that the GC doesn't sweep any of
- * the referenced objects.
- *
- * The GC will avoid scanning this object as long as
- * clazz->obj.clazz is gDvm.unlinkedJavaLangClass.
- * Once clazz is ready, we'll replace clazz->obj.clazz
- * with gDvm.classJavaLangClass to let the GC know
- * to look at it.
- */
- assert(clazz->obj.clazz == gDvm.unlinkedJavaLangClass);
-
- /* It's important that we take care of java.lang.Class
- * first. If we were to do this after looking up the
- * superclass (below), Class wouldn't be ready when
- * java.lang.Object needed it.
- *
- * Note that we don't set clazz->obj.clazz yet.
- */
- if (gDvm.classJavaLangClass == NULL) {
- if (clazz->classLoader == NULL &&
- strcmp(clazz->descriptor, "Ljava/lang/Class;") == 0)
- {
- gDvm.classJavaLangClass = clazz;
- } else {
- gDvm.classJavaLangClass =
- dvmFindSystemClassNoInit("Ljava/lang/Class;");
- if (gDvm.classJavaLangClass == NULL) {
- /* should have thrown one */
- assert(dvmCheckException(dvmThreadSelf()));
- goto bail;
- }
+ assert(gDvm.classJavaLangClass != NULL);
+ assert(clazz->obj.clazz == gDvm.classJavaLangClass);
+ if (clazz->classLoader == NULL &&
+ (strcmp(clazz->descriptor, "Ljava/lang/Class;") == 0))
+ {
+ if (gDvm.classJavaLangClass->ifieldCount > CLASS_FIELD_SLOTS) {
+ LOGE("java.lang.Class has %d instance fields (expected at most %d)",
+ gDvm.classJavaLangClass->ifieldCount, CLASS_FIELD_SLOTS);
+ dvmAbort();
+ }
+ if (gDvm.classJavaLangClass->sfieldCount != CLASS_SFIELD_SLOTS) {
+ LOGE("java.lang.Class has %d static fields (expected %d)",
+ gDvm.classJavaLangClass->sfieldCount, CLASS_SFIELD_SLOTS);
+ dvmAbort();
}
}
- assert(gDvm.classJavaLangClass != NULL);
-
- /*
- * Resolve all Dex indices so we can hand the ClassObject
- * over to the GC. If we fail at any point, we need to remove
- * any tracked references to avoid leaking memory.
+ /* "Resolve" the class.
+ *
+ * At this point, clazz's reference fields may contain Dex file
+ * indices instead of direct object references. Proxy objects are
+ * an exception, and may be the only exception. We need to
+ * translate those indices into real references, and let the GC
+ * look inside this ClassObject.
*/
+ if (clazz->status == CLASS_IDX) {
+ if (clazz->interfaceCount > 0) {
+ /* Copy u4 DEX idx values out of the ClassObject* array
+ * where we stashed them.
+ */
+ assert(sizeof(*interfaceIdxArray) == sizeof(*clazz->interfaces));
+ size_t len = clazz->interfaceCount * sizeof(*interfaceIdxArray);
+ interfaceIdxArray = malloc(len);
+ if (interfaceIdxArray == NULL) {
+ LOGW("Unable to allocate memory to link %s", clazz->descriptor);
+ goto bail;
+ }
+ memcpy(interfaceIdxArray, clazz->interfaces, len);
- /*
- * All classes have a direct superclass, except for java/lang/Object.
- */
- if (!classesResolved) {
- superclassIdx = (u4) clazz->super; /* unpack temp store */
+ dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
+ memset(clazz->interfaces, 0, len);
+ dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+ }
+
+ assert(sizeof(superclassIdx) == sizeof(clazz->super));
+ superclassIdx = (u4) clazz->super;
clazz->super = NULL;
- }
- if (strcmp(clazz->descriptor, "Ljava/lang/Object;") == 0) {
- assert(!classesResolved);
+ /* After this line, clazz will be fair game for the GC. The
+ * superclass and interfaces are all NULL.
+ */
+ clazz->status = CLASS_LOADED;
+
if (superclassIdx != kDexNoIndex) {
+ ClassObject* super = dvmResolveClass(clazz, superclassIdx, false);
+ if (super == NULL) {
+ assert(dvmCheckException(dvmThreadSelf()));
+ if (gDvm.optimizing) {
+ /* happens with "external" libs */
+ LOGV("Unable to resolve superclass of %s (%d)\n",
+ clazz->descriptor, superclassIdx);
+ } else {
+ LOGW("Unable to resolve superclass of %s (%d)\n",
+ clazz->descriptor, superclassIdx);
+ }
+ goto bail;
+ }
+ dvmSetFieldObject((Object *)clazz,
+ offsetof(ClassObject, super),
+ (Object *)super);
+ }
+
+ if (clazz->interfaceCount > 0) {
+ /* Resolve the interfaces implemented directly by this class. */
+ assert(interfaceIdxArray != NULL);
+ dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
+ for (i = 0; i < clazz->interfaceCount; i++) {
+ assert(interfaceIdxArray[i] != kDexNoIndex);
+ clazz->interfaces[i] =
+ dvmResolveClass(clazz, interfaceIdxArray[i], false);
+ if (clazz->interfaces[i] == NULL) {
+ const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+
+ assert(dvmCheckException(dvmThreadSelf()));
+ dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+
+ const char* classDescriptor;
+ classDescriptor =
+ dexStringByTypeIdx(pDexFile, interfaceIdxArray[i]);
+ if (gDvm.optimizing) {
+ /* happens with "external" libs */
+ LOGV("Failed resolving %s interface %d '%s'\n",
+ clazz->descriptor, interfaceIdxArray[i],
+ classDescriptor);
+ } else {
+ LOGI("Failed resolving %s interface %d '%s'\n",
+ clazz->descriptor, interfaceIdxArray[i],
+ classDescriptor);
+ }
+ goto bail;
+ }
+
+ /* are we allowed to implement this interface? */
+ if (!dvmCheckClassAccess(clazz, clazz->interfaces[i])) {
+ dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+ LOGW("Interface '%s' is not accessible to '%s'\n",
+ clazz->interfaces[i]->descriptor, clazz->descriptor);
+ dvmThrowException("Ljava/lang/IllegalAccessError;",
+ "interface not accessible");
+ goto bail;
+ }
+ LOGVV("+++ found interface '%s'\n",
+ clazz->interfaces[i]->descriptor);
+ }
+ dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+ }
+ }
+ /*
+ * There are now Class references visible to the GC in super and
+ * interfaces.
+ */
+
+ /*
+ * All classes have a direct superclass, except for
+ * java/lang/Object and primitive classes. Primitive classes are
+ * are created CLASS_INITIALIZED, so won't get here.
+ */
+ assert(clazz->primitiveType == PRIM_NOT);
+ if (strcmp(clazz->descriptor, "Ljava/lang/Object;") == 0) {
+ if (clazz->super != NULL) {
/* TODO: is this invariant true for all java/lang/Objects,
* regardless of the class loader? For now, assume it is.
*/
@@ -2520,25 +2599,10 @@
*/
CLEAR_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
} else {
- if (!classesResolved) {
- if (superclassIdx == kDexNoIndex) {
- dvmThrowException("Ljava/lang/LinkageError;",
- "no superclass defined");
- goto bail;
- }
- clazz->super = dvmResolveClass(clazz, superclassIdx, false);
- if (clazz->super == NULL) {
- assert(dvmCheckException(dvmThreadSelf()));
- if (gDvm.optimizing) {
- /* happens with "external" libs */
- LOGV("Unable to resolve superclass of %s (%d)\n",
- clazz->descriptor, superclassIdx);
- } else {
- LOGW("Unable to resolve superclass of %s (%d)\n",
- clazz->descriptor, superclassIdx);
- }
- goto bail;
- }
+ if (clazz->super == NULL) {
+ dvmThrowException("Ljava/lang/LinkageError;",
+ "no superclass defined");
+ goto bail;
}
/* verify */
if (dvmIsFinalClass(clazz->super)) {
@@ -2561,11 +2625,6 @@
goto bail;
}
- /* Don't let the GC reclaim the superclass.
- * TODO: shouldn't be needed; remove when things stabilize
- */
- dvmAddTrackedAlloc((Object *)clazz->super, NULL);
-
/* Inherit finalizability from the superclass. If this
* class also overrides finalize(), its CLASS_ISFINALIZABLE
* bit will already be set.
@@ -2633,100 +2692,6 @@
}
}
- if (!classesResolved && clazz->interfaceCount > 0) {
- /*
- * Resolve the interfaces implemented directly by this class. We
- * stuffed the class index into the interface pointer slot.
- */
- dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
- for (i = 0; i < clazz->interfaceCount; i++) {
- u4 interfaceIdx;
-
- interfaceIdx = (u4) clazz->interfaces[i]; /* unpack temp store */
- assert(interfaceIdx != kDexNoIndex);
-
- clazz->interfaces[i] = dvmResolveClass(clazz, interfaceIdx, false);
- if (clazz->interfaces[i] == NULL) {
- const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
-
- assert(dvmCheckException(dvmThreadSelf()));
- dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
-
- const char* classDescriptor;
- classDescriptor = dexStringByTypeIdx(pDexFile, interfaceIdx);
- if (gDvm.optimizing) {
- /* happens with "external" libs */
- LOGV("Failed resolving %s interface %d '%s'\n",
- clazz->descriptor, interfaceIdx, classDescriptor);
- } else {
- LOGI("Failed resolving %s interface %d '%s'\n",
- clazz->descriptor, interfaceIdx, classDescriptor);
- }
- goto bail_during_resolve;
- }
-
- /* are we allowed to implement this interface? */
- if (!dvmCheckClassAccess(clazz, clazz->interfaces[i])) {
- dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
- LOGW("Interface '%s' is not accessible to '%s'\n",
- clazz->interfaces[i]->descriptor, clazz->descriptor);
- dvmThrowException("Ljava/lang/IllegalAccessError;",
- "interface not accessible");
- goto bail_during_resolve;
- }
-
- /* Don't let the GC reclaim the interface class.
- * TODO: shouldn't be needed; remove when things stabilize
- */
- dvmAddTrackedAlloc((Object *)clazz->interfaces[i], NULL);
- numInterfacesResolved++;
-
- LOGVV("+++ found interface '%s'\n",
- clazz->interfaces[i]->descriptor);
- }
- dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
- }
-
- /*
- * The ClassObject is now in a GC-able state. We let the GC
- * realize this by punching in the real class type, which is
- * always java.lang.Class.
- *
- * After this line, clazz will be fair game for the GC.
- * Every field that the GC will look at must now be valid:
- * - clazz->super
- * - class->classLoader
- * - clazz->sfields
- * - clazz->interfaces
- */
- clazz->obj.clazz = gDvm.classJavaLangClass;
-
- if (false) {
-bail_during_resolve:
- resolve_okay = false;
- } else {
- resolve_okay = true;
- }
-
- /*
- * Now that the GC can scan the ClassObject, we can let
- * go of the explicit references we were holding onto.
- *
- * Either that or we failed, in which case we need to
- * release the references so we don't leak memory.
- */
- if (clazz->super != NULL) {
- dvmReleaseTrackedAlloc((Object *)clazz->super, NULL);
- }
- for (i = 0; i < numInterfacesResolved; i++) {
- dvmReleaseTrackedAlloc((Object *)clazz->interfaces[i], NULL);
- }
-
- if (!resolve_okay) {
- //LOGW("resolve_okay is false\n");
- goto bail;
- }
-
/*
* Populate vtable.
*/
@@ -2788,7 +2753,6 @@
if (gDvm.offJavaLangClass_pd <= 0) {
LOGE("ERROR: unable to find 'pd' field in Class\n");
dvmAbort(); /* we're not going to get much farther */
- //goto bail;
}
}
}
@@ -2833,6 +2797,9 @@
dvmThrowException("Ljava/lang/VirtualMachineError;", NULL);
}
}
+ if (interfaceIdxArray != NULL) {
+ free(interfaceIdxArray);
+ }
return okay;
}
@@ -3865,7 +3832,7 @@
bool parsed = dvmEncodedArrayIteratorGetNext(&iterator, &value);
StaticField* sfield = &clazz->sfields[i];
const char* descriptor = sfield->field.signature;
- bool needRelease = false;
+ bool isObj = false;
if (! parsed) {
/*
@@ -3899,13 +3866,13 @@
case kDexAnnotationString: {
parsed =
(strcmp(descriptor, "Ljava/lang/String;") == 0);
- needRelease = true;
+ isObj = true;
break;
}
case kDexAnnotationType: {
parsed =
(strcmp(descriptor, "Ljava/lang/Class;") == 0);
- needRelease = true;
+ isObj = true;
break;
}
default: {
@@ -3923,13 +3890,18 @@
if (parsed) {
/*
- * All's well, so store the value. Note: This always
- * stores the full width of a JValue, even though most of
- * the time only the first word is needed.
+ * All's well, so store the value.
*/
- sfield->value = value.value;
- if (needRelease) {
+ if (isObj) {
+ dvmSetStaticFieldObject(sfield, value.value.l);
dvmReleaseTrackedAlloc(value.value.l, self);
+ } else {
+ /*
+ * Note: This always stores the full width of a
+ * JValue, even though most of the time only the first
+ * word is needed.
+ */
+ sfield->value = value.value;
}
} else {
/*
@@ -4207,6 +4179,11 @@
*
* We will often be called recursively, e.g. when the <clinit> code resolves
* one of its fields, the field resolution will try to initialize the class.
+ * In that case we will return "true" even though the class isn't actually
+ * ready to go. The ambiguity can be resolved with dvmIsClassInitializing().
+ * (TODO: consider having this return an enum to avoid the extra call --
+ * return -1 on failure, 0 on success, 1 on still-initializing. Looks like
+ * dvmIsClassInitializing() is always paired with *Initialized())
*
* This can get very interesting if a class has a static field initialized
* to a new instance of itself. <clinit> will end up calling <init> on
@@ -4310,11 +4287,13 @@
}
clazz->status = CLASS_VERIFYING;
- if (!dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
+ if (!dvmVerifyClass(clazz)) {
verify_failed:
dvmThrowExceptionWithClassMessage("Ljava/lang/VerifyError;",
clazz->descriptor);
- clazz->verifyErrorClass = dvmGetException(self)->clazz;
+ dvmSetFieldObject((Object*) clazz,
+ offsetof(ClassObject, verifyErrorClass),
+ (Object*) dvmGetException(self)->clazz);
clazz->status = CLASS_ERROR;
goto bail_unlock;
}
@@ -4323,8 +4302,20 @@
}
noverify:
+ /*
+ * We need to ensure that certain instructions, notably accesses to
+ * volatile fields, are replaced before any code is executed. This
+ * must happen even if DEX optimizations are disabled.
+ */
+ if (!IS_CLASS_FLAG_SET(clazz, CLASS_ISOPTIMIZED)) {
+ LOGV("+++ late optimize on %s (pv=%d)\n",
+ clazz->descriptor, IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED));
+ dvmOptimizeClass(clazz, true);
+ SET_CLASS_FLAG(clazz, CLASS_ISOPTIMIZED);
+ }
+
#ifdef WITH_DEBUGGER
- /* update instruction stream now that the verifier is done */
+ /* update instruction stream now that verification + optimization is done */
dvmFlushBreakpoints(clazz);
#endif
@@ -4401,10 +4392,12 @@
return false;
}
+#ifdef WITH_PROFILER
u8 startWhen = 0;
if (gDvm.allocProf.enabled) {
startWhen = dvmGetRelativeTimeNsec();
}
+#endif
/*
* We're ready to go, and have exclusive access to the class.
@@ -4485,7 +4478,7 @@
* need to throw an ExceptionInInitializerError, but we want to
* tuck the original exception into the "cause" field.
*/
- LOGW("Exception %s thrown during %s.<clinit>\n",
+ LOGW("Exception %s thrown while initializing %s\n",
(dvmGetException(self)->clazz)->descriptor, clazz->descriptor);
throwClinitError();
//LOGW("+++ replaced\n");
@@ -4498,6 +4491,7 @@
clazz->status = CLASS_INITIALIZED;
LOGVV("Initialized class: %s\n", clazz->descriptor);
+#ifdef WITH_PROFILER
/*
* Update alloc counters. TODO: guard with mutex.
*/
@@ -4508,6 +4502,7 @@
gDvm.allocProf.classInitCount++;
self->allocProf.classInitCount++;
}
+#endif
}
bail_notify:
@@ -4532,19 +4527,47 @@
/*
* Replace method->nativeFunc and method->insns with new values. This is
- * performed on resolution of a native method.
+ * commonly performed after successful resolution of a native method.
+ *
+ * There are three basic states:
+ * (1) (initial) nativeFunc = dvmResolveNativeMethod, insns = NULL
+ * (2) (internal native) nativeFunc = <impl>, insns = NULL
+ * (3) (JNI) nativeFunc = JNI call bridge, insns = <impl>
+ *
+ * nativeFunc must never be NULL for a native method.
+ *
+ * The most common transitions are (1)->(2) and (1)->(3). The former is
+ * atomic, since only one field is updated; the latter is not, but since
+ * dvmResolveNativeMethod ignores the "insns" field we just need to make
+ * sure the update happens in the correct order.
+ *
+ * A transition from (2)->(1) would work fine, but (3)->(1) will not,
+ * because both fields change. If we did this while a thread was executing
+ * in the call bridge, we could null out the "insns" field right before
+ * the bridge tried to call through it. So, once "insns" is set, we do
+ * not allow it to be cleared. A NULL value for the "insns" argument is
+ * treated as "do not change existing value".
*/
-void dvmSetNativeFunc(const Method* method, DalvikBridgeFunc func,
+void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func,
const u2* insns)
{
ClassObject* clazz = method->clazz;
+ assert(func != NULL);
+
/* just open up both; easier that way */
dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
dvmLinearReadWrite(clazz->classLoader, clazz->directMethods);
- ((Method*)method)->nativeFunc = func;
- ((Method*)method)->insns = insns;
+ if (insns != NULL) {
+ /* update both, ensuring that "insns" is observed first */
+ method->insns = insns;
+ android_atomic_release_store((int32_t) func,
+ (void*) &method->nativeFunc);
+ } else {
+ /* only update nativeFunc */
+ method->nativeFunc = func;
+ }
dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
dvmLinearReadOnly(clazz->classLoader, clazz->directMethods);
diff --git a/vm/oo/Class.h b/vm/oo/Class.h
index 59e0da4..e27ef79 100644
--- a/vm/oo/Class.h
+++ b/vm/oo/Class.h
@@ -71,7 +71,7 @@
/*
* Find the class with the given descriptor. Load it if it hasn't already
* been.
- *
+ *
* "loader" is the initiating class loader.
*/
ClassObject* dvmFindClass(const char* descriptor, Object* loader);
@@ -108,7 +108,7 @@
* variations, this is only called explicitly for synthetic class
* generation (e.g. reflect.Proxy).
*/
-bool dvmLinkClass(ClassObject* clazz, bool classesResolved);
+bool dvmLinkClass(ClassObject* clazz);
/*
* Determine if a class has been initialized.
@@ -139,10 +139,10 @@
bool dvmLoaderInInitiatingList(const ClassObject* clazz, const Object* loader);
/*
- * Update method's "nativeFunc" and "insns" after native method resolution.
+ * Update method's "nativeFunc" and "insns". If "insns" is NULL, the
+ * current method->insns value is not changed.
*/
-void dvmSetNativeFunc(const Method* method, DalvikBridgeFunc func,
- const u2* insns);
+void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func, const u2* insns);
/*
* Set the method's "registerMap" field.
@@ -213,7 +213,7 @@
const Method* method2)
{
return dexProtoCompare(&method1->prototype, &method2->prototype);
-}
+}
/*
* Compare the two method prototypes, considering only the parameters
@@ -224,7 +224,7 @@
const Method* method2)
{
return dexProtoCompareParameters(&method1->prototype, &method2->prototype);
-}
+}
/*
* Compare the two method names and prototypes, a la strcmp(). The
@@ -273,4 +273,9 @@
int dvmCompareNameDescriptorAndMethod(const char* name,
const char* descriptor, const Method* method);
+/*
+ * Returns the size of the given class object in bytes.
+ */
+size_t dvmClassObjectSize(const ClassObject *clazz);
+
#endif /*_DALVIK_OO_CLASS*/
diff --git a/vm/oo/Object.c b/vm/oo/Object.c
index eff0983..3fa86e3 100644
--- a/vm/oo/Object.c
+++ b/vm/oo/Object.c
@@ -85,7 +85,7 @@
StaticField* dvmFindStaticField(const ClassObject* clazz,
const char* fieldName, const char* signature)
{
- StaticField* pField;
+ const StaticField* pField;
int i;
assert(clazz != NULL);
@@ -95,12 +95,12 @@
* fields, the VM allows you to have two fields with the same name so
* long as they have different types.
*/
- pField = clazz->sfields;
+ pField = &clazz->sfields[0];
for (i = 0; i < clazz->sfieldCount; i++, pField++) {
if (strcmp(fieldName, pField->field.name) == 0 &&
strcmp(signature, pField->field.signature) == 0)
{
- return pField;
+ return (StaticField*) pField;
}
}
@@ -216,7 +216,7 @@
}
proto = &method->prototype;
-
+
if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) {
return 1;
}
@@ -256,7 +256,7 @@
* and also find a pointer to the return type.
*/
static inline size_t countArgsAndFindReturnType(const char* descriptor,
- const char** pReturnType)
+ const char** pReturnType)
{
size_t count = 0;
bool bogus = false;
@@ -264,7 +264,7 @@
assert(*descriptor == '(');
descriptor++;
-
+
while (!done) {
switch (*descriptor) {
case 'B': case 'C': case 'D': case 'F':
@@ -297,7 +297,7 @@
break;
}
case ')': {
- /*
+ /*
* Note: The loop will exit after incrementing descriptor
* one more time, so it then points at the return type.
*/
@@ -336,7 +336,7 @@
/* Skip the '('. */
descriptor++;
-
+
for (i = 0; i < argCount; i++) {
argTypes[i] = buffer;
@@ -353,9 +353,9 @@
*(buffer++) = c;
} while (c != ';');
}
-
+
*(buffer++) = '\0';
- }
+ }
}
/*
@@ -395,7 +395,7 @@
methods = clazz->directMethods;
methodCount = clazz->directMethodCount;
}
-
+
for (i = 0; i < methodCount; i++) {
Method* method = &methods[i];
if (compareMethodHelper(method, name, returnType, argCount,
@@ -424,7 +424,7 @@
*/
static Method* findMethodInListByProto(const ClassObject* clazz,
MethodType wantedType, bool isHier, const char* name, const DexProto* proto)
-{
+{
while (clazz != NULL) {
int i;
@@ -739,4 +739,3 @@
clazz = clazz->super;
}
}
-
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index df167d5..7428cef 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -21,6 +21,8 @@
#ifndef _DALVIK_OO_OBJECT
#define _DALVIK_OO_OBJECT
+#include <Atomic.h>
+
#include <stddef.h>
/* fwd decl */
@@ -137,8 +139,8 @@
CLASS_ERROR = -1,
CLASS_NOTREADY = 0,
- CLASS_LOADED = 1,
- CLASS_PREPARED = 2, /* part of linking */
+ CLASS_IDX = 1, /* loaded, DEX idx in super or ifaces */
+ CLASS_LOADED = 2, /* DEX idx values resolved */
CLASS_RESOLVED = 3, /* part of linking */
CLASS_VERIFYING = 4, /* in the process of being verified */
CLASS_VERIFIED = 5, /* logically part of linking; done pre-init */
@@ -146,7 +148,6 @@
CLASS_INITIALIZED = 7, /* ready to go */
} ClassStatus;
-
/*
* Primitive type identifiers. We use these values as indexes into an
* array of synthesized classes, so these start at zero and count up.
@@ -254,8 +255,12 @@
* Properly initialize an Object.
* void DVM_OBJECT_INIT(Object *obj, ClassObject *clazz_)
*/
-#define DVM_OBJECT_INIT(obj, clazz_) \
- do { (obj)->clazz = (clazz_); DVM_LOCK_INIT(&(obj)->lock); } while (0)
+#define DVM_OBJECT_INIT(obj, clazz_) \
+ do { \
+ dvmSetFieldObject((Object *)obj, offsetof(Object, clazz), \
+ (Object *)clazz_); \
+ DVM_LOCK_INIT(&(obj)->lock); \
+ } while (0)
/*
* Data objects have an Object header followed by their instance data.
@@ -320,6 +325,45 @@
};
/*
+ * Generic field header. We pass this around when we want a generic Field
+ * pointer (e.g. for reflection stuff). Testing the accessFlags for
+ * ACC_STATIC allows a proper up-cast.
+ */
+struct Field {
+ ClassObject* clazz; /* class in which the field is declared */
+ const char* name;
+ const char* signature; /* e.g. "I", "[C", "Landroid/os/Debug;" */
+ u4 accessFlags;
+#ifdef PROFILE_FIELD_ACCESS
+ u4 gets;
+ u4 puts;
+#endif
+};
+
+/*
+ * Static field.
+ */
+struct StaticField {
+ Field field; /* MUST be first item */
+ JValue value; /* initially set from DEX for primitives */
+};
+
+/*
+ * Instance field.
+ */
+struct InstField {
+ Field field; /* MUST be first item */
+
+ /*
+ * This field indicates the byte offset from the beginning of the
+ * (Object *) to the actual instance data; e.g., byteOffset==0 is
+ * the same as the object pointer (bug!), and byteOffset==4 is 4
+ * bytes farther.
+ */
+ int byteOffset;
+};
+
+/*
* This defines the amount of space we leave for field slots in the
* java.lang.Class definition. If we alter the class to have more than
* this many fields, the VM will abort at startup.
@@ -443,10 +487,6 @@
int ifviPoolCount;
int* ifviPool;
- /* static fields */
- int sfieldCount;
- StaticField* sfields;
-
/* instance fields
*
* These describe the layout of the contents of a DataObject-compatible
@@ -467,6 +507,10 @@
/* source file name, if known */
const char* sourceFile;
+
+ /* static fields */
+ int sfieldCount;
+ StaticField sfields[]; /* MUST be last item */
};
/*
@@ -555,45 +599,6 @@
#endif
};
-/*
- * Generic field header. We pass this around when we want a generic Field
- * pointer (e.g. for reflection stuff). Testing the accessFlags for
- * ACC_STATIC allows a proper up-cast.
- */
-struct Field {
- ClassObject* clazz; /* class in which the field is declared */
- const char* name;
- const char* signature; /* e.g. "I", "[C", "Landroid/os/Debug;" */
- u4 accessFlags;
-#ifdef PROFILE_FIELD_ACCESS
- u4 gets;
- u4 puts;
-#endif
-};
-
-/*
- * Static field.
- */
-struct StaticField {
- Field field; /* MUST be first item */
- JValue value; /* initially set from DEX for primitives */
-};
-
-/*
- * Instance field.
- */
-struct InstField {
- Field field; /* MUST be first item */
-
- /*
- * This field indicates the byte offset from the beginning of the
- * (Object *) to the actual instance data; e.g., byteOffset==0 is
- * the same as the object pointer (bug!), and byteOffset==4 is 4
- * bytes farther.
- */
- int byteOffset;
-};
-
/*
* Find a method within a class. The superclass is not searched.
@@ -672,140 +677,6 @@
}
/*
- * Field access functions. Pass in the word offset from Field->byteOffset.
- *
- * We guarantee that long/double field data is 64-bit aligned, so it's safe
- * to access them with ldrd/strd on ARM.
- *
- * The VM treats all fields as 32 or 64 bits, so the field set functions
- * write 32 bits even if the underlying type is smaller.
- */
-#define BYTE_OFFSET(_ptr, _offset) ((void*) (((u1*)(_ptr)) + (_offset)))
-
-INLINE JValue* dvmFieldPtr(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset));
-}
-
-INLINE bool dvmGetFieldBoolean(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->z;
-}
-INLINE s1 dvmGetFieldByte(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->b;
-}
-INLINE s2 dvmGetFieldShort(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->s;
-}
-INLINE u2 dvmGetFieldChar(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->c;
-}
-INLINE s4 dvmGetFieldInt(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->i;
-}
-INLINE s8 dvmGetFieldLong(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->j;
-}
-INLINE float dvmGetFieldFloat(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->f;
-}
-INLINE double dvmGetFieldDouble(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->d;
-}
-INLINE Object* dvmGetFieldObject(const Object* obj, int offset) {
- return ((JValue*)BYTE_OFFSET(obj, offset))->l;
-}
-
-INLINE void dvmSetFieldBoolean(Object* obj, int offset, bool val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
-}
-INLINE void dvmSetFieldByte(Object* obj, int offset, s1 val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
-}
-INLINE void dvmSetFieldShort(Object* obj, int offset, s2 val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
-}
-INLINE void dvmSetFieldChar(Object* obj, int offset, u2 val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
-}
-INLINE void dvmSetFieldInt(Object* obj, int offset, s4 val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
-}
-INLINE void dvmSetFieldLong(Object* obj, int offset, s8 val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->j = val;
-}
-INLINE void dvmSetFieldFloat(Object* obj, int offset, float val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->f = val;
-}
-INLINE void dvmSetFieldDouble(Object* obj, int offset, double val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->d = val;
-}
-INLINE void dvmSetFieldObject(Object* obj, int offset, Object* val) {
- ((JValue*)BYTE_OFFSET(obj, offset))->l = val;
-}
-
-/*
- * Static field access functions.
- */
-INLINE JValue* dvmStaticFieldPtr(const StaticField* sfield) {
- return (JValue*)&sfield->value;
-}
-
-INLINE bool dvmGetStaticFieldBoolean(const StaticField* sfield) {
- return sfield->value.z;
-}
-INLINE s1 dvmGetStaticFieldByte(const StaticField* sfield) {
- return sfield->value.b;
-}
-INLINE s2 dvmGetStaticFieldShort(const StaticField* sfield) {
- return sfield->value.s;
-}
-INLINE u2 dvmGetStaticFieldChar(const StaticField* sfield) {
- return sfield->value.c;
-}
-INLINE s4 dvmGetStaticFieldInt(const StaticField* sfield) {
- return sfield->value.i;
-}
-INLINE s8 dvmGetStaticFieldLong(const StaticField* sfield) {
- return sfield->value.j;
-}
-INLINE float dvmGetStaticFieldFloat(const StaticField* sfield) {
- return sfield->value.f;
-}
-INLINE double dvmGetStaticFieldDouble(const StaticField* sfield) {
- return sfield->value.d;
-}
-INLINE Object* dvmGetStaticFieldObject(const StaticField* sfield) {
- return sfield->value.l;
-}
-
-INLINE void dvmSetStaticFieldBoolean(StaticField* sfield, bool val) {
- sfield->value.i = val;
-}
-INLINE void dvmSetStaticFieldByte(StaticField* sfield, s1 val) {
- sfield->value.i = val;
-}
-INLINE void dvmSetStaticFieldShort(StaticField* sfield, s2 val) {
- sfield->value.i = val;
-}
-INLINE void dvmSetStaticFieldChar(StaticField* sfield, u2 val) {
- sfield->value.i = val;
-}
-INLINE void dvmSetStaticFieldInt(StaticField* sfield, s4 val) {
- sfield->value.i = val;
-}
-INLINE void dvmSetStaticFieldLong(StaticField* sfield, s8 val) {
- sfield->value.j = val;
-}
-INLINE void dvmSetStaticFieldFloat(StaticField* sfield, float val) {
- sfield->value.f = val;
-}
-INLINE void dvmSetStaticFieldDouble(StaticField* sfield, double val) {
- sfield->value.d = val;
-}
-INLINE void dvmSetStaticFieldObject(StaticField* sfield, Object* val) {
- sfield->value.l = val;
-}
-
-/*
* Helpers.
*/
INLINE bool dvmIsPublicMethod(const Method* method) {
@@ -859,6 +730,9 @@
INLINE bool dvmIsFinalField(const Field* field) {
return (field->accessFlags & ACC_FINAL) != 0;
}
+INLINE bool dvmIsVolatileField(const Field* field) {
+ return (field->accessFlags & ACC_VOLATILE) != 0;
+}
INLINE bool dvmIsInterfaceClass(const ClassObject* clazz) {
return (clazz->accessFlags & ACC_INTERFACE) != 0;
@@ -872,8 +746,8 @@
INLINE bool dvmIsAbstractClass(const ClassObject* clazz) {
return (clazz->accessFlags & ACC_ABSTRACT) != 0;
}
-INLINE bool dvmIsAnnotationClass(const ClassObject* clazz) {
- return (clazz->accessFlags & ACC_ANNOTATION) != 0;
+INLINE bool dvmIsAnnotationClass(const ClassObject* clazz) {
+ return (clazz->accessFlags & ACC_ANNOTATION) != 0;
}
INLINE bool dvmIsPrimitiveClass(const ClassObject* clazz) {
return clazz->primitiveType != PRIM_NOT;
diff --git a/vm/oo/ObjectInlines.h b/vm/oo/ObjectInlines.h
new file mode 100644
index 0000000..d26183b
--- /dev/null
+++ b/vm/oo/ObjectInlines.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Helper functions to access data fields in Objects.
+ */
+#ifndef _DALVIK_OO_OBJECTINLINES
+#define _DALVIK_OO_OBJECTINLINES
+
+/*
+ * Store a single value in the array, and if the value isn't null,
+ * note in the write barrier.
+ */
+INLINE void dvmSetObjectArrayElement(const ArrayObject* obj, int index,
+ Object* val) {
+ ((Object **)(obj)->contents)[index] = val;
+ if (val != NULL) {
+ dvmWriteBarrierArray(obj, index, index + 1);
+ }
+}
+
+
+/*
+ * Field access functions. Pass in the word offset from Field->byteOffset.
+ *
+ * We guarantee that long/double field data is 64-bit aligned, so it's safe
+ * to access them with ldrd/strd on ARM.
+ *
+ * The VM treats all fields as 32 or 64 bits, so the field set functions
+ * write 32 bits even if the underlying type is smaller.
+ *
+ * Setting Object types to non-null values includes a call to the
+ * write barrier.
+ */
+#define BYTE_OFFSET(_ptr, _offset) ((void*) (((u1*)(_ptr)) + (_offset)))
+
+INLINE JValue* dvmFieldPtr(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset));
+}
+
+INLINE bool dvmGetFieldBoolean(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->z;
+}
+INLINE s1 dvmGetFieldByte(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->b;
+}
+INLINE s2 dvmGetFieldShort(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->s;
+}
+INLINE u2 dvmGetFieldChar(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->c;
+}
+INLINE s4 dvmGetFieldInt(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->i;
+}
+INLINE s8 dvmGetFieldLong(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->j;
+}
+INLINE float dvmGetFieldFloat(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->f;
+}
+INLINE double dvmGetFieldDouble(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->d;
+}
+INLINE Object* dvmGetFieldObject(const Object* obj, int offset) {
+ return ((JValue*)BYTE_OFFSET(obj, offset))->l;
+}
+INLINE s4 dvmGetFieldIntVolatile(const Object* obj, int offset) {
+ s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+ return android_atomic_acquire_load(ptr);
+}
+INLINE Object* dvmGetFieldObjectVolatile(const Object* obj, int offset) {
+ void** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l;
+ return (Object*) android_atomic_acquire_load((int32_t*)ptr);
+}
+INLINE s8 dvmGetFieldLongVolatile(const Object* obj, int offset) {
+ const s8* addr = BYTE_OFFSET(obj, offset);
+ s8 val = dvmQuasiAtomicRead64(addr);
+ ANDROID_MEMBAR_FULL();
+ return val;
+}
+
+INLINE void dvmSetFieldBoolean(Object* obj, int offset, bool val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldByte(Object* obj, int offset, s1 val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldShort(Object* obj, int offset, s2 val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldChar(Object* obj, int offset, u2 val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldInt(Object* obj, int offset, s4 val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldLong(Object* obj, int offset, s8 val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->j = val;
+}
+INLINE void dvmSetFieldFloat(Object* obj, int offset, float val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->f = val;
+}
+INLINE void dvmSetFieldDouble(Object* obj, int offset, double val) {
+ ((JValue*)BYTE_OFFSET(obj, offset))->d = val;
+}
+INLINE void dvmSetFieldObject(Object* obj, int offset, Object* val) {
+ JValue* lhs = BYTE_OFFSET(obj, offset);
+ lhs->l = val;
+ if (val != NULL) {
+ dvmWriteBarrierField(obj, &lhs->l);
+ }
+}
+INLINE void dvmSetFieldIntVolatile(Object* obj, int offset, s4 val) {
+ s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+ android_atomic_release_store(val, ptr);
+}
+INLINE void dvmSetFieldObjectVolatile(Object* obj, int offset, Object* val) {
+ void** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l;
+ android_atomic_release_store((int32_t)val, (int32_t*)ptr);
+ if (val != NULL) {
+ dvmWriteBarrierField(obj, ptr);
+ }
+}
+INLINE void dvmSetFieldLongVolatile(Object* obj, int offset, s8 val) {
+ s8* addr = BYTE_OFFSET(obj, offset);
+ ANDROID_MEMBAR_FULL();
+ dvmQuasiAtomicSwap64(val, addr);
+}
+
+/*
+ * Static field access functions.
+ */
+INLINE JValue* dvmStaticFieldPtr(const StaticField* sfield) {
+ return (JValue*)&sfield->value;
+}
+
+INLINE bool dvmGetStaticFieldBoolean(const StaticField* sfield) {
+ return sfield->value.z;
+}
+INLINE s1 dvmGetStaticFieldByte(const StaticField* sfield) {
+ return sfield->value.b;
+}
+INLINE s2 dvmGetStaticFieldShort(const StaticField* sfield) {
+ return sfield->value.s;
+}
+INLINE u2 dvmGetStaticFieldChar(const StaticField* sfield) {
+ return sfield->value.c;
+}
+INLINE s4 dvmGetStaticFieldInt(const StaticField* sfield) {
+ return sfield->value.i;
+}
+INLINE s8 dvmGetStaticFieldLong(const StaticField* sfield) {
+ return sfield->value.j;
+}
+INLINE float dvmGetStaticFieldFloat(const StaticField* sfield) {
+ return sfield->value.f;
+}
+INLINE double dvmGetStaticFieldDouble(const StaticField* sfield) {
+ return sfield->value.d;
+}
+INLINE Object* dvmGetStaticFieldObject(const StaticField* sfield) {
+ return sfield->value.l;
+}
+INLINE s4 dvmGetStaticFieldIntVolatile(const StaticField* sfield) {
+ const s4* ptr = &(sfield->value.i);
+ return android_atomic_acquire_load((s4*)ptr);
+}
+INLINE Object* dvmGetStaticFieldObjectVolatile(const StaticField* sfield) {
+ void* const* ptr = &(sfield->value.l);
+ return (Object*) android_atomic_acquire_load((int32_t*)ptr);
+}
+INLINE s8 dvmGetStaticFieldLongVolatile(const StaticField* sfield) {
+ const s8* addr = &sfield->value.j;
+ s8 val = dvmQuasiAtomicRead64(addr);
+ ANDROID_MEMBAR_FULL();
+ return val;
+}
+
+INLINE void dvmSetStaticFieldBoolean(StaticField* sfield, bool val) {
+ sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldByte(StaticField* sfield, s1 val) {
+ sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldShort(StaticField* sfield, s2 val) {
+ sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldChar(StaticField* sfield, u2 val) {
+ sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldInt(StaticField* sfield, s4 val) {
+ sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldLong(StaticField* sfield, s8 val) {
+ sfield->value.j = val;
+}
+INLINE void dvmSetStaticFieldFloat(StaticField* sfield, float val) {
+ sfield->value.f = val;
+}
+INLINE void dvmSetStaticFieldDouble(StaticField* sfield, double val) {
+ sfield->value.d = val;
+}
+INLINE void dvmSetStaticFieldObject(StaticField* sfield, Object* val) {
+ sfield->value.l = val;
+ if (val != NULL) {
+ dvmWriteBarrierField((Object *)sfield->field.clazz, &sfield->value.l);
+ }
+}
+INLINE void dvmSetStaticFieldIntVolatile(StaticField* sfield, s4 val) {
+ s4* ptr = &(sfield->value.i);
+ android_atomic_release_store(val, ptr);
+}
+INLINE void dvmSetStaticFieldObjectVolatile(StaticField* sfield, Object* val) {
+ void** ptr = &(sfield->value.l);
+ android_atomic_release_store((int32_t)val, (int32_t*)ptr);
+ if (val != NULL) {
+ dvmWriteBarrierField((Object *)sfield->field.clazz, &sfield->value.l);
+ }
+}
+INLINE void dvmSetStaticFieldLongVolatile(StaticField* sfield, s8 val) {
+ s8* addr = &sfield->value.j;
+ ANDROID_MEMBAR_FULL();
+ dvmQuasiAtomicSwap64(val, addr);
+}
+
+#endif /*_DALVIK_OO_OBJECTINLINES*/
diff --git a/vm/oo/Resolve.c b/vm/oo/Resolve.c
index 68fdd51..c4bda8b 100644
--- a/vm/oo/Resolve.c
+++ b/vm/oo/Resolve.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Resolve classes, methods, fields, and strings.
*
@@ -256,10 +257,21 @@
}
/*
- * The class is initialized, the method has been found. Add a pointer
- * to our data structure so we don't have to jump through the hoops again.
+ * If the class has been initialized, add a pointer to our data structure
+ * so we don't have to jump through the hoops again. If this is a
+ * static method and the defining class is still initializing (i.e. this
+ * thread is executing <clinit>), don't do the store, otherwise other
+ * threads could call the method without waiting for class init to finish.
*/
- dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+ if (methodType == METHOD_STATIC && !dvmIsClassInitialized(resMethod->clazz))
+ {
+ LOGVV("--- not caching resolved method %s.%s (class init=%d/%d)\n",
+ resMethod->clazz->descriptor, resMethod->name,
+ dvmIsClassInitializing(resMethod->clazz),
+ dvmIsClassInitialized(resMethod->clazz));
+ } else {
+ dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+ }
return resMethod;
}
@@ -366,8 +378,11 @@
//assert(dvmIsClassInitialized(resMethod->clazz));
/*
- * The class is initialized, the method has been found. Add a pointer
- * to our data structure so we don't have to jump through the hoops again.
+ * Add a pointer to our data structure so we don't have to jump
+ * through the hoops again.
+ *
+ * As noted above, no need to worry about whether the interface that
+ * defines the method has been or is currently executing <clinit>.
*/
dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
@@ -419,8 +434,14 @@
dvmIsClassInitializing(resField->field.clazz));
/*
- * The class is initialized, the method has been found. Add a pointer
- * to our data structure so we don't have to jump through the hoops again.
+ * The class is initialized (or initializing), the field has been
+ * found. Add a pointer to our data structure so we don't have to
+ * jump through the hoops again.
+ *
+ * Anything that uses the resolved table entry must have an instance
+ * of the class, so any class init activity has already happened (or
+ * been deliberately bypassed when <clinit> created an instance).
+ * So it's always okay to update the table.
*/
dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField);
LOGVV(" field %u is %s.%s\n",
@@ -476,10 +497,20 @@
}
/*
- * The class is initialized, the method has been found. Add a pointer
- * to our data structure so we don't have to jump through the hoops again.
+ * If the class has been initialized, add a pointer to our data structure
+ * so we don't have to jump through the hoops again. If it's still
+ * initializing (i.e. this thread is executing <clinit>), don't do
+ * the store, otherwise other threads could use the field without waiting
+ * for class init to finish.
*/
- dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
+ if (dvmIsClassInitialized(resField->field.clazz)) {
+ dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
+ } else {
+ LOGVV("--- not caching resolved field %s.%s (class init=%d/%d)\n",
+ resField->field.clazz->descriptor, resField->field.name,
+ dvmIsClassInitializing(resField->field.clazz),
+ dvmIsClassInitialized(resField->field.clazz));
+ }
return resField;
}
@@ -507,8 +538,7 @@
* already interned.
*/
utf8 = dexStringAndSizeById(pDvmDex->pDexFile, stringIdx, &utf16Size);
- strObj = dvmCreateStringFromCstrAndLength(utf8, utf16Size,
- ALLOC_DEFAULT);
+ strObj = dvmCreateStringFromCstrAndLength(utf8, utf16Size);
if (strObj == NULL) {
/* ran out of space in GC heap? */
assert(dvmCheckException(dvmThreadSelf()));
diff --git a/vm/oo/TypeCheck.c b/vm/oo/TypeCheck.c
index 1762045..fdd38ea 100644
--- a/vm/oo/TypeCheck.c
+++ b/vm/oo/TypeCheck.c
@@ -246,4 +246,3 @@
INSTANCEOF_CACHE_SIZE, instance, clazz);
#undef ATOMIC_CACHE_CALC
}
-
diff --git a/vm/reflect/Annotation.c b/vm/reflect/Annotation.c
index fb4b83f..a5007ba 100644
--- a/vm/reflect/Annotation.c
+++ b/vm/reflect/Annotation.c
@@ -120,8 +120,8 @@
*/
static u4 readUleb128(const u1** pBuf)
{
- u4 result = 0;
- int shift = 0;
+ u4 result = 0;
+ int shift = 0;
const u1* buf = *pBuf;
u1 val;
@@ -174,7 +174,7 @@
}
/*
- * Return an array of empty arrays of Annotation objects.
+ * Return an array of empty arrays of Annotation objects.
*
* Caller must call dvmReleaseTrackedAlloc().
*/
@@ -183,7 +183,7 @@
Thread* self = dvmThreadSelf();
ArrayObject* arr;
int i;
-
+
arr = dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArrayArray,
numElements, ALLOC_DEFAULT);
if (arr != NULL) {
@@ -295,7 +295,6 @@
Method* resMethod;
const DexMethodId* pMethodId;
const char* name;
- const char* signature;
/* if we've already resolved this method, return it */
resMethod = dvmDexGetResolvedMethod(referrer->pDvmDex, methodIdx);
@@ -545,8 +544,7 @@
return false;
} else {
ArrayObject* newArray;
- Object** pObj;
- u4 size;
+ u4 size, count;
size = readUleb128(&ptr);
LOGVV("--- annotation array, size is %u at %p\n", size, ptr);
@@ -556,18 +554,17 @@
LOGE("annotation element array alloc failed (%d)\n", size);
return false;
}
- pObj = (Object**)newArray->contents;
AnnotationValue avalue;
- while (size--) {
+ for (count = 0; count < size; count++) {
if (!processAnnotationValue(clazz, &ptr, &avalue,
kAllObjects)) {
dvmReleaseTrackedAlloc((Object*)newArray, self);
return false;
}
Object* obj = avalue.value.l;
+ dvmSetObjectArrayElement(newArray, count, obj);
dvmReleaseTrackedAlloc(obj, self);
- *pObj++ = obj;
}
elemObj = (Object*) newArray;
@@ -735,7 +732,7 @@
dvmAllocObject(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember,
ALLOC_DEFAULT);
name = dexStringById(pDexFile, elementNameIdx);
- nameObj = dvmCreateStringFromCstr(name, ALLOC_DEFAULT);
+ nameObj = dvmCreateStringFromCstr(name);
/* find the method in the annotation class, given only the name */
if (name != NULL) {
@@ -804,12 +801,11 @@
const u1** pPtr)
{
Thread* self = dvmThreadSelf();
- const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
Object* newAnno = NULL;
ArrayObject* elementArray = NULL;
const ClassObject* annoClass;
const u1* ptr;
- u4 typeIdx, size;
+ u4 typeIdx, size, count;
ptr = *pPtr;
typeIdx = readUleb128(&ptr);
@@ -838,7 +834,6 @@
* default values get merged in later.
*/
JValue result;
- Object** pElement = NULL;
if (size > 0) {
elementArray = dvmAllocArrayByClass(
@@ -849,20 +844,19 @@
size);
goto bail;
}
- pElement = (Object**) elementArray->contents;
}
/*
* "ptr" points to a byte stream with "size" occurrences of
* annotation_element.
*/
- while (size--) {
+ for (count = 0; count < size; count++) {
Object* newMember = createAnnotationMember(clazz, annoClass, &ptr);
if (newMember == NULL)
goto bail;
/* add it to the array */
- *pElement++ = newMember;
+ dvmSetObjectArrayElement(elementArray, count, newMember);
}
dvmCallMethod(self,
@@ -900,8 +894,8 @@
DexFile* pDexFile = clazz->pDvmDex->pDexFile;
const DexAnnotationItem* pAnnoItem;
ArrayObject* annoArray;
- Object** pContents;
int i, count;
+ u4 dstIndex;
/* we need these later; make sure they're initialized */
if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory))
@@ -916,27 +910,29 @@
count++;
}
- annoArray =dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
- count, ALLOC_DEFAULT);
+ annoArray =
+ dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
+ count, ALLOC_DEFAULT);
if (annoArray == NULL)
return NULL;
- pContents = (Object**) annoArray->contents;
/*
* Generate Annotation objects. We must put them into the array
* immediately (or add them to the tracked ref table).
*/
+ dstIndex = 0;
for (i = 0; i < (int) pAnnoSet->size; i++) {
pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
if (pAnnoItem->visibility != visibility)
continue;
const u1* ptr = pAnnoItem->annotation;
- *pContents = processEncodedAnnotation(clazz, &ptr);
- if (*pContents == NULL) {
+ Object *anno = processEncodedAnnotation(clazz, &ptr);
+ if (anno == NULL) {
dvmReleaseTrackedAlloc((Object*) annoArray, NULL);
return NULL;
}
- pContents++;
+ dvmSetObjectArrayElement(annoArray, dstIndex, anno);
+ ++dstIndex;
}
return annoArray;
@@ -1023,7 +1019,6 @@
*/
static bool skipEncodedAnnotation(const ClassObject* clazz, const u1** pPtr)
{
- const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
const u1* ptr;
u4 size;
@@ -1148,7 +1143,6 @@
int expectedType, const char* debugAnnoName)
{
const u1* ptr;
- Object* obj;
AnnotationValue avalue;
/* find the annotation */
@@ -1894,7 +1888,6 @@
DexFile* pDexFile = clazz->pDvmDex->pDexFile;
const DexAnnotationsDirectoryItem* pAnnoDir;
const DexFieldAnnotationsItem* pFieldList;
- const DexAnnotationSetItem* pAnnoSet = NULL;
pAnnoDir = getAnnoDirectory(pDexFile, clazz);
if (pAnnoDir == NULL)
@@ -1941,8 +1934,6 @@
{
ClassObject* clazz = field->clazz;
ArrayObject* annoArray = NULL;
- DexFile* pDexFile = clazz->pDvmDex->pDexFile;
- const DexAnnotationsDirectoryItem* pAnnoDir;
const DexAnnotationSetItem* pAnnoSet = NULL;
pAnnoSet = findAnnotationSetForField(field);
@@ -1994,7 +1985,6 @@
{
DexFile* pDexFile = clazz->pDvmDex->pDexFile;
ArrayObject* annoArrayArray = NULL;
- ArrayObject** pContents;
u4 idx;
/* allocate an array of Annotation arrays to hold results */
@@ -2005,24 +1995,24 @@
goto bail;
}
- pContents = (ArrayObject**) annoArrayArray->contents;
-
for (idx = 0; idx < count; idx++) {
Thread* self = dvmThreadSelf();
const DexAnnotationSetRefItem* pItem;
const DexAnnotationSetItem* pAnnoSet;
+ Object *annoSet;
pItem = dexGetParameterAnnotationSetRef(pAnnoSetList, idx);
pAnnoSet = dexGetSetRefItemItem(pDexFile, pItem);
- *pContents = processAnnotationSet(clazz, pAnnoSet,
- kDexVisibilityRuntime);
- if (*pContents == NULL) {
+ annoSet = (Object *)processAnnotationSet(clazz,
+ pAnnoSet,
+ kDexVisibilityRuntime);
+ if (annoSet == NULL) {
LOGW("processAnnotationSet failed\n");
annoArrayArray = NULL;
goto bail;
}
- dvmReleaseTrackedAlloc((Object*) *pContents, self);
- pContents++;
+ dvmSetObjectArrayElement(annoArrayArray, idx, annoSet);
+ dvmReleaseTrackedAlloc((Object*) annoSet, self);
}
bail:
@@ -2134,7 +2124,7 @@
/**
* Initializes an encoded array iterator.
- *
+ *
* @param iterator iterator to initialize
* @param encodedArray encoded array to iterate over
* @param clazz class to use when resolving strings and types
@@ -2160,9 +2150,9 @@
* cursor. This returns primitive values in their corresponding union
* slots, and returns everything else (including nulls) as object
* references in the "l" union slot.
- *
+ *
* The caller must call dvmReleaseTrackedAlloc() on any returned reference.
- *
+ *
* @param value pointer to store decoded value into
* @returns true if a value was decoded and the cursor advanced; false if
* the last value had already been decoded or if there was a problem decoding
@@ -2189,4 +2179,3 @@
iterator->elementsLeft--;
return true;
}
-
diff --git a/vm/reflect/Proxy.c b/vm/reflect/Proxy.c
index 31df708..eef658d 100644
--- a/vm/reflect/Proxy.c
+++ b/vm/reflect/Proxy.c
@@ -47,6 +47,7 @@
/* private static fields in the Proxy class */
#define kThrowsField 0
+#define kProxySFieldCount 1
/*
@@ -135,7 +136,7 @@
ArrayObject* throws = NULL;
ClassObject* newClass = NULL;
int i;
-
+
nameStr = dvmCreateCstrFromString(str);
if (nameStr == NULL) {
dvmThrowException("Ljava/lang/IllegalArgumentException;",
@@ -177,17 +178,23 @@
/*
* Allocate storage for the class object and set some basic fields.
*/
- newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
+ newClass = (ClassObject*) dvmMalloc(sizeof(*newClass) +
+ kProxySFieldCount * sizeof(StaticField),
+ ALLOC_DEFAULT);
if (newClass == NULL)
goto bail;
- DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
+ DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
dvmSetClassSerialNumber(newClass);
newClass->descriptorAlloc = dvmNameToDescriptor(nameStr);
newClass->descriptor = newClass->descriptorAlloc;
newClass->accessFlags = ACC_PUBLIC | ACC_FINAL;
- newClass->super = gDvm.classJavaLangReflectProxy;
+ dvmSetFieldObject((Object *)newClass,
+ offsetof(ClassObject, super),
+ (Object *)gDvm.classJavaLangReflectProxy);
newClass->primitiveType = PRIM_NOT;
- newClass->classLoader = loader;
+ dvmSetFieldObject((Object *)newClass,
+ offsetof(ClassObject, classLoader),
+ (Object *)loader);
#if WITH_HPROF && WITH_HPROF_STACK
hprofFillInStackTrace(newClass);
#endif
@@ -228,8 +235,8 @@
* Static field list. We have one private field, for our list of
* exceptions declared for each method.
*/
- newClass->sfieldCount = 1;
- newClass->sfields = (StaticField*) calloc(1, sizeof(StaticField));
+ assert(kProxySFieldCount == 1);
+ newClass->sfieldCount = kProxySFieldCount;
StaticField* sfield = &newClass->sfields[kThrowsField];
sfield->field.clazz = newClass;
sfield->field.name = "throws";
@@ -238,10 +245,12 @@
dvmSetStaticFieldObject(sfield, (Object*)throws);
/*
- * Everything is ready. See if the linker will lap it up.
+ * Everything is ready. This class didn't come out of a DEX file
+ * so we didn't tuck any indexes into the class object. We can
+ * advance to LOADED state immediately.
*/
newClass->status = CLASS_LOADED;
- if (!dvmLinkClass(newClass, true)) {
+ if (!dvmLinkClass(newClass)) {
LOGD("Proxy class link failed\n");
goto bail;
}
@@ -425,7 +434,6 @@
static int copyWithoutDuplicates(Method** allMethods, int allCount,
Method** outMethods, ArrayObject* throwLists)
{
- Method* best;
int outCount = 0;
int i, j;
@@ -793,7 +801,7 @@
meth->name = "<init>";
meth->prototype =
gDvm.methJavaLangReflectProxy_constructorPrototype->prototype;
- meth->shorty =
+ meth->shorty =
gDvm.methJavaLangReflectProxy_constructorPrototype->shorty;
// no pDexCode or pDexMethod
@@ -858,7 +866,7 @@
*/
int srcIndex = 0;
-
+
argCount = 0;
while (*desc != '\0') {
char descChar = *(desc++);
@@ -936,7 +944,6 @@
Object* handler;
Method* invoke;
ClassObject* returnType;
- int hOffset;
JValue invokeResult;
/*
@@ -1094,4 +1101,3 @@
/* no match in declared throws */
return true;
}
-
diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c
index 2e3c549..cf63462 100644
--- a/vm/reflect/Reflect.c
+++ b/vm/reflect/Reflect.c
@@ -71,9 +71,9 @@
return false;
}
- gDvm.classJavaLangClassArray =
+ gDvm.classJavaLangClassArray =
dvmFindArrayClass("[Ljava/lang/Class;", NULL);
- gDvm.classJavaLangObjectArray =
+ gDvm.classJavaLangObjectArray =
dvmFindArrayClass("[Ljava/lang/Object;", NULL);
if (gDvm.classJavaLangClassArray == NULL ||
gDvm.classJavaLangObjectArray == NULL)
@@ -240,7 +240,6 @@
ClassObject* defClass)
{
ArrayObject* classArray;
- ClassObject** classes;
char* signature = *pSignature;
char* cp;
int i, count;
@@ -273,7 +272,6 @@
return NULL;
/* fill it in */
- classes = (ClassObject**) classArray->contents;
cp = signature;
for (i = 0; i < count; i++) {
ClassObject* clazz;
@@ -284,8 +282,7 @@
return NULL;
}
LOGVV("REFLECT %d: '%s'\n", i, clazz->descriptor);
-
- *classes++ = clazz;
+ dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
}
*pSignature = cp;
@@ -306,7 +303,7 @@
int slot;
if (dvmIsStaticField(field)) {
- slot = (StaticField*)field - clazz->sfields;
+ slot = (StaticField*)field - &clazz->sfields[0];
assert(slot >= 0 && slot < clazz->sfieldCount);
slot = -(slot+1);
} else {
@@ -362,7 +359,7 @@
if (type == NULL)
goto bail;
- nameObj = dvmCreateStringFromCstr(field->name, ALLOC_DEFAULT);
+ nameObj = dvmCreateStringFromCstr(field->name);
if (nameObj == NULL)
goto bail;
@@ -395,7 +392,6 @@
ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
{
ArrayObject* fieldArray = NULL;
- Object** fields;
int i, count;
if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
@@ -421,34 +417,38 @@
kObjectArrayRefWidth, ALLOC_DEFAULT);
if (fieldArray == NULL)
return NULL;
- fields = (Object**) fieldArray->contents;
/* populate */
+ size_t fieldCount = 0;
for (i = 0; i < clazz->sfieldCount; i++) {
if (!publicOnly ||
(clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0)
{
- *fields = createFieldObject(&clazz->sfields[i].field, clazz);
- if (*fields == NULL)
+ Object* field = createFieldObject(&clazz->sfields[i].field, clazz);
+ if (field == NULL) {
goto fail;
- dvmReleaseTrackedAlloc(*fields, NULL);
- fields++;
- count--;
+ }
+ dvmSetObjectArrayElement(fieldArray, fieldCount, field);
+ dvmReleaseTrackedAlloc(field, NULL);
+ ++fieldCount;
}
}
for (i = 0; i < clazz->ifieldCount; i++) {
if (!publicOnly ||
(clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0)
{
- *fields = createFieldObject(&clazz->ifields[i].field, clazz);
- if (*fields == NULL)
+ Object* field = createFieldObject(&clazz->ifields[i].field, clazz);
+ if (field == NULL) {
goto fail;
- dvmReleaseTrackedAlloc(*fields, NULL);
- fields++;
- count--;
+ }
+ dvmSetObjectArrayElement(fieldArray, fieldCount, field);
+ dvmReleaseTrackedAlloc(field, NULL);
+ ++fieldCount;
}
}
+ assert(fieldCount == fieldArray->length);
+
/* caller must call dvmReleaseTrackedAlloc */
return fieldArray;
@@ -575,7 +575,6 @@
ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
{
ArrayObject* consArray;
- Object** consObjPtr;
Method* meth;
int i, count;
@@ -610,12 +609,11 @@
if (consArray == NULL)
return NULL;
- consObjPtr = (Object**) consArray->contents;
-
/*
* Fill out the array.
*/
meth = clazz->directMethods;
+ size_t consObjCount = 0;
for (i = 0; i < clazz->directMethodCount; i++, meth++) {
if ((!publicOnly || dvmIsPublicMethod(meth)) &&
dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
@@ -623,12 +621,13 @@
Object* consObj = createConstructorObject(meth);
if (consObj == NULL)
goto fail;
- *consObjPtr++ = consObj;
+ dvmSetObjectArrayElement(consArray, consObjCount, consObj);
+ ++consObjCount;
dvmReleaseTrackedAlloc(consObj, NULL);
}
}
- assert(consObjPtr - (Object**) consArray->contents == count);
+ assert(consObjCount == consArray->length);
/* caller must call dvmReleaseTrackedAlloc */
return consArray;
@@ -700,7 +699,7 @@
goto bail;
/* method name */
- nameObj = dvmCreateStringFromCstr(meth->name, ALLOC_DEFAULT);
+ nameObj = dvmCreateStringFromCstr(meth->name);
if (nameObj == NULL)
goto bail;
@@ -740,7 +739,6 @@
ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
{
ArrayObject* methodArray;
- Object** methObjPtr;
Method* meth;
int i, count;
@@ -778,12 +776,12 @@
if (methodArray == NULL)
return NULL;
- methObjPtr = (Object**) methodArray->contents;
/*
* Fill out the array.
*/
meth = clazz->virtualMethods;
+ size_t methObjCount = 0;
for (i = 0; i < clazz->virtualMethodCount; i++, meth++) {
if ((!publicOnly || dvmIsPublicMethod(meth)) &&
!dvmIsMirandaMethod(meth))
@@ -791,7 +789,8 @@
Object* methObj = dvmCreateReflectMethodObject(meth);
if (methObj == NULL)
goto fail;
- *methObjPtr++ = methObj;
+ dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
+ ++methObjCount;
dvmReleaseTrackedAlloc(methObj, NULL);
}
}
@@ -803,12 +802,13 @@
Object* methObj = dvmCreateReflectMethodObject(meth);
if (methObj == NULL)
goto fail;
- *methObjPtr++ = methObj;
+ dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
+ ++methObjCount;
dvmReleaseTrackedAlloc(methObj, NULL);
}
}
- assert(methObjPtr - (Object**) methodArray->contents == count);
+ assert(methObjCount == methodArray->length);
/* caller must call dvmReleaseTrackedAlloc */
return methodArray;
@@ -841,11 +841,9 @@
/*
* Fill out the array.
*/
- Object** interfaceObjPtr = (Object**) interfaceArray->contents;
- int i;
- for (i = 0; i < count; i++) {
- *interfaceObjPtr++ = (Object*) clazz->interfaces[i];
- }
+ memcpy(interfaceArray->contents, clazz->interfaces,
+ count * sizeof(Object *));
+ dvmWriteBarrierArray(interfaceArray, 0, count);
/* caller must call dvmReleaseTrackedAlloc */
return interfaceArray;
@@ -1029,7 +1027,7 @@
DataObject* dvmWrapPrimitive(JValue value, ClassObject* returnType)
{
static const char* boxTypes[] = { // order from enum PrimitiveType
- "Ljava/lang/Boolean;",
+ "Ljava/lang/Boolean;",
"Ljava/lang/Character;",
"Ljava/lang/Float;",
"Ljava/lang/Double;",
@@ -1093,10 +1091,8 @@
bool dvmUnwrapPrimitive(Object* value, ClassObject* returnType,
JValue* pResult)
{
- JValue result;
PrimitiveType typeIndex = returnType->primitiveType;
PrimitiveType valueIndex;
- //const u4* dataPtr;
if (typeIndex == PRIM_NOT) {
if (value != NULL && !dvmInstanceof(value->clazz, returnType)) {
@@ -1104,6 +1100,8 @@
value->clazz->descriptor, returnType->descriptor);
return false;
}
+ /* Never on the heap, so no write barrier needed. */
+ assert(!dvmIsValidObjectAddress(pResult));
pResult->l = value;
return true;
} else if (typeIndex == PRIM_VOID) {
@@ -1255,4 +1253,3 @@
return dvmCreateReflectMethodObject(method);
}
}
-
diff --git a/vm/reflect/Reflect.h b/vm/reflect/Reflect.h
index cd8e76c..16e7148 100644
--- a/vm/reflect/Reflect.h
+++ b/vm/reflect/Reflect.h
@@ -208,7 +208,7 @@
/**
* Initializes an encoded array iterator.
- *
+ *
* @param iterator iterator to initialize
* @param encodedArray encoded array to iterate over
* @param clazz class to use when resolving strings and types
@@ -226,9 +226,9 @@
* cursor. This returns primitive values in their corresponding union
* slots, and returns everything else (including nulls) as object
* references in the "l" union slot.
- *
+ *
* The caller must call dvmReleaseTrackedAlloc() on any returned reference.
- *
+ *
* @param value pointer to store decoded value into
* @returns true if a value was decoded and the cursor advanced; false if
* the last value had already been decoded or if there was a problem decoding
diff --git a/vm/test/AtomicSpeed.c b/vm/test/AtomicSpeed.c
deleted file mode 100644
index e2ffbef..0000000
--- a/vm/test/AtomicSpeed.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Atomic operation performance test.
- */
-#include "Dalvik.h"
-
-//#define TRIVIAL_COMPARE /* do something simple instead of an atomic op */
-
-/*
- * Perform operation. Returns elapsed time.
- */
-u8 dvmTestAtomicSpeedSub(int repeatCount)
-{
- static int value = 7;
- int* valuePtr = &value;
- u8 start, end;
- int i;
-
-#ifdef TRIVIAL_COMPARE
- /* init to arg value so compiler can't pre-determine result */
- int j = repeatCount;
-#endif
-
- assert((repeatCount % 10) == 0);
-
- start = dvmGetRelativeTimeNsec();
-
- for (i = repeatCount / 10; i != 0; i--) {
-#ifdef TRIVIAL_COMPARE
- // integer add (Dream: 3.4ns -- THUMB has 10 adds, ARM condenses)
- j += i; j += i; j += i; j += i; j += i;
- j += i; j += i; j += i; j += i; j += i;
-#else
- // succeed 10x (Dream: 155.9ns)
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
- ATOMIC_CMP_SWAP(valuePtr, 7, 7);
-
- // fail 10x (Dream: 158.5ns)
- /*
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- ATOMIC_CMP_SWAP(valuePtr, 6, 7);
- */
-#endif
- }
-
- end = dvmGetRelativeTimeNsec();
-
-#ifdef TRIVIAL_COMPARE
- /* use value so compiler can't eliminate it */
- dvmFprintf(stdout, "%d\n", j);
-#else
- dvmFprintf(stdout, ".");
- fflush(stdout); // not quite right if they intercepted fprintf
-#endif
- return end - start;
-}
-
-/*
- * Control loop.
- */
-bool dvmTestAtomicSpeed(void)
-{
- static const int kIterations = 10;
- static const int kRepeatCount = 5 * 1000 * 1000;
- static const int kDelay = 500 * 1000;
- u8 results[kIterations];
- int i;
-
- for (i = 0; i < kIterations; i++) {
- results[i] = dvmTestAtomicSpeedSub(kRepeatCount);
- usleep(kDelay);
- }
-
- dvmFprintf(stdout, "\n");
- dvmFprintf(stdout, "Atomic speed test results (%d per iteration):\n",
- kRepeatCount);
- for (i = 0; i < kIterations; i++) {
- dvmFprintf(stdout,
- " %2d: %.3fns\n", i, (double) results[i] / kRepeatCount);
- }
-
- return true;
-}
-
diff --git a/vm/test/AtomicTest.c b/vm/test/AtomicTest.c
new file mode 100644
index 0000000..62333d0
--- /dev/null
+++ b/vm/test/AtomicTest.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This provides a handful of correctness and speed tests on our atomic
+ * operations.
+ *
+ * This doesn't really belong here, but we currently lack a better place
+ * for it, so this will do for now.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <cutils/atomic.h>
+#ifdef __arm__
+# include <machine/cpu-features.h>
+#endif
+
+#define USE_ATOMIC 1
+#define THREAD_COUNT 10
+#define ITERATION_COUNT 500000
+
+#ifdef HAVE_ANDROID_OS
+/*#define TEST_BIONIC 1*/
+#endif
+
+
+#ifdef TEST_BIONIC
+extern int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
+extern int __atomic_swap(int _new, volatile int *ptr);
+extern int __atomic_dec(volatile int *ptr);
+extern int __atomic_inc(volatile int *ptr);
+#endif
+
+static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t waitCond = PTHREAD_COND_INITIALIZER;
+
+static volatile int threadsStarted = 0;
+
+/* results */
+static int incTest = 0;
+static int decTest = 0;
+static int addTest = 0;
+static int andTest = 0;
+static int orTest = 0;
+static int casTest = 0;
+static int failingCasTest = 0;
+static int swapTest = 0;
+static int64_t wideCasTest = 0x6600000077000000LL;
+
+/*
+ * Get a relative time value.
+ */
+static int64_t getRelativeTimeNsec(void)
+{
+#define HAVE_POSIX_CLOCKS
+#ifdef HAVE_POSIX_CLOCKS
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return (int64_t) now.tv_sec*1000000000LL + now.tv_nsec;
+#else
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return (int64_t) now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
+#endif
+}
+
+
+/*
+ * Non-atomic implementations, for comparison.
+ *
+ * If these get inlined the compiler may figure out what we're up to and
+ * completely elide the operations.
+ */
+static void incr(void) __attribute__((noinline));
+static void decr(void) __attribute__((noinline));
+static void add(int addVal) __attribute__((noinline));
+static int compareAndSwap(int oldVal, int newVal, int* addr) __attribute__((noinline));
+static int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr) __attribute__((noinline));
+
+static void incr(void)
+{
+ incTest++;
+}
+static void decr(void)
+{
+ decTest--;
+}
+static void add(int32_t addVal)
+{
+ addTest += addVal;
+}
+static int compareAndSwap(int32_t oldVal, int32_t newVal, int32_t* addr)
+{
+ if (*addr == oldVal) {
+ *addr = newVal;
+ return 0;
+ }
+ return 1;
+}
+static int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr)
+{
+ if (*addr == oldVal) {
+ *addr = newVal;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Exercise several of the atomic ops.
+ */
+static void doAtomicTest(int num)
+{
+ int addVal = (num & 0x01) + 1;
+
+ int i;
+ for (i = 0; i < ITERATION_COUNT; i++) {
+ if (USE_ATOMIC) {
+ android_atomic_inc(&incTest);
+ android_atomic_dec(&decTest);
+ android_atomic_add(addVal, &addTest);
+
+ int val;
+ do {
+ val = casTest;
+ } while (android_atomic_release_cas(val, val+3, &casTest) != 0);
+ do {
+ val = casTest;
+ } while (android_atomic_acquire_cas(val, val-1, &casTest) != 0);
+
+ int64_t wval;
+ do {
+ wval = dvmQuasiAtomicRead64(&wideCasTest);
+ } while (dvmQuasiAtomicCas64(wval,
+ wval + 0x0000002000000001LL, &wideCasTest) != 0);
+ do {
+ wval = dvmQuasiAtomicRead64(&wideCasTest);
+ } while (dvmQuasiAtomicCas64(wval,
+ wval - 0x0000002000000001LL, &wideCasTest) != 0);
+ } else {
+ incr();
+ decr();
+ add(addVal);
+
+ int val;
+ do {
+ val = casTest;
+ } while (compareAndSwap(val, val+3, &casTest) != 0);
+ do {
+ val = casTest;
+ } while (compareAndSwap(val, val-1, &casTest) != 0);
+
+ int64_t wval;
+ do {
+ wval = wideCasTest;
+ } while (compareAndSwapWide(wval,
+ wval + 0x0000002000000001LL, &wideCasTest) != 0);
+ do {
+ wval = wideCasTest;
+ } while (compareAndSwapWide(wval,
+ wval - 0x0000002000000001LL, &wideCasTest) != 0);
+ }
+ }
+}
+
+/*
+ * Entry point for multi-thread test.
+ */
+static void* atomicTest(void* arg)
+{
+ pthread_mutex_lock(&waitLock);
+ threadsStarted++;
+ pthread_cond_wait(&waitCond, &waitLock);
+ pthread_mutex_unlock(&waitLock);
+
+ doAtomicTest((int) arg);
+
+ return NULL;
+}
+
+/* lifted from a VM test */
+static int64_t testAtomicSpeedSub(int repeatCount)
+{
+ static int value = 7;
+ int* valuePtr = &value;
+ int64_t start, end;
+ int i;
+
+ start = getRelativeTimeNsec();
+
+ for (i = repeatCount / 10; i != 0; i--) {
+ if (USE_ATOMIC) {
+ // succeed 10x
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ (void) android_atomic_release_cas(7, 7, valuePtr);
+ } else {
+ // succeed 10x
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ compareAndSwap(7, 7, valuePtr);
+ }
+ }
+
+ end = getRelativeTimeNsec();
+
+ dvmFprintf(stdout, ".");
+ fflush(stdout);
+ return end - start;
+}
+
+static void testAtomicSpeed(void)
+{
+ static const int kIterations = 10;
+ static const int kRepeatCount = 5 * 1000 * 1000;
+ static const int kDelay = 50 * 1000;
+ int64_t results[kIterations];
+ int i;
+
+ for (i = 0; i < kIterations; i++) {
+ results[i] = testAtomicSpeedSub(kRepeatCount);
+ usleep(kDelay);
+ }
+
+ dvmFprintf(stdout, "\n");
+ dvmFprintf(stdout, "%s speed test results (%d per iteration):\n",
+ USE_ATOMIC ? "Atomic" : "Non-atomic", kRepeatCount);
+ for (i = 0; i < kIterations; i++) {
+ dvmFprintf(stdout,
+ " %2d: %.3fns\n", i, (double) results[i] / kRepeatCount);
+ }
+}
+
+/*
+ * Start tests, show results.
+ */
+bool dvmTestAtomicSpeed(void)
+{
+ pthread_t threads[THREAD_COUNT];
+ void *(*startRoutine)(void*) = atomicTest;
+ int64_t startWhen, endWhen;
+
+#if defined(__ARM_ARCH__)
+ dvmFprintf(stdout, "__ARM_ARCH__ is %d\n", __ARM_ARCH__);
+#endif
+#if defined(ANDROID_SMP)
+ dvmFprintf(stdout, "ANDROID_SMP is %d\n", ANDROID_SMP);
+#endif
+ dvmFprintf(stdout, "Creating threads\n");
+
+ int i;
+ for (i = 0; i < THREAD_COUNT; i++) {
+ void* arg = (void*) i;
+ if (pthread_create(&threads[i], NULL, startRoutine, arg) != 0) {
+ dvmFprintf(stderr, "thread create failed\n");
+ }
+ }
+
+ /* wait for all the threads to reach the starting line */
+ while (1) {
+ pthread_mutex_lock(&waitLock);
+ if (threadsStarted == THREAD_COUNT) {
+ dvmFprintf(stdout, "Starting test\n");
+ startWhen = getRelativeTimeNsec();
+ pthread_cond_broadcast(&waitCond);
+ pthread_mutex_unlock(&waitLock);
+ break;
+ }
+ pthread_mutex_unlock(&waitLock);
+ usleep(100000);
+ }
+
+ for (i = 0; i < THREAD_COUNT; i++) {
+ void* retval;
+ if (pthread_join(threads[i], &retval) != 0) {
+ dvmFprintf(stderr, "thread join (%d) failed\n", i);
+ }
+ }
+
+ endWhen = getRelativeTimeNsec();
+ dvmFprintf(stdout, "All threads stopped, time is %.6fms\n",
+ (endWhen - startWhen) / 1000000.0);
+
+ /*
+ * Show results; expecting:
+ *
+ * incTest = 5000000
+ * decTest = -5000000
+ * addTest = 7500000
+ * casTest = 10000000
+ * wideCasTest = 0x6600000077000000
+ */
+ dvmFprintf(stdout, "incTest = %d\n", incTest);
+ dvmFprintf(stdout, "decTest = %d\n", decTest);
+ dvmFprintf(stdout, "addTest = %d\n", addTest);
+ dvmFprintf(stdout, "casTest = %d\n", casTest);
+ dvmFprintf(stdout, "wideCasTest = 0x%llx\n", wideCasTest);
+
+ /* do again, serially (SMP check) */
+ startWhen = getRelativeTimeNsec();
+ for (i = 0; i < THREAD_COUNT; i++) {
+ doAtomicTest(i);
+ }
+ endWhen = getRelativeTimeNsec();
+ dvmFprintf(stdout, "Same iterations done serially: time is %.6fms\n",
+ (endWhen - startWhen) / 1000000.0);
+
+ /*
+ * Hard to do a meaningful thrash test on these, so just do a simple
+ * function test.
+ */
+ andTest = 0xffd7fa96;
+ orTest = 0x122221ff;
+ swapTest = 0x11111111;
+ android_atomic_and(0xfffdaf96, &andTest);
+ android_atomic_or(0xdeaaeb00, &orTest);
+ int oldSwap = android_atomic_swap(0x22222222, &swapTest);
+ int oldSwap2 = android_atomic_swap(0x33333333, &swapTest);
+ if (android_atomic_release_cas(failingCasTest+1, failingCasTest-1,
+ &failingCasTest) == 0)
+ dvmFprintf(stdout, "failing test did not fail!\n");
+
+ dvmFprintf(stdout, "andTest = 0x%x\n", andTest);
+ dvmFprintf(stdout, "orTest = 0x%x\n", orTest);
+ dvmFprintf(stdout, "swapTest = 0x%x -> 0x%x\n", oldSwap, oldSwap2);
+ dvmFprintf(stdout, "swapTest = 0x%x -> 0x%x\n", oldSwap2, swapTest);
+ dvmFprintf(stdout, "failingCasTest = %d\n", failingCasTest);
+
+#ifdef TEST_BIONIC
+ /*
+ * Quick function test on the bionic ops.
+ */
+ int prev;
+ int tester = 7;
+ prev = __atomic_inc(&tester);
+ __atomic_inc(&tester);
+ __atomic_inc(&tester);
+ dvmFprintf(stdout, "bionic 3 inc: %d -> %d\n", prev, tester);
+ prev = __atomic_dec(&tester);
+ __atomic_dec(&tester);
+ __atomic_dec(&tester);
+ dvmFprintf(stdout, "bionic 3 dec: %d -> %d\n", prev, tester);
+ prev = __atomic_swap(27, &tester);
+ dvmFprintf(stdout, "bionic swap: %d -> %d\n", prev, tester);
+ int swapok = __atomic_cmpxchg(27, 72, &tester);
+ dvmFprintf(stdout, "bionic cmpxchg: %d (%d)\n", tester, swapok);
+#endif
+
+ testAtomicSpeed();
+
+ return 0;
+}
diff --git a/vm/test/TestHash.c b/vm/test/TestHash.c
index 7233b15..26de141 100644
--- a/vm/test/TestHash.c
+++ b/vm/test/TestHash.c
@@ -61,7 +61,7 @@
for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter);
dvmHashIterNext(&iter))
{
- const char* str = (const char*) dvmHashIterData(&iter);
+ //const char* str = (const char*) dvmHashIterData(&iter);
//printf(" '%s'\n", str);
// (should verify strings)
count++;